[
  {
    "path": ".dockerignore",
    "content": ".git\n.github\n.gitignore\nreports\npapers\negg-herbie/target\n"
  },
  {
    "path": ".fmt.rkt",
    "content": "#lang racket/base\n\n(require fmt/conventions)\n\n(provide the-formatter-map)\n\n(define (the-formatter-map s)\n  (case s\n    [(\"define-operators\") (standard-formatter-map \"begin\")]\n    [(\"define-operations\") (standard-formatter-map \"define\")]\n    [(\"define-rules\") (standard-formatter-map \"define\")]\n    [(\"define-generator\") (standard-formatter-map \"define\")]\n    [(\"define-api-endpoint\") (standard-formatter-map \"define\")]\n    [else #f]))\n"
  },
  {
    "path": ".github/workflows/distribute.yml",
    "content": "name: Distribute\n\non:\n  push:\n    branches:\n      - main\n\nenv:\n  RUST_BACKTRACE: full\n\njobs:\n  distribute:\n    strategy:\n      matrix:\n        include:\n          - os: macos-latest\n            arch: aarch64\n          - os: macos-15-intel\n            arch: x64\n          - os: ubuntu-latest\n            arch: x64\n          - os: windows-latest\n            arch: x64\n\n    runs-on: ${{ matrix.os }}\n\n    steps:\n      - name: \"Install Racket\"\n        uses: Bogdanp/setup-racket@v1.14\n        with:\n            version: \"8.18\"\n            architecture: ${{ matrix.arch }}\n      - name: Cache Racket dependencies\n        uses: actions/cache@v4\n        with:\n          key: ${{ runner.os }}-deps\n          path: |\n            ~/.cache/racket\n            ~/.local/share/racket\n            ~/Library/Racket/\n            ${{ env.APPDATA }}/Racket\n      - name: Install Rust compiler\n        uses: dtolnay/rust-toolchain@stable\n        with:\n            toolchain: stable\n            components: rustfmt, clippy\n      - name: Cache cargo build\n        uses: Swatinem/rust-cache@v2\n      - uses: actions/checkout@v5\n      - name: \"Install dependencies\"\n        run: make install\n      # Build executable and remove Herbie launcher\n      - name: \"Build standalone executable\"\n        run: make distribution\n      - name: \"Uninstall Herbie launcher\"\n        run: raco pkg remove herbie egg-herbie\n      # Test executable\n      - name: \"Test executable, improve tool (Windows)\"\n        if: runner.os == 'Windows'\n        run: herbie-compiled/herbie.exe improve --threads yes bench/tutorial.fpcore improve.fpcore\n      - name: \"Test executable, improve tool (Linux / MacOS)\"\n        if: runner.os != 'Windows'\n        run: herbie-compiled/bin/herbie improve --threads yes bench/tutorial.fpcore improve.fpcore\n      - name: \"Test executable, report tool (Windows)\"\n        if: runner.os == 'Windows'\n        run: herbie-compiled/herbie.exe report --threads yes bench/tutorial.fpcore tmp\n      - name: \"Test executable, report tool (Linux / MacOS)\"\n        if: runner.os != 'Windows'\n        run: herbie-compiled/bin/herbie report --threads yes bench/tutorial.fpcore tmp\n"
  },
  {
    "path": ".github/workflows/plugins.yml",
    "content": "name: Plugins\n\non: [push]\n\nenv:\n  RUST_BACKTRACE: full\n\njobs:\n  softposit:\n    name: \"Plugin tests (Posits)\"\n    runs-on: ubuntu-latest\n    steps:\n      - name: \"Install Packages\"\n        run: sudo apt-get install -y libmpfr6 libmpfr-dev\n      - name: \"Install Racket\"\n        uses: Bogdanp/setup-racket@v1.14\n        with:\n          version: \"8.18\"\n      - name: Install Rust compiler\n        uses: dtolnay/rust-toolchain@stable\n        with:\n            toolchain: stable\n            components: rustfmt, clippy\n      - name: Cache cargo build\n        uses: Swatinem/rust-cache@v2\n      - uses: actions/checkout@v5\n      - name: \"Install dependencies\"\n        run: make install\n      - name: \"Install SoftPosit support\"\n        run: raco pkg install softposit-rkt\n      - name: \"Run posit benchmarks\"\n        run: racket infra/ci.rkt --rival2 --platform infra/softposit.rkt --precision posit16 --seed 0 infra/bench/posits.fpcore\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Build new Herbie release\n\non:\n  push:\n    tags:\n    - 'v*'\n\njobs:\n  build:\n    name: Build\n    strategy:\n      matrix:     # manual matrix\n        include:\n          - os: windows-latest\n            os-name: windows\n            arch: x64\n          - os: ubuntu-20.04  # keep old for glibc compatability\n            os-name: ubuntu\n            arch: x64\n          - os: macos-latest\n            os-name: macOS-m1\n            arch: arm64\n          - os: macos-15-intel\n            os-name: macOS\n            arch: x64\n\n    runs-on: ${{ matrix.os }}\n\n    steps:\n      - uses: actions/checkout@v5\n\n      - name: Install Racket\n        uses: Bogdanp/setup-racket@v1.14\n        with:\n          version: 8.18\n          architecture: ${{ matrix.arch }}\n\n      - name: Install Rust compiler\n        uses: dtolnay/rust-toolchain@stable\n        with:\n            toolchain: stable\n            \n      - name: build egg-herbie\n        run: cargo build --release --manifest-path=egg-herbie/Cargo.toml\n      \n      - name: Create tarball\n        run: raco pkg create --format zip egg-herbie\n\n      - name: Rename tarballs\n        run: |\n          mv egg-herbie.zip egg-herbie-${{ matrix.os-name }}.zip\n          mv egg-herbie.zip.CHECKSUM egg-herbie-${{ matrix.os-name }}.zip.CHECKSUM\n\n      - name: Upload pre-built egg-herbie\n        uses: actions/upload-artifact@v4\n        with:\n          path: egg-herbie-${{ matrix.os-name }}.zip\n          name: egg-herbie-${{ matrix.os-name }}.zip\n          if-no-files-found: error\n\n      - name: Upload pre-built egg-herbie checksum\n        uses: actions/upload-artifact@v4\n        with:\n          path: egg-herbie-${{ matrix.os-name }}.zip.CHECKSUM\n          name: egg-herbie-${{ matrix.os-name }}.zip.CHECKSUM\n          if-no-files-found: error\n\n  release:\n    name: Create Initial Release\n    runs-on: ubuntu-latest\n    needs: build\n    \n    steps:\n      - name: Download pre-built artifacts\n        uses: actions/download-artifact@v4\n        with:\n          path: artifacts\n          pattern: egg-herbie-*\n          merge-multiple: true\n\n      - name: Create Release\n        uses: ncipollo/release-action@v1.20.0\n        with:\n          tag: ${{ github.ref }}\n          name: ${{ github.ref }}\n          commit: ${{ github.commit }}\n          draft: true\n          prerelease: false\n          artifactErrorsFailBuild: true\n          artifacts: \"artifacts/*\"\n"
  },
  {
    "path": ".github/workflows/resyntax-autofixer.yml",
    "content": "name: Resyntax Autofixer\n\non:\n  workflow_dispatch:\n  schedule:\n    - cron: \"0 0 * * 0\"\n\njobs:\n  autofix:\n    runs-on: ubuntu-latest\n    env:\n      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n    permissions:\n      pull-requests: write\n      contents: write\n    steps:\n      - name: \"Install Packages\"\n        run: sudo apt-get install -y libmpfr6 libmpfr-dev\n      - name: \"Install Racket\"\n        uses: Bogdanp/setup-racket@v1.14\n        with:\n          version: current\n      - name: Install Rust compiler\n        uses: dtolnay/rust-toolchain@stable\n        with:\n            toolchain: stable\n            components: rustfmt, clippy\n      - name: Cache cargo build\n        uses: Swatinem/rust-cache@v2\n      - uses: actions/checkout@v5\n      - name: \"Install dependencies\"\n        run: make install\n      - name: Create a Resyntax pull request\n        uses: jackfirth/create-resyntax-pull-request@v0.5.1\n        with:\n          private-key: ${{ secrets.RESYNTAX_APP_PRIVATE_KEY }}\n          max-fixes: '10'\n          max-modified-files: '3'\n          max-modified-lines: '100'\n"
  },
  {
    "path": ".github/workflows/tests.yml",
    "content": "name: Integration\n\non: [push]\n\nenv:\n  RUST_BACKTRACE: full\n\njobs:\n  hamming:\n    name: \"Integration tests (Hamming)\"\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        racket-version: [ '8.7', '8.18' ]\n        precision: [ 'binary32', 'binary64' ]\n    steps:\n      - name: \"Install Packages\"\n        run: sudo apt-get install -y libmpfr6 libmpfr-dev\n      - name: \"Install Racket\"\n        uses: Bogdanp/setup-racket@v1.14\n        with:\n          version: ${{ matrix.racket-version }}\n      - name: Install Rust compiler\n        uses: dtolnay/rust-toolchain@stable\n        with:\n            toolchain: stable\n            components: rustfmt, clippy\n      - name: Cache cargo build\n        uses: Swatinem/rust-cache@v2\n      - uses: actions/checkout@v5\n      - name: \"Install dependencies\"\n        run: make install\n      - run: racket -y infra/ci.rkt --precision ${{ matrix.precision }} --seed 0 bench/hamming/\n"
  },
  {
    "path": ".github/workflows/unit-test.yml",
    "content": "name: Unit tests\n\non: [push]\n\nenv:\n  RUST_BACKTRACE: full\n\njobs:\n  unit-tests:\n    name: \"Unit Tests\"\n    runs-on: ubuntu-latest\n    steps:\n      - name: \"Install Packages\"\n        run: sudo apt-get install -y libmpfr6 libmpfr-dev\n      - name: \"Install Racket\"\n        uses: Bogdanp/setup-racket@v1.14\n        with:\n          version: \"8.18\"\n      - name: Install Rust compiler\n        uses: dtolnay/rust-toolchain@stable\n        with:\n            toolchain: stable\n            components: rustfmt, clippy\n      - name: Cache cargo build\n        uses: Swatinem/rust-cache@v2\n      - uses: actions/checkout@v5\n      - name: \"Install dependencies\"\n        run: make install\n      # SoftPosit is required to test the softposit platform we use for testing\n      - name: \"Install SoftPosit support\"\n        run: raco pkg install softposit-rkt\n\n      - name: \"Test raco fmt compliance\"\n        run: make fmt && git diff --exit-code\n\n      # Run the Herbie unit tests\n      - name: \"Run Herbie unit tests\"\n        run: raco test src/ infra/ egg-herbie/\n\n      # Test the command-line tools\n      - name: \"Test the shell command-line tool\"\n        run: |\n          <bench/tutorial.fpcore racket -l herbie shell >/tmp/out.fpcore\n          test `grep -c :precision /tmp/out.fpcore` -eq 3\n          test `grep -c ';;' /tmp/out.fpcore` -eq 0\n      - name: \"Test the improve command-line tool\"\n        run: |\n          racket -l herbie improve bench/tutorial.fpcore /tmp/out.fpcore\n          test `grep -c :precision /tmp/out.fpcore` -eq 3\n          test `grep -c '^; ' /tmp/out.fpcore` -eq 0\n      - name: \"Run the report command-line tool\"\n        run: |\n          racket -l herbie report bench/tutorial.fpcore /tmp/out/\n          test -d /tmp/out/\n          test -f /tmp/out/index.html\n          test -f /tmp/out/results.json\n      - name: \"Run two reports with the same seed and diff them\"\n        run: |\n          racket -l herbie report --threads yes --seed 1 bench/hamming/rearrangement.fpcore tmp-0\n          racket -l herbie report --threads yes --seed 1 bench/hamming/rearrangement.fpcore tmp-1\n          racket infra/diff.rkt tmp-0 tmp-1\n\n      - name: \"Run Herbie on array benchmarks\"\n        run: racket -l herbie improve bench/arrays /tmp/out.fpcore\n      - name: \"Run Herbie with egglog\"\n        run: racket -y infra/ci.rkt --egglog --precision binary64 --seed 1 bench/tutorial.fpcore\n\n      # Test the egg-herbie Rust code\n      - run: cd egg-herbie && cargo clippy --tests\n        continue-on-error: true\n      - run: cd egg-herbie && cargo test\n      - run: cd egg-herbie && cargo fmt -- --check\n      - run: cd egg-herbie && raco test ./\n\n      # Test the API\n      - uses: actions/setup-node@v6\n        with:\n          node-version: 20\n      - name: \"Test the endpoint\"\n        run: node infra/test-api.mjs\n"
  },
  {
    "path": ".gitignore",
    "content": "# OS cruft\n*~\n*.swp\n.DS_Store\n\n# Standard directories\nwww/demo\ndemo.log\ntest.fpcore\ntmp\ntmp-*\ndump-*\n.codex\n\n# Related repositories\n/reports\npapers\nplugins\nplugin\nrival\nrival3\nregraph\negg-herbie/pkg\nodyssey\ngeneric-flonum\n\n# Racket\n*.zo\n*.dep\nherbie-compiled/\n\n# Python\n.env/\n.worktrees\n\n"
  },
  {
    "path": "AGENTS.md",
    "content": "\n# Formatting\n\n- Use `map` over `for/list` only if it avoids a `lambda`.\n- Always use `in-list` and similar with `for` variants.\n- Always pass `#:length N` to `for/vector`.\n- Do not code defensively. Do not do runtime type checks or fallback.\n  Prefer to examine all callers to establish types, or if they can\n  differ prefer `match` with explicit patterns for all cases, to\n  ensure that an unanticipated values at any point cause errors.\n- Format Racket code with `make fmt` at the top level.\n- Check `git diff` and delete dead code before finishing a task.\n- Update docs in `www/doc/2.3/` if you change user-visible options.\n- Enforce module layering `utils < syntax < core < reports < api`: do not add imports from a lower layer to a higher layer.\n\n# Testing\n\n- If you change the Herbie core, test that your changes work with\n  `racket src/main.rkt report bench/tutorial.fpcore tmp`. This should\n  take about 5-10 seconds and all of the tests should pass with\n  perfect accuracy. You can also use other benchmark suites if asked.\n- If you need to store two reports name the folders `tmp-X` for some X.\n- Arguments come after the word `report` before any other arguments.\n- Herbie prints a seed every time it runs; you can pass `--seed N`\n  after the \"report\" argument to fix the seed reproducibly.\n- You can pass `--timeout T` to time out a benchmark after T seconds.\n- After running tests, `tmp` will have one directory per benchmark.\n  Each has a detailed `graph.html`, including tracebacks for crashes.\n- The default e-graph backend is `egg`; pass `--enable generate:egglog`\n  to enable the `egglog` backend. You may need to add `~/.cargo/bin`\n  to the `PATH`.\n- Some files have unit tests; run them with `raco test <file>`.\n\n# Observability\n\n- `jq` is installed, use it\n- If you're investigating a single benchmark, copy it to a file named\n  `test.fpcore` and run just that file.\n- Herbie runs output a `tmp/<benchmark>/timeline.json` with rich\n  observability data for each benchmark.\n- A timeline is a list of phases, each a map from key to \"table\",\n  each table is a list of fixed-length arrays.\n- Timeline types are defined in `src/utils/timeline.rkt`; HTML\n  generation is defined in `src/reports/timeline.rkt`.\n- Add to the timeline with `(timeline-push! 'type val1 val2 ...)`. The\n  `val`s must be JSON-compatible, so convert symbols to strings.\n- Herbie runs generates a profile in `tmp/<benchmark>/profile.json`.\n- You can also dump GC/memory data to `dump-trace.json` with `--enable\n  dump:trace`, Rival commands with `--enable dump:rival`, and egglog\n  commands with `--enable dump:egglog`. Dumps go in `dump-XXX` in the\n  current directory. Clean that directory when done.\n"
  },
  {
    "path": "Dockerfile",
    "content": "# Multistage build: https://docs.docker.com/develop/develop-images/multistage-build/\n# We build necessary binaries in one image, then COPY them to a second production \n# image to save some space.\n\n# Build image\n# Builds output under /herbie/egg-herbie\nFROM rust:1.88.0 AS egg-herbie-builder\nWORKDIR /herbie\nCOPY egg-herbie egg-herbie\nRUN cargo build --release --manifest-path=egg-herbie/Cargo.toml\nRUN cargo install egglog --version 1.0.0\n\n# Production image\nFROM racket/racket:8.17-full AS production\nLABEL maintainer=\"Pavel Panchekha <me@pavpanchekha.com>\"\nCOPY --from=egg-herbie-builder /herbie/egg-herbie /src/egg-herbie\nRUN raco pkg install --no-docs /src/egg-herbie\nCOPY --from=egg-herbie-builder /usr/local/cargo/bin/egglog /usr/local/bin/egglog\nCOPY src /src/herbie\nRUN raco pkg install --no-docs --auto /src/herbie\nENTRYPOINT [\"racket\", \"/src/herbie/main.rkt\"]\nEXPOSE 80\n# NOTE --public allows the Docker host to interact with the demo,\n# typical users shouldn't need to use it.\nCMD [\"web\", \"--public\", \"--port\", \"80\", \"--quiet\", \"--demo\", \"--threads\", \"2\"]\n"
  },
  {
    "path": "LICENSE.md",
    "content": "Copyright (c) 2015-2024 Herbie Project\nModified work Copyright 2016 Google Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": ".PHONY: help install egg-herbie nightly index start-server deploy coverage\n\nhelp:\n\t@echo \"Type 'make install' to install Herbie\"\n\t@echo \"Then type 'racket -l herbie web' to run it.\"\n\ninstall: clean egg-herbie egglog-herbie update\n\nclean:\n\traco pkg remove --force --no-docs herbie && echo \"Uninstalled old herbie\" || :\n\traco pkg remove --force --no-docs egg-herbie && echo \"Uninstalled old egg-herbie\" || :\n\traco pkg remove --force --no-docs egg-herbie-linux && echo \"Uninstalled old egg-herbie\" || :\n\traco pkg remove --force --no-docs egg-herbie-windows && echo \"Uninstalled old egg-herbie\" || :\n\traco pkg remove --force --no-docs egg-herbie-osx && echo \"Uninstalled old egg-herbie\" || :\n\traco pkg remove --force --no-docs egg-herbie-macosm1 && echo \"Uninstalled old egg-herbie\" || :\n\nupdate:\n\traco pkg install --update-deps --no-docs --auto --name herbie src/\n\traco pkg update --auto rival\n\traco pkg update --auto rival3\n\traco pkg update --name herbie --deps search-auto src/\n\negg-herbie:\n\tcargo build --release --manifest-path=egg-herbie/Cargo.toml\n\traco pkg remove --force --no-docs egg-herbie && echo \"Warning: uninstalling egg-herbie and reinstalling local version\" || :\n\traco pkg remove --force --no-docs egg-herbie-linux && echo \"Warning: uninstalling egg-herbie and reinstalling local version\" || :\n\traco pkg remove --force --no-docs egg-herbie-windows && echo \"Warning: uninstalling egg-herbie and reinstalling local version\" || :\n\traco pkg remove --force --no-docs egg-herbie-osx && echo \"Warning: uninstalling egg-herbie and reinstalling local version\" || :\n\traco pkg remove --force --no-docs egg-herbie-macosm1 && echo \"Warning: uninstalling egg-herbie and reinstalling local version\" || :\n\traco pkg install ./egg-herbie\n\negglog-herbie:\n\tcargo install --git \"https://github.com/egraphs-good/egglog-experimental\" --branch main egglog-experimental\n\ndistribution: minimal-distribution\n\tcp -r bench herbie-compiled/\n\nminimal-distribution:\n\tmkdir -p herbie-compiled/\n\tcp README.md herbie-compiled/\n\tcp LICENSE.md herbie-compiled/\n\tcp logo.png herbie-compiled/\n\traco exe -o herbie --orig-exe --embed-dlls --vv src/main.rkt\n\t[ ! -f herbie.exe ] || (raco distribute herbie-compiled herbie.exe && rm herbie.exe)\n\t[ ! -f herbie.app ] || (raco distribute herbie-compiled herbie.app && rm herbie.app)\n\t[ ! -f herbie ] || (raco distribute herbie-compiled herbie && rm herbie)\n\nnightly:\n\tbash infra/nightly.sh bench reports --threads 2\n\nupgrade:\n\tgit pull\n\t$(MAKE) install\n\nstart-server:\n\tracket -y src/main.rkt web --seed 1 --timeout 150 --threads 8 \\\n\t\t--demo --public --prefix /demo/ --port 4053 --save-session www/demo/ \\\n\t\t--log infra/server.log --quiet 2>&1\n\nfmt:\n\t@raco fmt -i $(shell find egg-herbie src infra -name '*.rkt' -not -path 'src/platforms/*.rkt' -not -path 'infra/softposit.rkt')\n\ncoverage:\n\t@racket infra/coverage.rkt --benchmark $(or $(BENCH),bench/hamming) $(ARGS)\n\nherbie.zip herbie.zip.CHECKSUM:\n\traco pkg create src/\n\tmv src.zip herbie.zip\n\tmv src.zip.CHECKSUM herbie.zip.CHECKSUM\n\nrandom-file:\n\t@find src infra -path '*/compiled/*' -prune \\\n\t\t    -o -path 'infra/survey/*' -prune \\\n\t\t    -o -type f -print | \\\n\tsort -R | head -n1\n"
  },
  {
    "path": "README.md",
    "content": "![Herbie](logo.png)\n\n\nHerbie automatically improves the error of floating point expressions.\nVisit [our website](https://herbie.uwplse.org) for tutorials,\ndocumentation, and an online demo. Herbie is a joint project of the\nUniversities of [Washington](https://uwplse.org) and\n[Utah](https://cpu.cs.utah.edu).\n\n## Installing\n\nWe recommend installing Herbie from the Racket Package Archive. To do\nso, [install Racket](https://download.racket-lang.org/) and then run:\n\n    raco pkg install --auto herbie\n\nYou can then run `racket -l herbie` to run Herbie. Herbie supports\nWindows, Linux, and macOS on both x86 and AArch64. For full\ninstructions, see the\n[documentation](https://herbie.uwplse.org/doc/latest/installing.html).\n\n## Installing from Source\n\nYou can install Herbie from source if you want to participate in\nHerbie development. This requires\n[Racket](https://download.racket-lang.org/) (8.0 or later) and\n[Rust](https://www.rust-lang.org/tools/install) (1.87.0 or later).\nOn Linux, avoid the Snap installer for Racket. Then, download the\nthis repository and run:\n\n    make install\n\nYou can then run `racket -l herbie` to run Herbie, or run\n`src/main.rkt` directly.\n\n## Running Herbie\n\nYou can run Herbie's web interface with:\n\n    $ racket -l herbie web\n\nFor more information on running Herbie, please see the\n[tutorial](https://herbie.uwplse.org/doc/latest/using-web.html).\n\nYou can also use Herbie from the command line:\n\n    $ racket -l herbie shell\n    Herbie 1.3 with seed 1866513483\n    Find help on https://herbie.uwplse.org/, exit with Ctrl-D\n    herbie> (FPCore (x) (- (+ 1 x) x))\n    (FPCore (x)\n      ...\n      1)\n\nHere the input is the program `(1 + x) - x` and the output is `1`. The\ninput format is [FPCore](https://fpbench.org/spec/fpcore-1.2.html);\nyou can see more examples in `bench/`.\n\nBesides `shell`, Herbie has batch the `improve` and `report` commands.\nThe [documentation](https://herbie.uwplse.org/doc/latest/options.html)\nhas more details.\n"
  },
  {
    "path": "bench/.gitignore",
    "content": "random.rkt\n"
  },
  {
    "path": "bench/arrays/basic.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore first-element ((v 2))\n :name \"First element from 2-element vector input\"\n (ref v 0))\n\n(FPCore nested-literal ()\n :name \"Element from nested array literal\"\n (ref (ref (array (array 2.0 0.5)\n                  (array -0.25 1.5))\n           1)\n      0))\n\n(FPCore bias-add ()\n :name \"Sum two literal bias terms\"\n (let* ([bias (array 0.1 -0.2)])\n   (+ (ref bias 0) (ref bias 1))))\n"
  },
  {
    "path": "bench/arrays/ops.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore vector-sum ((v 2))\n :name \"Sum two-element vector\"\n :pre (and (<= (fabs (ref v 0)) 1e150)\n           (<= (fabs (ref v 1)) 1e150))\n (+ (ref v 0) (ref v 1)))\n\n(FPCore dot-product-2d ((a 2) (b 2))\n :name \"2D vector dot product\"\n :pre (and (<= (fabs (ref a 0)) 1e150)\n           (<= (fabs (ref a 1)) 1e150)\n           (<= (fabs (ref b 0)) 1e150)\n           (<= (fabs (ref b 1)) 1e150))\n (+ (* (ref a 0) (ref b 0))\n    (* (ref a 1) (ref b 1))))\n\n(FPCore weighted-combo (w (v 2))\n :name \"Weighted combination of scalar and vector\"\n :pre (and (<= (fabs w) 1e150)\n           (<= (fabs (ref v 0)) 1e150)\n           (<= (fabs (ref v 1)) 1e150))\n (+ (* w (ref v 0)) (ref v 1)))\n\n(FPCore scaled-sum ((v 2) s)\n :name \"Scaled sum of vector elements\"\n :pre (and (<= (fabs s) 1e150)\n           (<= (fabs (ref v 0)) 1e150)\n           (<= (fabs (ref v 1)) 1e150))\n (+ (* s (ref v 0))\n    (* s (ref v 1))))\n\n(FPCore mat-vec-first-row ((v 2))\n :name \"Apply fixed 2x2 matrix row to vector\"\n :pre (and (<= (fabs (ref v 0)) 1e150)\n           (<= (fabs (ref v 1)) 1e150))\n (let* ([row0 (array 1.5 -0.75)]\n        [row1 (array -0.1 0.3)])\n   (+ (* (ref row0 0) (ref v 0))\n      (* (ref row0 1) (ref v 1)))))\n"
  },
  {
    "path": "bench/arrays/outputs.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore literal-vector ()\n :name \"Return fixed 2-element array literal\"\n :precision binary64\n (array 1.0\n        -1.0))\n\n(FPCore copy-vector ((v 2))\n :name \"Return input vector elements as array\"\n :precision binary64\n (array (ref v 0)\n        (ref v 1)))\n\n(FPCore ((x 2))\n  :name \"2sin (example 3.3) using vector\"\n  :pre (and (<= -1e4 (ref x 0)) (<= (ref x 0) 1e4) (< (* 1e-16 (fabs (ref x 0))) (ref x 1)) (< (ref x 1) (* (fabs (ref x 0)))))\n  (- (sin (+ (ref x 0) (ref x 1))) (sin (ref x 0))))\n\n(FPCore create-vector ((! :precision binary64 v0) (! :precision binary64 v1))\n :name \"Return input elements as array\"\n :precision binary64\n (array v0 v1))\n\n(FPCore reverse-vector ((v 2))\n :name \"Reverse input vector elements\"\n :precision binary64\n (array (ref v 1)\n        (ref v 0)))\n\n(FPCore mean-and-span ((v 2))\n :name \"Mean and half-difference of vector\"\n :precision binary64\n :pre (and (<= (fabs (ref v 0)) 1e150)\n           (<= (fabs (ref v 1)) 1e150))\n (let* ([mean (* 0.5 (+ (ref v 0) (ref v 1)))]\n        [half-span (* 0.5 (- (ref v 0) (ref v 1)))])\n   (array mean half-span)))\n\n(FPCore duplicate-scalar ((! :precision binary64 s))\n :name \"Duplicate scalar into array\"\n :precision binary64\n :pre (<= (fabs s) 1e150)\n (array s s))\n\n(FPCore pairwise-sum ((a 2) (b 2))\n :name \"Pairwise sum of two input vectors\"\n :precision binary64\n (array (+ (ref a 0) (ref b 0))\n        (+ (ref a 1) (ref b 1))))\n"
  },
  {
    "path": "bench/demo.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (x y z)\n :name \"fabs fraction 1\"\n (fabs (- (/ (+ x 4) y) (* (/ x y) z))))\n\n(FPCore (a b)\n :name \"fabs fraction 2\"\n (/ (fabs (- a b)) 2))\n\n(FPCore (f n)\n :name \"subtraction fraction\"\n (/ (- (+ f n)) (- f n)))\n\n(FPCore (x)\n :name \"exp neg sub\"\n (exp (- (- 1 (* x x)))))\n\n(FPCore (x)\n :name \"sqrt times\"\n (* (sqrt (- x 1)) (sqrt x)))\n\n(FPCore (x)\n :name \"neg log\"\n (- (log (- (/ 1 x) 1))))\n\n(FPCore (x)\n :name \"sqrt sqr\"\n :alt \n (! :herbie-platform default (if (< x 0) 2 0))\n\n (- (/ x x) (* (/ 1 x) (sqrt (* x x)))))\n\n(FPCore (a b c)\n :name \"jeff quadratic root 1\"\n (let ((d (sqrt (- (* b b) (* (* 4 a) c)))))\n   (if (>= b 0) (/ (- (- b) d) (* 2 a)) (/ (* 2 c) (+ (- b) d)))))\n\n(FPCore (a b c)\n :name \"jeff quadratic root 2\"\n (let ((d (sqrt (- (* b b) (* (* 4 a) c)))))\n   (if (>= b 0) (/ (* 2 c) (- (- b) d)) (/ (+ (- b) d) (* 2 a)))))\n\n(FPCore (p)\n  :name \"peicewise-defined\"\n  :pre (and (>= p -1.79e308) (<= p 1.79e308))\n  :alt\n    (if (and (>= p -1e-6) (<= p 0))\n      (- (+ p 1) (/ (* p p) (- p 1)))\n      (- p (fma (/ p (- p 1)) p -1)))\n  (- (+ p 1.0) (/ (pow (fmin p 0.0) 2.0) (- (fmin p 0.0) 1.0))))\n\n(FPCore (x)\n  :name \"(x - 1) to (x - 20)\"\n  :precision binary64\n  :pre (<= 1 x 20)\n  (* (* (* (* (* (* (* (* (* (* (* (* (* (* (* (* (* (* (* (- x 1.0) (- x 2.0)) (- x 3.0)) (- x 4.0)) (- x 5.0)) (- x 6.0)) (- x 7.0)) (- x 8.0)) (- x 9.0)) (- x 10.0)) (- x 11.0)) (- x 12.0)) (- x 13.0)) (- x 14.0)) (- x 15.0)) (- x 16.0)) (- x 17.0)) (- x 18.0)) (- x 19.0)) (- x 20.0)))\n\n(FPCore (a b C)\n  :name \"Law of Cosines\"\n  :precision binary64\n  :pre (and (<= 0 a 1e9) (<= 0 b 1e9) (<= 0 C PI))\n  (sqrt (- (+ (pow a 2.0) (pow b 2.0)) (* (* (* 2.0 a) b) (cos C)))))\n\n(FPCore (a b c)\n  :name \"Q^3 (Cubic Equation Discriminant Part)\"\n  :precision binary64\n  :pre (and (<= -1e9 a 1e9) (<= -1e9 b 1e9) (<= -1e9 c 1e9))\n  (pow (/ (- (* 3.0 (* a c)) (pow b 2.0)) (* 9.0 (pow a 2.0))) 3.0))\n\n(FPCore (x a)\n  :name \"Success Probability\"\n  :precision binary64\n  :pre (and (<= 0.0 x 1) (<= 1/3 a 3.0))\n  (- 1.0 (pow (- 1.0 x) a)))\n\n(FPCore (x)\n :name \"Quantum aproximation with lots of constants\"\n :precision binary64\n (let* (\n        (E (exp 1))\n        (sqrtE (sqrt E))\n        (invSqrtE (/ 1 sqrtE))\n        (logTerm (log (- 1 invSqrtE)))\n        (log2Term (* logTerm logTerm))\n        (log3Term (* log2Term logTerm))\n        (E3/2 (pow E 1.5))\n        (E5/2 (pow E 2.5))\n        (E7/2 (pow E 3.5))\n        (dx (- x 1/2))\n\n        ;; Common denominator\n        (D (+ (* sqrtE log2Term)\n              (* 16 sqrtE logTerm)\n              (* -64 sqrtE)\n              (* -8 (pow E 2) log2Term)\n              (* -4 (pow E 2) logTerm)\n              (* -8 E log2Term)\n              (* -84 E logTerm)\n              (* 16 E)\n              (* 2 E3/2 log2Term)\n              (* 16 E3/2 logTerm)\n              (* -4 E3/2)\n              (* E5/2 log2Term)\n              -24))\n\n        ;; Numerators\n        (n1 (+ (* sqrtE log3Term)\n               (* 20 sqrtE log2Term)\n               (* 210 sqrtE logTerm)\n               (* -1200 sqrtE)\n               (* -18 (pow E 3) log3Term)\n               (* -20 (pow E 3) log2Term)\n               (* -116 (pow E 2) log3Term)\n               (* -720 (pow E 2) log2Term)\n               (* 120 (pow E 2) logTerm)\n               (* -18 E log3Term)\n               (* -220 E log2Term)\n               (* -1280 E logTerm)\n               (* -300 E)\n               (* 3 E3/2 log3Term)\n               (* -20 E3/2 log2Term)\n               (* -930 E3/2 logTerm)\n               (* 3 E5/2 log3Term)\n               (* 120 E5/2 log2Term)\n               (* -20 E5/2 logTerm)\n               (* E7/2 log3Term)\n               -120))\n\n        (n2 (+ (* sqrtE log3Term)\n               (* 18 sqrtE log2Term)\n               (* -108 sqrtE logTerm)\n               (* -192 sqrtE)\n               (* (pow E 3) log3Term)\n               (* -16 (pow E 2) log3Term)\n               (* 6 (pow E 2) log2Term)\n               (* -18 (pow E 2) logTerm)\n               (* -9 E log3Term)\n               (* -94 E log2Term)\n               (* -378 E logTerm)\n               (* 48 E)\n               (* -16 E3/2 log3Term)\n               (* -174 E3/2 log2Term)\n               (* 72 E3/2 logTerm)\n               (* -12 E3/2)\n               (* -9 E5/2 log3Term)\n               (* -4 E5/2 log2Term)\n               (* -12 logTerm)\n               -72))\n\n        (n3 (+ (* sqrtE logTerm)\n               (* -216 sqrtE)\n               (* -8 (pow E 3) logTerm)\n               (* 2 (pow E 3))\n               (* -176 (pow E 2) logTerm)\n               (* 96 (pow E 2))\n               (* -8 E logTerm)\n               (* 266 E)\n               (* 83 E3/2 logTerm)\n               (* -232 E3/2)\n               (* 83 E5/2 logTerm)\n               (* -16 E5/2)\n               (* E7/2 logTerm)\n               12))\n\n        (n4 (+ (* -18 sqrtE logTerm)\n               (* -110 sqrtE)\n               (* (pow E 3) logTerm)\n               (* 53 (pow E 2) logTerm)\n               (* 13 E logTerm)\n               (* 30 E)\n               (* -66 E3/2 logTerm)\n               (* 30 E3/2)\n               (* -8 E5/2 logTerm)\n               logTerm\n               10))\n\n        (n5 (+ (* -18 sqrtE log2Term)\n               (* -115 sqrtE logTerm)\n               (* -340 sqrtE)\n               (* (pow E 3) log2Term)\n               (* 3 (pow E 2) log2Term)\n               (* 90 (pow E 2) logTerm)\n               (* -10 (pow E 2))\n               (* 3 E log2Term)\n               (* 20 E logTerm)\n               (* -390 E)\n               (* -116 E3/2 log2Term)\n               (* -530 E3/2 logTerm)\n               (* 60 E3/2)\n               (* -18 E5/2 log2Term)\n               (* -15 E5/2 logTerm)\n               log2Term\n               (* 10 logTerm)\n               60))\n\n        (n6 (+ (* sqrtE log2Term)\n               (* 15 sqrtE logTerm)\n               (* -156 sqrtE)\n               (* (pow E 3) log2Term)\n               (* -16 (pow E 2) log2Term)\n               (* 30 (pow E 2) logTerm)\n               (* -6 (pow E 2))\n               (* -9 E log2Term)\n               (* -70 E logTerm)\n               (* -126 E)\n               (* -16 E3/2 log2Term)\n               (* -180 E3/2 logTerm)\n               (* 24 E3/2)\n               (* -9 E5/2 log2Term)\n               (* -7 E5/2 logTerm)\n               -12))\n       )\n   (+ 1\n      (/\n       (+\n         (/ (* n1 (* dx dx)) (* 30 (pow (- 1 sqrtE) 2) D))\n         (/ (* n2 dx) (* 3 (- 1 sqrtE) D))\n         (/ (* sqrtE n3 (pow dx 4)) (* 360 (pow (- 1 sqrtE) 4) D))\n         (/ (* sqrtE n4 (pow dx 3)) (* 30 (pow (- 1 sqrtE) 3) D))\n         (/ (* sqrtE n5 (pow dx 2)) (* 30 (pow (- 1 sqrtE) 2) D))\n         (/ (* n6 dx) (* 3 (- 1 sqrtE) D))\n         logTerm)\n       ))))"
  },
  {
    "path": "bench/graphics/fidget/bear.fpcore",
    "content": "(FPCore (x y z)\n  :name \"The bear head is based on a design by Hazel Fraticelli and Anthony Taconi\"\n  :precision binary64\n  (fmin (/ (- (log (+ (exp (* -11 (- (/ (- (log (+ (exp (* -30.555555 (/ (- (log (+ (exp (* -11 (/ (- (log (+ (exp (* -11 (- (/ (- (log (+ (exp (* -16 (/ (- (log (+ (exp (* -5.612245 (- (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) -0.4) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.1) 2))) 1.4))) (exp (* -5.612245 (- (sqrt (+ (+ (pow (* (* (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) (- 1 (* 0.5 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8) 2))) 1)))))) (+ 1 (* 2 (exp (- (/ (sqrt (+ (+ (pow (* (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) (- 1 (* 0.5 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8) 2))) 1)))))) 2) (pow (+ (* (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1) (- 1 (* 0.5 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8) 2))) 1)))))) 1.5) 2)) (pow (+ 0.8 (* (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8) (- 1 (* 0.5 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8) 2))) 1))))))) 2))) 1)))))) 2) (pow (- (* (+ (* (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1) (- 1 (* 0.5 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8) 2))) 1)))))) 1.5) (+ 1 (* 2 (exp (- (/ (sqrt (+ (+ (pow (* (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) (- 1 (* 0.5 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8) 2))) 1)))))) 2) (pow (+ (* (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1) (- 1 (* 0.5 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8) 2))) 1)))))) 1.5) 2)) (pow (+ 0.8 (* (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8) (- 1 (* 0.5 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8) 2))) 1))))))) 2))) 1)))))) 2) 2)) (pow (- (* (+ 0.8 (* (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8) (- 1 (* 0.5 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8) 2))) 1))))))) (+ 1 (* 2 (exp (- (/ (sqrt (+ (+ (pow (* (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) (- 1 (* 0.5 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8) 2))) 1)))))) 2) (pow (+ (* (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1) (- 1 (* 0.5 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8) 2))) 1)))))) 1.5) 2)) (pow (+ 0.8 (* (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8) (- 1 (* 0.5 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8) 2))) 1))))))) 2))) 1)))))) -0.2) 2))) 0.9)))))) 5.612245))) (exp (* -16 (- (/ (- (log (+ (exp (* -5.612245 (- (- (sqrt (+ (+ (pow (- (* (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.48241276) (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.7513133)) 0.5854049) (+ 1 (* 1.2 (exp (- (/ (sqrt (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.48241276) (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.7513133)) 0.5854049) 2) (+ (pow (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.33768892) 0.55581105) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.5259193)) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.625) 1.09375) 2)))) 0.5)))))) -0.5) 2) (pow (* (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.33768892) 0.55581105) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.5259193)) (+ 1 (* 1.2 (exp (- (/ (sqrt (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.48241276) (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.7513133)) 0.5854049) 2) (+ (pow (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.33768892) 0.55581105) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.5259193)) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.625) 1.09375) 2)))) 0.5)))))) 2)) (pow (- (* (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.625) 1.09375) (+ 1 (* 1.2 (exp (- (/ (sqrt (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.48241276) (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.7513133)) 0.5854049) 2) (+ (pow (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.33768892) 0.55581105) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.5259193)) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.625) 1.09375) 2)))) 0.5)))))) -0.5) 2))) 0.5)))) (exp (* -5.612245 (- (sqrt (+ (pow (+ 0.3 (* (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.48241276) (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.7513133)) 0.5854049) (+ 1 (* 1.2 (exp (- (/ (sqrt (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.48241276) (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.7513133)) 0.5854049) 2) (+ (pow (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.33768892) 0.55581105) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.5259193)) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.625) 1.09375) 2)))) 0.5))))))) 2) (+ (pow (* (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.33768892) 0.55581105) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.5259193)) (+ 1 (* 1.2 (exp (- (/ (sqrt (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.48241276) (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.7513133)) 0.5854049) 2) (+ (pow (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.33768892) 0.55581105) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.5259193)) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.625) 1.09375) 2)))) 0.5)))))) 2) (pow (- (* (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.625) 1.09375) (+ 1 (* 1.2 (exp (- (/ (sqrt (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.48241276) (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.7513133)) 0.5854049) 2) (+ (pow (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.33768892) 0.55581105) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.5259193)) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.625) 1.09375) 2)))) 0.5)))))) -0.5) 2)))) 0.2)))))) 5.612245))))))) 16)))) (exp (* -11 (- (sqrt (+ (pow (- (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.4) 2) (+ (pow (/ (- (- (+ (* (/ y 1.5) 2.0808594) (* (/ z 1) 2.3650744)) (* (/ x 1.5) 1.089751)) 0.92795134) 0.7) 2) (pow (/ (- 0.0625 (- (* (/ z 1) 1.7215275) (+ (* (/ y 1.5) 2.5876334) (* (/ x 1.5) 1.2048262)))) 1.5) 2)))) 0.2)))))) 11))) (exp (* -11 (- (sqrt (+ (pow (- (* (- (* (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) 1) (- 1 (* 2 (exp (- (/ (sqrt (+ (pow (- (* (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) 1) 2) (+ (pow (* (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) 2) (pow (- (* (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) -1) 2)))) 0.5)))))) -1) 2) (+ (pow (* (* (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) (- 1 (* 2 (exp (- (/ (sqrt (+ (pow (- (* (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) 1) 2) (+ (pow (* (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) 2) (pow (- (* (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) -1) 2)))) 0.5)))))) 2) (pow (* (- (* (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) -1) (- 1 (* 2 (exp (- (/ (sqrt (+ (pow (- (* (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) 1) 2) (+ (pow (* (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) 2) (pow (- (* (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) -1) 2)))) 0.5)))))) 2)))) 0.3)))))) 11))) (exp (* -30.555555 (fmax (fmax (fmax (- -1.5 (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) (- (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 1.5)) (fmax (- 0.5 (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3)) (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 3))) (fmax (- (- (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) (/ 0.1 (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3))) -0.7)) (- (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) (/ 0.1 (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3))) -0.7)))))))) 30.555555)))) (exp (* -11 (fmin (fmin (fmax (- (sqrt (+ (pow (/ (* (/ (- (+ (- (+ (* (/ z 1) 0.5766893) (* (/ y 1.5) 2.1271143)) (* (/ x 1.5) 0.10320534)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.7495963)) 1.115259) 0.6) (+ 1 (* 4 (exp (- (/ (sqrt (+ (pow (- (+ (* (- (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (- (+ (* (/ z 1) 0.5766893) (* (/ y 1.5) 2.1271143)) (* (/ x 1.5) 0.10320534)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.7495963)) 1.115259) 0.6) 2) (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))) 2) (pow (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6) 2)))) 1)))))) (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6)) (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (- (+ (* (/ z 1) 0.5766893) (* (/ y 1.5) 2.1271143)) (* (/ x 1.5) 0.10320534)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.7495963)) 1.115259) 0.6) 2) (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))) 2) (pow (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6) 2)))) 1))))) (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))))) -1) 2) (+ (pow (/ (- (+ (- (+ (* (/ z 1) 0.5766893) (* (/ y 1.5) 2.1271143)) (* (/ x 1.5) 0.10320534)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.7495963)) 1.115259) 0.6) 2) (pow (- (+ (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (- (+ (* (/ z 1) 0.5766893) (* (/ y 1.5) 2.1271143)) (* (/ x 1.5) 0.10320534)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.7495963)) 1.115259) 0.6) 2) (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))) 2) (pow (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6) 2)))) 1))))) (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6)) (* (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (- (+ (* (/ z 1) 0.5766893) (* (/ y 1.5) 2.1271143)) (* (/ x 1.5) 0.10320534)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.7495963)) 1.115259) 0.6) 2) (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))) 2) (pow (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6) 2)))) 1))))) (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))))) -1.5) 2)))) 0.5)))))) 0.8) 2) (+ (pow (- (* (- (+ (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (- (+ (* (/ z 1) 0.5766893) (* (/ y 1.5) 2.1271143)) (* (/ x 1.5) 0.10320534)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.7495963)) 1.115259) 0.6) 2) (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))) 2) (pow (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6) 2)))) 1))))) (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6)) (* (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (- (+ (* (/ z 1) 0.5766893) (* (/ y 1.5) 2.1271143)) (* (/ x 1.5) 0.10320534)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.7495963)) 1.115259) 0.6) 2) (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))) 2) (pow (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6) 2)))) 1))))) (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))))) -1.5) (+ 1 (* 4 (exp (- (/ (sqrt (+ (pow (- (+ (* (- (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (- (+ (* (/ z 1) 0.5766893) (* (/ y 1.5) 2.1271143)) (* (/ x 1.5) 0.10320534)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.7495963)) 1.115259) 0.6) 2) (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))) 2) (pow (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6) 2)))) 1)))))) (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6)) (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (- (+ (* (/ z 1) 0.5766893) (* (/ y 1.5) 2.1271143)) (* (/ x 1.5) 0.10320534)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.7495963)) 1.115259) 0.6) 2) (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))) 2) (pow (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6) 2)))) 1))))) (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))))) -1) 2) (+ (pow (/ (- (+ (- (+ (* (/ z 1) 0.5766893) (* (/ y 1.5) 2.1271143)) (* (/ x 1.5) 0.10320534)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.7495963)) 1.115259) 0.6) 2) (pow (- (+ (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (- (+ (* (/ z 1) 0.5766893) (* (/ y 1.5) 2.1271143)) (* (/ x 1.5) 0.10320534)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.7495963)) 1.115259) 0.6) 2) (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))) 2) (pow (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6) 2)))) 1))))) (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6)) (* (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (- (+ (* (/ z 1) 0.5766893) (* (/ y 1.5) 2.1271143)) (* (/ x 1.5) 0.10320534)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.7495963)) 1.115259) 0.6) 2) (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))) 2) (pow (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6) 2)))) 1))))) (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))))) -1.5) 2)))) 0.5)))))) 1.5) 2) (pow (* (- (+ (* (- (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (- (+ (* (/ z 1) 0.5766893) (* (/ y 1.5) 2.1271143)) (* (/ x 1.5) 0.10320534)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.7495963)) 1.115259) 0.6) 2) (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))) 2) (pow (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6) 2)))) 1)))))) (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6)) (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (- (+ (* (/ z 1) 0.5766893) (* (/ y 1.5) 2.1271143)) (* (/ x 1.5) 0.10320534)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.7495963)) 1.115259) 0.6) 2) (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))) 2) (pow (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6) 2)))) 1))))) (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))))) -1) (+ 1 (* 4 (exp (- (/ (sqrt (+ (pow (- (+ (* (- (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (- (+ (* (/ z 1) 0.5766893) (* (/ y 1.5) 2.1271143)) (* (/ x 1.5) 0.10320534)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.7495963)) 1.115259) 0.6) 2) (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))) 2) (pow (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6) 2)))) 1)))))) (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6)) (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (- (+ (* (/ z 1) 0.5766893) (* (/ y 1.5) 2.1271143)) (* (/ x 1.5) 0.10320534)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.7495963)) 1.115259) 0.6) 2) (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))) 2) (pow (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6) 2)))) 1))))) (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))))) -1) 2) (+ (pow (/ (- (+ (- (+ (* (/ z 1) 0.5766893) (* (/ y 1.5) 2.1271143)) (* (/ x 1.5) 0.10320534)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.7495963)) 1.115259) 0.6) 2) (pow (- (+ (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (- (+ (* (/ z 1) 0.5766893) (* (/ y 1.5) 2.1271143)) (* (/ x 1.5) 0.10320534)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.7495963)) 1.115259) 0.6) 2) (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))) 2) (pow (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6) 2)))) 1))))) (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6)) (* (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (- (+ (* (/ z 1) 0.5766893) (* (/ y 1.5) 2.1271143)) (* (/ x 1.5) 0.10320534)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.7495963)) 1.115259) 0.6) 2) (+ (pow (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))) 2) (pow (/ (- (+ 0.9244498 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.6) 2)))) 1))))) (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))))) -1.5) 2)))) 0.5)))))) 2)))) 0.7) (fmax (fmax (- (+ (- (+ (* (/ z 1) 0.96114874) (* (/ y 1.5) 3.5451903)) (* (/ x 1.5) 0.17200887)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.2493271)) 2.8587651) (fmax (- 0.858765 (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.2493271) (- (+ (* (/ z 1) 0.96114874) (* (/ y 1.5) 3.5451903)) (* (/ x 1.5) 0.17200887)))) (- (+ 0.54074955 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1.6334443)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.33111554)))) (fmax (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (* (/ z 1) 0.35865277) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172)))) 1.4760667) (fmax (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0522937) (- (+ (* (/ z 1) 0.35865277) 0.5239333) (+ (* (/ y 1.5) 4.247789) (* (/ x 1.5) 0.6231172))))) (- (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.33111554) (+ 2.5407495 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1.6334443))))))) (fmax (- (sqrt (+ (pow (/ (* (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.38941833) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.921061)) 0.75479674) 0.9) (+ 1 (* 4 (exp (- (/ (sqrt (+ (pow (- (+ (* (- (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.38941833) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.921061)) 0.75479674) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889) 2)))) 1)))))) (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9)) (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.38941833) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.921061)) 0.75479674) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889) 2)))) 1))))) (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889))) -1) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.38941833) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.921061)) 0.75479674) 0.9) 2) (pow (- (+ (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.38941833) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.921061)) 0.75479674) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889) 2)))) 1))))) (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9)) (* (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.38941833) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.921061)) 0.75479674) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889) 2)))) 1))))) (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889))) -1.5) 2)))) 0.5)))))) 0.8) 2) (+ (pow (- (* (- (+ (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.38941833) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.921061)) 0.75479674) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889) 2)))) 1))))) (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9)) (* (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.38941833) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.921061)) 0.75479674) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889) 2)))) 1))))) (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889))) -1.5) (+ 1 (* 4 (exp (- (/ (sqrt (+ (pow (- (+ (* (- (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.38941833) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.921061)) 0.75479674) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889) 2)))) 1)))))) (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9)) (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.38941833) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.921061)) 0.75479674) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889) 2)))) 1))))) (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889))) -1) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.38941833) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.921061)) 0.75479674) 0.9) 2) (pow (- (+ (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.38941833) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.921061)) 0.75479674) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889) 2)))) 1))))) (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9)) (* (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.38941833) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.921061)) 0.75479674) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889) 2)))) 1))))) (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889))) -1.5) 2)))) 0.5)))))) 1.5) 2) (pow (* (- (+ (* (- (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.38941833) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.921061)) 0.75479674) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889) 2)))) 1)))))) (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9)) (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.38941833) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.921061)) 0.75479674) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889) 2)))) 1))))) (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889))) -1) (+ 1 (* 4 (exp (- (/ (sqrt (+ (pow (- (+ (* (- (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.38941833) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.921061)) 0.75479674) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889) 2)))) 1)))))) (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9)) (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.38941833) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.921061)) 0.75479674) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889) 2)))) 1))))) (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889))) -1) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.38941833) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.921061)) 0.75479674) 0.9) 2) (pow (- (+ (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.38941833) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.921061)) 0.75479674) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889) 2)))) 1))))) (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9)) (* (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.38941833) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.921061)) 0.75479674) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.921061) 1.2962569) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.38941833)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889) 2)))) 1))))) (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889))) -1.5) 2)))) 0.5)))))) 2)))) 0.7) (fmax (fmax (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0234011) (+ 0.16133696 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.43268704)))) (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.43268704) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0234011)) 1.8386631)) (fmax (fmax (- (* (+ (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 1.1111112)) (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.8888889)) (fmax (- (+ 0.44028544 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1.0234011)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.43268704)) (- (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.43268704) (+ 2.4402854 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1.0234011)))))))) (fmax (- (sqrt (+ (pow (/ (* (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.19866933) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.9800666)) 0.8012642) 0.9) (+ 1 (* 4 (exp (- (/ (sqrt (+ (pow (- (+ (* (- (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.19866933) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.9800666)) 0.8012642) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221) 2)))) 1)))))) (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9)) (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.19866933) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.9800666)) 0.8012642) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221) 2)))) 1))))) (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221))) -1) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.19866933) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.9800666)) 0.8012642) 0.9) 2) (pow (- (+ (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.19866933) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.9800666)) 0.8012642) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221) 2)))) 1))))) (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9)) (* (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.19866933) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.9800666)) 0.8012642) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221) 2)))) 1))))) (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221))) -1.5) 2)))) 0.5)))))) 0.8) 2) (+ (pow (- (* (- (+ (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.19866933) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.9800666)) 0.8012642) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221) 2)))) 1))))) (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9)) (* (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.19866933) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.9800666)) 0.8012642) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221) 2)))) 1))))) (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221))) -1.5) (+ 1 (* 4 (exp (- (/ (sqrt (+ (pow (- (+ (* (- (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.19866933) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.9800666)) 0.8012642) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221) 2)))) 1)))))) (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9)) (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.19866933) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.9800666)) 0.8012642) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221) 2)))) 1))))) (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221))) -1) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.19866933) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.9800666)) 0.8012642) 0.9) 2) (pow (- (+ (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.19866933) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.9800666)) 0.8012642) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221) 2)))) 1))))) (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9)) (* (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.19866933) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.9800666)) 0.8012642) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221) 2)))) 1))))) (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221))) -1.5) 2)))) 0.5)))))) 1.5) 2) (pow (* (- (+ (* (- (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.19866933) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.9800666)) 0.8012642) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221) 2)))) 1)))))) (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9)) (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.19866933) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.9800666)) 0.8012642) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221) 2)))) 1))))) (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221))) -1) (+ 1 (* 4 (exp (- (/ (sqrt (+ (pow (- (+ (* (- (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.19866933) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.9800666)) 0.8012642) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221) 2)))) 1)))))) (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9)) (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.19866933) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.9800666)) 0.8012642) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221) 2)))) 1))))) (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221))) -1) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.19866933) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.9800666)) 0.8012642) 0.9) 2) (pow (- (+ (* (cos (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.19866933) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.9800666)) 0.8012642) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221) 2)))) 1))))) (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9)) (* (sin (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.19866933) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.9800666)) 0.8012642) 0.9) 2) (+ (pow (/ (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.9800666) 1.0807292) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.19866933)) 0.9) 2) (pow (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221) 2)))) 1))))) (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221))) -1.5) 2)))) 0.5)))))) 2)))) 0.7) (fmax (fmax (- (+ (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0889629) (+ 0.1097064 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.2207437)))) (- (+ (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 0.2207437) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 1.0889629)) 1.8902936)) (fmax (fmax (- (+ 1.7777778 (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112))) (- (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1.1111112) 0.22222221)) (fmax (- (+ 0.20081031 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1.0889629)) (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.2207437)) (- (* (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.2207437) (+ 2.2008104 (* (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 1.0889629))))))))))))) 11) (fmin (- (sqrt (+ (pow (- (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.4) 2) (+ (pow (/ (- (- (+ (* (/ y 1.5) 2.0808594) (* (/ z 1) 2.3650744)) (* (/ x 1.5) 1.089751)) 0.92795134) 0.7) 2) (pow (/ (- 0.0625 (- (* (/ z 1) 1.7215275) (+ (* (/ y 1.5) 2.5876334) (* (/ x 1.5) 1.2048262)))) 1.5) 2)))) 0.25) (- (/ (- (log (+ (exp (* -30.555555 (- (- (sqrt (+ (pow (- (* (- (* (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) 1) (- 1 (* 2 (exp (- (/ (sqrt (+ (pow (- (* (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) 1) 2) (+ (pow (* (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) 2) (pow (- (* (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) -1) 2)))) 0.5)))))) -1) 2) (+ (pow (* (* (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) (- 1 (* 2 (exp (- (/ (sqrt (+ (pow (- (* (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) 1) 2) (+ (pow (* (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) 2) (pow (- (* (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) -1) 2)))) 0.5)))))) 2) (pow (* (- (* (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) -1) (- 1 (* 2 (exp (- (/ (sqrt (+ (pow (- (* (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) 1) 2) (+ (pow (* (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) 2) (pow (- (* (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) (- 1 (exp (- (/ (sqrt (+ (+ (pow (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3) 2) (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2) 2)) (pow (- (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 1) 2))) 0.5))))) -1) 2)))) 0.5)))))) 2)))) 0.4)))) (exp (* -30.555555 (- (sqrt (+ (+ (pow (- (* (- (* (/ (- (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.25) 0.9) (- 1 (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.25) 0.9) 2) (+ (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2.19) 2) (pow (+ 0.30833334 (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8333333)) 2)))) 0.15)))))) 0.2) (- 1 (exp (- (/ (sqrt (+ (+ (pow (- (* (/ (- (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.25) 0.9) (- 1 (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.25) 0.9) 2) (+ (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2.19) 2) (pow (+ 0.30833334 (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8333333)) 2)))) 0.15)))))) 0.2) 2) (pow (* (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2.19) (- 1 (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.25) 0.9) 2) (+ (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2.19) 2) (pow (+ 0.30833334 (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8333333)) 2)))) 0.15)))))) 2)) (pow (- (* (+ 0.30833334 (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8333333)) (- 1 (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.25) 0.9) 2) (+ (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2.19) 2) (pow (+ 0.30833334 (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8333333)) 2)))) 0.15)))))) 0.35) 2))) 0.15))))) -0.2) 2) (pow (* (* (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2.19) (- 1 (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.25) 0.9) 2) (+ (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2.19) 2) (pow (+ 0.30833334 (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8333333)) 2)))) 0.15)))))) (- 1 (exp (- (/ (sqrt (+ (+ (pow (- (* (/ (- (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.25) 0.9) (- 1 (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.25) 0.9) 2) (+ (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2.19) 2) (pow (+ 0.30833334 (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8333333)) 2)))) 0.15)))))) 0.2) 2) (pow (* (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2.19) (- 1 (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.25) 0.9) 2) (+ (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2.19) 2) (pow (+ 0.30833334 (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8333333)) 2)))) 0.15)))))) 2)) (pow (- (* (+ 0.30833334 (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8333333)) (- 1 (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.25) 0.9) 2) (+ (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2.19) 2) (pow (+ 0.30833334 (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8333333)) 2)))) 0.15)))))) 0.35) 2))) 0.15))))) 2)) (pow (- (* (- (* (+ 0.30833334 (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8333333)) (- 1 (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.25) 0.9) 2) (+ (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2.19) 2) (pow (+ 0.30833334 (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8333333)) 2)))) 0.15)))))) 0.35) (- 1 (exp (- (/ (sqrt (+ (+ (pow (- (* (/ (- (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.25) 0.9) (- 1 (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.25) 0.9) 2) (+ (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2.19) 2) (pow (+ 0.30833334 (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8333333)) 2)))) 0.15)))))) 0.2) 2) (pow (* (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2.19) (- 1 (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.25) 0.9) 2) (+ (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2.19) 2) (pow (+ 0.30833334 (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8333333)) 2)))) 0.15)))))) 2)) (pow (- (* (+ 0.30833334 (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8333333)) (- 1 (* 1.5 (exp (- (/ (sqrt (+ (pow (/ (- (fabs (/ (+ (* 0.87758255 (+ (* 0.9950042 (/ x 1.5)) (* -0.099833414 (/ y 1.5)))) (* 0.47942555 (/ z 1))) 0.3)) 0.25) 0.9) 2) (+ (pow (- (/ (- (* (/ z 1) 0.8753842) (+ (* (/ x 1.5) 0.4828974) (* (/ y 1.5) 0.022641014))) 0.3) 2.19) 2) (pow (+ 0.30833334 (* (/ (+ (+ (* (/ z 1) 0.06207773) (* (/ x 1.5) 0.06583953)) (* (/ y 1.5) 0.99589735)) 0.3) 0.8333333)) 2)))) 0.15)))))) 0.35) 2))) 0.15))))) -0.1) 2))) 0.14)))))) 30.555555)))))\n\n"
  },
  {
    "path": "bench/graphics/fidget/colonnade.fpcore",
    "content": "(FPCore (x y z)\n  :name \"Model of a colonnade with a balcony and outside staircase\"\n  :precision binary64\n  (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmax (fmax (fmax (fmax (fmax (fmax (- (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmax (fmax (fmax (- (* y 10) 3.5) (- 0.5 (* y 10))) (- (+ 3.5 (* z 10)))) (+ 1 (* z 10))) (- (sqrt (+ (pow (- (* y 10) 2) 2) (pow (+ 1 (* z 10)) 2))) 1.5)) (fmax (fmax (fmax (- (* y 10) 7) (- 4 (* y 10))) (- (+ 3.5 (* z 10)))) (+ 1 (* z 10)))) (- (sqrt (+ (pow (- (* y 10) 5.5) 2) (pow (+ 1 (* z 10)) 2))) 1.5)) (fmax (fmax (fmax (- 7.5 (* y 10)) (- (* y 10) 10.5)) (- (+ 3.5 (* z 10)))) (+ 1 (* z 10)))) (- (sqrt (+ (pow (- (* y 10) 9) 2) (pow (+ 1 (* z 10)) 2))) 1.5)) (fmax (fmax (fmax (- (+ 3 (* y 10))) (* y 10)) (- (+ 3.5 (* z 10)))) (+ 1 (* z 10)))) (- (sqrt (+ (pow (+ 1.5 (* y 10)) 2) (pow (+ 1 (* z 10)) 2))) 1.5))) (+ 2.5 (* x 10))) (- (+ 3 (* x 10)))) (- (* z 10) 2.5)) (- (* y 10) 9)) (- (+ 3.5 (* y 10)))) (- (+ 3.5 (* z 10)))) (fmax (fmax (fmax (fmax (fmax (fmax (- (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmax (fmax (fmax (- (* y 10) 3.5) (- 0.5 (* y 10))) (- (+ 3.5 (* z 10)))) (+ 1 (* z 10))) (- (sqrt (+ (pow (- (* y 10) 2) 2) (pow (+ 1 (* z 10)) 2))) 1.5)) (fmax (fmax (fmax (- (* y 10) 7) (- 4 (* y 10))) (- (+ 3.5 (* z 10)))) (+ 1 (* z 10)))) (- (sqrt (+ (pow (- (* y 10) 5.5) 2) (pow (+ 1 (* z 10)) 2))) 1.5)) (fmax (fmax (fmax (- 7.5 (* y 10)) (- (* y 10) 10.5)) (- (+ 3.5 (* z 10)))) (+ 1 (* z 10)))) (- (sqrt (+ (pow (- (* y 10) 9) 2) (pow (+ 1 (* z 10)) 2))) 1.5)) (fmax (fmax (fmax (- (+ 3 (* y 10))) (* y 10)) (- (+ 3.5 (* z 10)))) (+ 1 (* z 10)))) (- (sqrt (+ (pow (+ 1.5 (* y 10)) 2) (pow (+ 1 (* z 10)) 2))) 1.5))) (- (* x 10) 5.7)) (- 5.2 (* x 10))) (- (* z 10) 2.5)) (- (* y 10) 9)) (- (+ 3.5 (* y 10)))) (- (+ 3.5 (* z 10))))) (fmax (fmax (fmax (fmax (fmax (fmax (- (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmax (fmax (fmax (fmax (fmax (- (* z 10) 16.5) (- 3.5 (* z 10))) (+ 4.1 (* y 10))) (- (+ (* y 10) 13.5))) (- (* x 10) 9)) (- 5 (* x 10))) (fmax (fmax (fmax (fmax (fmax (- (* z 10) 16.5) (- (* x 10) 9)) (- 5 (* x 10))) (- 0.5 (* z 10))) (+ 7.5 (* y 10))) (- (+ 8.5 (* y 10))))) (fmax (fmax (fmax (fmax (fmax (- (* x 10) 9) (- 3.1 (* z 10))) (- (* y 10) 10.5)) (- 6.5 (* y 10))) (- 3 (* x 10))) (- (* z 10) 6.5))) (fmax (fmax (fmax (fmax (fmax (fmax (- (* z 10) 16.5) (+ 4.1 (* y 10))) (- 5 (* x 10))) (- 1.5 (* z 10))) (- (+ 6.1 (* y 10)))) (- (* x 10) 5.8)) (- (* x 8) (+ 2.5 (* z 10))))) (fmax (fmax (fmax (fmax (fmax (- 5 (* x 10)) (- 3.1 (* z 10))) (- (* x 10) 5.8)) (- (* z 10) 6)) (- (* y 10) 6.2)) (- (+ 2.5 (* y 10))))) (fmax (fmax (fmax (fmax (fmax (- 5 (* x 10)) (- (* z 10) 5.8)) (- (* y 10) 6)) (- (+ 2.3 (* y 10)))) (- (* x 10) 6)) (- 3.3 (* z 10)))) (fmax (fmax (fmax (fmax (fmax (fmax (- (* z 10) 16.5) (+ 4.1 (* y 10))) (- 1.5 (* z 10))) (- (+ 6.1 (* y 10)))) (- 6.7 (* x 10))) (- (* x 10) 7.5)) (- 7.5 (+ (* x 8) (* z 10))))) (fmax (fmax (fmax (fmax (fmax (- 3.1 (* z 10)) (- (* z 10) 6)) (- (* y 10) 6.2)) (- (+ 2.5 (* y 10)))) (- 6.7 (* x 10))) (- (* x 10) 7.5))) (fmax (fmax (fmax (fmax (fmax (- (* z 10) 5.8) (- (* y 10) 6)) (- (+ 2.3 (* y 10)))) (- (* x 10) 7.5)) (- 6.5 (* x 10))) (- 3.3 (* z 10))))) (- 5.5 (* x 10))) (- (* y 10) 9)) (- (+ 8.5 (* y 10)))) (- (* x 10) 7)) (- (* z 10) 6.5)) (- (+ 3.5 (* z 10))))) (fmax (fmax (fmax (fmax (fmax (- (* z 10) 3.5) (+ 5.4 (* y 10))) (- (+ 6.5 (* y 10)))) (- (* x 10) 6.8)) (- 5.7 (* x 10))) (- 3.3 (* z 10)))) (fmax (fmax (fmax (fmax (fmax (- (* z 10) 6.7) (- (* y 10) 6.5)) (- (+ 4.3 (* y 10)))) (- (* x 10) 7.2)) (- 5.3 (* x 10))) (- 6.5 (* z 10)))) (fmax (fmax (fmax (fmax (fmax (+ (+ (* z 1.7238) 5.43983) (* y 9.8503)) (- (* z 1.7238) (+ 7.95658 (* y 9.8503)))) (- (+ (* z 1.84289) (* x 9.82872)) 7.48826)) (- (+ (* z 1.84289) 4.79765) (* x 9.82872))) (- (* z 10) 3.9)) (- 3.3 (* z 10)))) (fmax (fmax (- (* x 10) 6.7) (- 5.8 (* x 10))) (- (sqrt (+ (pow (+ 4.1 (* y 10)) 2) (pow (- (* z 10) 3.3) 2))) 1.5))) (fmax (fmax (fmax (fmax (- (* x 10) 6.8) (- 5.7 (* x 10))) (- (sqrt (+ (pow (+ 4.1 (* y 10)) 2) (pow (- (* z 10) 3.3) 2))) 1.5)) (- 1.3 (sqrt (+ (pow (+ 4.1 (* y 10)) 2) (pow (- (* z 10) 3.3) 2))))) (- 3.3 (* z 10)))) (- (sqrt (+ (+ (pow (- (* z 10) 5.6) 2) (pow (- (* x 10) 4.85) 2)) (pow (+ 3.15 (* y 10)) 2))) 0.1)) (fmax (fmin (fmin (fmin (fmax (fmax (fmax (fmax (fmax (- 2.8 (* z 10)) (- 5.4 (* y 10))) (- (* x 10) 9)) (- (* y 10) 9)) (- (* z 10) 3.1)) (- (+ 9 (* x 10)))) (fmax (fmax (fmax (- (* z 30) (+ 5.4 (* y 10))) (- (fmax (- (* z 30) (+ 3 (* y 10))) (- (fmin (- 9 (* x 10)) (- (* x 10) 5.5)))))) (- (fmin (+ 0.0999999 (* z 10)) (- 3.1 (* z 10))))) (- (fmin (- 9 (* x 10)) (- (* x 10) 5.5))))) (fmax (fmax (- (* z 30) (+ 9.3 (* y 10))) (- (fmin (- 9 (* x 10)) (- (* x 10) 5.5)))) (- (fmin (fmin (fmax (- (fmin (- 9 (* x 10)) (- (* x 10) 5.5))) (- (* z 30) (+ 6.9 (* y 10)))) (- 0.2 (* z 10))) (+ 8.5 (* y 10)))))) (fmax (fmax (fmax (fmax (fmax (- (* z 10) 0.2) (- (+ 0.0999999 (* z 10)))) (+ 3.2 (* y 10))) (- (+ 7.2 (* y 10)))) (- 7 (* x 10))) (- (* x 10) 9))) (- (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmax (- 0.2 (* z 10)) (+ 3 (* y 10))) (fmax (- 0.371 (* z 10)) (+ 2.5 (* y 10)))) (fmax (+ 2 (* y 10)) (- 0.542 (* z 10)))) (fmax (- 0.713 (* z 10)) (+ 1.5 (* y 10)))) (fmax (+ 1 (* y 10)) (- 0.884 (* z 10)))) (fmax (+ 0.5 (* y 10)) (- 1.055 (* z 10)))) (fmax (- 1.226 (* z 10)) (* y 10))) (fmax (- (* y 10) 0.5) (- 1.397 (* z 10)))) (fmax (- (* y 10) 1) (- 1.568 (* z 10)))) (fmax (- (* y 10) 1.5) (- 1.739 (* z 10)))) (fmax (- 1.91 (* z 10)) (- (* y 10) 2))) (fmax (- (* y 10) 2.5) (- 2.081 (* z 10)))) (fmax (- (* y 10) 3) (- 2.252 (* z 10)))) (fmax (- 2.423 (* z 10)) (- (* y 10) 3.5))) (fmax (- (* y 10) 4) (- 2.594 (* z 10)))) (fmax (- (* y 10) 4.5) (- 2.765 (* z 10)))) (fmax (- (* y 10) 5) (- 2.936 (* z 10)))) (fmax (- 3.107 (* z 10)) (- (* y 10) 5.5))) (fmax (- 3.278 (* z 10)) (- (* y 10) 6))) (fmax (- 3.449 (* z 10)) (- (* y 10) 6.5))) (fmax (+ 9.2 (* y 10)) (- (+ 0.65 (* z 10))))) (fmax (+ 8.7 (* y 10)) (- (+ 0.479 (* z 10))))) (fmax (+ 8.2 (* y 10)) (- (+ 0.308 (* z 10))))) (fmax (+ 7.7 (* y 10)) (- (+ 0.137 (* z 10))))) (fmax (+ 7.2 (* y 10)) (- 0.0339999 (* z 10))))))) (fmax (fmax (- (sqrt (+ (pow (+ 3.15 (* y 10)) 2) (pow (+ 2.75 (* x 10)) 2))) 0.1) (- (* z 10) 7.4)) (- 6.5 (* z 10)))) (- (sqrt (+ (+ (pow (- (* z 10) 7.4) 2) (pow (+ 3.15 (* y 10)) 2)) (pow (+ 2.75 (* x 10)) 2))) 0.1)) (fmax (fmax (fmax (fmax (fmax (- (* z 10) 4.8) (- 2.5 (* z 10))) (- (+ 7.1 (* x 10)))) (+ 2.6 (* y 10))) (- (+ 3.7 (* y 10)))) (+ 6 (* x 10)))) (- (sqrt (+ (+ (pow (- (* z 5) 2.2) 2) (pow (+ 6.55 (* x 10)) 2)) (pow (+ 3.15 (* y 10)) 2))) 0.5)) (fmax (fmax (- (* z 10) 5.6) (- 4.8 (* z 10))) (- (sqrt (+ (pow (+ 6.55 (* x 10)) 2) (pow (+ 3.15 (* y 10)) 2))) 0.1))) (- (sqrt (+ (+ (pow (+ 6.55 (* x 10)) 2) (pow (- (* z 10) 5.6) 2)) (pow (+ 3.15 (* y 10)) 2))) 0.1)) (fmax (fmax (fmax (fmax (fmax (- (* z 10) 4.8) (- 2.5 (* z 10))) (- (* x 10) 1.6)) (- 0.5 (* x 10))) (+ 2.6 (* y 10))) (- (+ 3.7 (* y 10))))) (- (sqrt (+ (+ (pow (- (* z 5) 2.2) 2) (pow (- (* x 10) 1.05) 2)) (pow (+ 3.15 (* y 10)) 2))) 0.5)) (fmax (fmax (- (* z 10) 5.6) (- 4.8 (* z 10))) (- (sqrt (+ (pow (- (* x 10) 1.05) 2) (pow (+ 3.15 (* y 10)) 2))) 0.1))) (- (sqrt (+ (+ (pow (- (* z 10) 5.6) 2) (pow (- (* x 10) 1.05) 2)) (pow (+ 3.15 (* y 10)) 2))) 0.1)) (fmax (fmax (fmax (fmax (fmax (- (* z 10) 4.8) (- 2.5 (* z 10))) (- (* x 10) 5.4)) (- 4.3 (* x 10))) (+ 2.6 (* y 10))) (- (+ 3.7 (* y 10))))) (- (sqrt (+ (+ (pow (- (* z 5) 2.2) 2) (pow (- (* x 10) 4.85) 2)) (pow (+ 3.15 (* y 10)) 2))) 0.5)) (fmax (fmax (- (* z 10) 5.6) (- 4.8 (* z 10))) (- (sqrt (+ (pow (- (* x 10) 4.85) 2) (pow (+ 3.15 (* y 10)) 2))) 0.1))) (fmax (fmax (fmax (fmax (fmax (fmax (fmax (- (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmax (fmax (fmax (fmax (fmax (- (* x 10) 5.5) (- (+ 9 (* x 10)))) (- (* z 10) 4.2)) (- 3.3 (* z 10))) (+ 3.4 (* y 10))) (- (+ 3.6 (* y 10)))) (fmax (fmax (fmax (fmax (fmax (- (* z 10) 4.1) (- 3.4 (* z 10))) (+ 2.5 (* y 10))) (+ 8.1 (* x 10))) (- (+ 8.9 (* x 10)))) (- (+ 3.5 (* y 10))))) (fmax (fmax (fmax (fmax (fmax (- (* z 10) 4.1) (- 3.4 (* z 10))) (+ 2.5 (* y 10))) (+ 7.15 (* x 10))) (- (+ 7.95 (* x 10)))) (- (+ 3.5 (* y 10))))) (fmax (fmax (fmax (fmax (fmax (- (* z 10) 4.1) (- 3.4 (* z 10))) (+ 2.5 (* y 10))) (+ 5.2 (* x 10))) (- (+ 6 (* x 10)))) (- (+ 3.5 (* y 10))))) (fmax (fmax (fmax (fmax (fmax (- (* z 10) 4.1) (- 3.4 (* z 10))) (+ 2.5 (* y 10))) (+ 4.25 (* x 10))) (- (+ 5.05 (* x 10)))) (- (+ 3.5 (* y 10))))) (fmax (fmax (fmax (fmax (fmax (- (* z 10) 4.1) (- 3.4 (* z 10))) (+ 2.5 (* y 10))) (+ 3.3 (* x 10))) (- (+ 4.1 (* x 10)))) (- (+ 3.5 (* y 10))))) (fmax (fmax (fmax (fmax (fmax (- (* z 10) 4.1) (- 3.4 (* z 10))) (+ 2.5 (* y 10))) (+ 1.4 (* x 10))) (- (+ 2.2 (* x 10)))) (- (+ 3.5 (* y 10))))) (fmax (fmax (fmax (fmax (fmax (- (* z 10) 4.1) (- 3.4 (* z 10))) (+ 2.5 (* y 10))) (+ 0.45 (* x 10))) (- (+ 1.25 (* x 10)))) (- (+ 3.5 (* y 10))))) (fmax (fmax (fmax (fmax (fmax (- (* z 10) 4.1) (- 3.4 (* z 10))) (+ 2.5 (* y 10))) (- (* x 10) 0.5)) (- (+ 0.3 (* x 10)))) (- (+ 3.5 (* y 10))))) (fmax (fmax (fmax (fmax (fmax (- (* z 10) 4.1) (- 3.4 (* z 10))) (+ 2.5 (* y 10))) (- (* x 10) 2.4)) (- 1.6 (* x 10))) (- (+ 3.5 (* y 10))))) (fmax (fmax (fmax (fmax (fmax (- (* z 10) 4.1) (- 3.4 (* z 10))) (+ 2.5 (* y 10))) (- (* x 10) 3.35)) (- 2.55 (* x 10))) (- (+ 3.5 (* y 10))))) (fmax (fmax (fmax (fmax (fmax (- (* z 10) 4.1) (- 3.4 (* z 10))) (+ 2.5 (* y 10))) (- (* x 10) 4.3)) (- 3.5 (* x 10))) (- (+ 3.5 (* y 10)))))) (+ 3 (* y 10))) (- (+ 3.5 (* y 10)))) (- (* z 10) 4.4)) (- (+ 3.5 (* z 10)))) (- (* x 10) 6)) (- (+ 9 (* x 10)))) (- (fmin (fmin (fmin (fmin (fmin (fmin (fmin (fmax (fmax (fmax (- (+ 3.5 (* z 10))) (+ 1 (* z 10))) (+ 7.5 (* x 10))) (- (+ (* x 10) 10.5))) (- (sqrt (+ (pow (+ 1 (* z 10)) 2) (pow (+ 9 (* x 10)) 2))) 1.5)) (fmax (fmax (fmax (- (+ 3.5 (* z 10))) (+ 1 (* z 10))) (+ 4 (* x 10))) (- (+ 7 (* x 10))))) (- (sqrt (+ (pow (+ 1 (* z 10)) 2) (pow (+ 5.5 (* x 10)) 2))) 1.5)) (fmax (fmax (fmax (- (+ 3.5 (* z 10))) (+ 1 (* z 10))) (- (* x 10) 1.5)) (- (+ 1.5 (* x 10))))) (- (sqrt (+ (pow (+ 1 (* z 10)) 2) (pow (* x 10) 2))) 1.5)) (fmax (fmax (fmax (- (+ 3.5 (* z 10))) (+ 1 (* z 10))) (- (* x 10) 5)) (- 2 (* x 10)))) (- (sqrt (+ (pow (+ 1 (* z 10)) 2) (pow (- (* x 10) 3.5) 2))) 1.5))))) (fmax (fmax (fmax (fmax (fmax (- (+ 4 (* z 10))) (- (* y 10) 9)) (- (+ 8.5 (* y 10)))) (- (* x 10) 7)) (+ 3.5 (* z 10))) (- (+ 9 (* x 10))))) (fmax (fmax (fmax (fmax (fmax (- (* y 10) 9) (- (* x 10) 7)) (- (* z 10) 2.3)) (- 2 (* z 10))) (- (+ 3.9 (* y 10)))) (- (+ 9 (* x 10))))) (fmax (fmax (fmax (fmax (fmax (- (* y 10) 9) (- (* x 10) 7)) (- (* z 10) 3.1)) (- 2.3 (* z 10))) (- (+ 3.8 (* y 10)))) (- (+ 9 (* x 10))))) (fmax (fmax (fmax (fmax (fmax (- (* x 10) 7) (- (+ 3.9 (* y 10)))) (- (* z 10) 3.2)) (- 2.9 (* z 10))) (+ 3.5 (* y 10))) (- (+ 9 (* x 10))))) (fmax (fmax (fmax (fmax (fmax (- (* z 10) 6.5) (+ 2.6 (* y 10))) (- (+ 3.7 (* y 10)))) (+ 2.2 (* x 10))) (- (+ 3.3 (* x 10)))) (- (+ 3.5 (* z 10))))) (- (sqrt (+ (+ (pow (- (* z 5) 3.05) 2) (pow (+ 3.15 (* y 10)) 2)) (pow (+ 2.75 (* x 10)) 2))) 0.5)))\n\n"
  },
  {
    "path": "bench/graphics/fidget/gyroid-sphere.fpcore",
    "content": "(FPCore (x y z)\n  :name \"Gyroid sphere\"\n  :precision binary64\n  (let* ([scale 30]\n         [gyroid (+ (+ (* (sin (* x scale)) (cos (* y scale))) (* (sin (* y scale)) (cos (* z scale)))) (* (sin (* z scale)) (cos (* x scale))))]\n         [fill (- (fabs gyroid) 0.2)]\n         [sphere (- (sqrt (+ (+ (pow (* x scale) 2) (pow (* y scale) 2)) (pow (* z scale) 2))) 25)])\n    (fmax sphere fill)))\n"
  },
  {
    "path": "bench/graphics/fidget/hi.fpcore",
    "content": "(FPCore (x y)\n  :name \"The letters hi in the upper-right quadrant\"\n  :precision binary64\n  (fmin (fmin (fmin (fmin (fmax (fmax (fmax (- y 0.55) (- y)) (- x 0.825)) (- 0.725 x)) (- (sqrt (+ (pow (- y 0.7) 2) (pow (- x 0.775) 2))) 0.075)) (fmax (fmax (fmax (- y) (- y 0.275)) (- x 0.55)) (- 0.45 x))) (fmax (fmax (fmax (- y) (- y 1)) (- x 0.1)) (- x))) (fmax (fmax (fmax (fmax (fmax (- y 0.55) (- x 0.55)) (- x)) (- 0.275 y)) (- 0.175 (sqrt (+ (pow (- y 0.275) 2) (pow (- x 0.275) 2))))) (- (sqrt (+ (pow (- y 0.275) 2) (pow (- x 0.275) 2))) 0.275))))\n"
  },
  {
    "path": "bench/graphics/fidget/prospero.fpcore",
    "content": "(FPCore\n (x y)\n :name\n \"Text of a monologue from The Tempest\"\n :precision\n binary64\n (fmin\n  (fmin\n   (fmin\n    (fmin\n     (fmin\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (+ 2.95 (* x 8.13008)) (- (+ 3.675 (* x 8.13008))))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (- (+ 2.95 (* x 8.13008))) 2)\n                 (pow (+ 6.025 (* y 8.13008)) 2)))))\n             (-\n              (sqrt\n               (+\n                (pow (- (+ 2.95 (* x 8.13008))) 2)\n                (pow (+ 6.025 (* y 8.13008)) 2)))\n              0.275))\n            (+ 5.3 (* y 8.13008)))\n           (- (+ 6.3 (* y 8.13008))))\n          (fmax\n           (fmax\n            (fmax (+ 4.025 (* x 8.13008)) (- (+ 4.125 (* x 8.13008))))\n            (+ 5.3 (* y 8.13008)))\n           (- (+ 6.3 (* y 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 4.275 (* x 8.13008)) (- (+ 4.375 (* x 8.13008))))\n            (+ 5.3 (* y 8.13008)))\n           (- (+ 6.3 (* y 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (+ 5.5 (* y 8.13008)) (- (+ 5.75 (* y 8.13008))))\n             (+ 4.5 (* x 8.13008)))\n            (- (+ 4.6 (* x 8.13008))))\n           (fmax\n            (fmax\n             (fmax (- (+ 5.4 (* y 8.13008))) (+ 4.7 (* x 8.13008)))\n             (- (+ 5.2 (* x 8.13008))))\n            (+ 5.3 (* y 8.13008))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 4.7 (* x 8.13008)) (- (+ 5.2 (* x 8.13008))))\n            (+ 6.2 (* y 8.13008)))\n           (- (+ 6.3 (* y 8.13008))))\n          (fmax\n           (fmax\n            (fmax (+ 4.9 (* x 8.13008)) (- (+ 5 (* x 8.13008))))\n            (+ 5.3 (* y 8.13008)))\n           (- (+ 6.3 (* y 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 4.2 (* y 8.13008)) (- (+ 5.2 (* y 8.13008))))\n            (- 5.7205 (* x 8.13008)))\n           (- (* x 8.13008) 5.8205))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (+ 4.65 (* y 8.13008)) (- (+ 4.75 (* y 8.13008))))\n             (- 5.54551 (* x 8.13008)))\n            (- (* x 8.13008) 5.7205))\n           (fmax\n            (fmax\n             (fmax (- (+ 5.2 (* y 8.13008))) (- 5.54551 (* x 8.13008)))\n             (- (* x 8.13008) 5.7205))\n            (+ 5.1 (* y 8.13008)))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (+ 1.53565 (* y 2.84553)) (* x 4.47154))\n            (- (* x 4.47154) (+ 0.90565 (* y 2.03252))))\n           (- (+ 0.575 (* y 0.813008))))\n          (fmax\n           (fmax\n            (- (+ (+ (* y 2.03252) 2.24435) (* x 4.47154)))\n            (+ (+ 2.81935 (* y 2.84553)) (* x 4.47154)))\n           (- (+ 0.63 (* y 0.813008)))))\n         (fmin\n          (fmax\n           (fmax\n            (+ (+ (* y 2.03252) 2.24435) (* x 4.47154))\n            (- (+ (+ 2.81935 (* y 2.84553)) (* x 4.47154))))\n           (+ 0.63 (* y 0.813008)))\n          (fmin\n           (fmax\n            (fmax\n             (- (+ (+ 2.81935 (* y 2.84553)) (* x 4.47154)))\n             (+ (+ (* y 2.03252) 2.18935) (* x 4.47154)))\n            (+ 0.575 (* y 0.813008)))\n           (fmax\n            (fmax\n             (+ (+ 2.81935 (* y 2.84553)) (* x 4.47154))\n             (- (+ (+ (* y 2.03252) 2.18935) (* x 4.47154))))\n            (- (+ 0.575 (* y 0.813008)))))))\n        (fmin\n         (fmin\n          (fmax\n           (-\n            0.175\n            (sqrt\n             (+\n              (pow (+ 1.842 (* x 8.13008)) 2)\n              (pow (+ 6.025 (* y 8.13008)) 2))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 1.842 (* x 8.13008)) 2)\n              (pow (+ 6.025 (* y 8.13008)) 2)))\n            0.275))\n          (fmax\n           (fmax\n            (fmax (+ 2.475 (* x 8.13008)) (- (+ 2.575 (* x 8.13008))))\n            (+ 5.75 (* y 8.13008)))\n           (- (+ 6.3 (* y 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (+ 3.12857 (* x 11.6144)) (- (+ 3.67857 (* x 11.6144))))\n              (-\n               0.45\n               (sqrt\n                (+\n                 (pow (+ 6.3 (* y 8.13008)) 2)\n                 (pow (+ 3.91072 (* x 14.518)) 2)))))\n             (-\n              (sqrt\n               (+\n                (pow (+ 6.3 (* y 8.13008)) 2)\n                (pow (+ 3.12857 (* x 11.6144)) 2)))\n              0.55))\n            (+ 5.75 (* y 8.13008)))\n           (- (+ 6.3 (* y 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (+ 2.775 (* x 8.13008))) (+ 2.675 (* x 8.13008)))\n             (+ 5.3 (* y 8.13008)))\n            (- (+ 6.3 (* y 8.13008))))\n           (fmax\n            (fmax\n             (fmax (+ 2.775 (* x 8.13008)) (- (+ 2.95 (* x 8.13008))))\n             (+ 5.75 (* y 8.13008)))\n            (- (+ 5.85 (* y 8.13008)))))))))\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 2.775 (* x 8.13008)) (- (+ 2.95 (* x 8.13008))))\n            (+ 6.2 (* y 8.13008)))\n           (- (+ 6.3 (* y 8.13008))))\n          (fmax\n           (-\n            (fmin\n             (-\n              (sqrt\n               (+\n                (pow (- 1.33245 (* x 3.61337)) 2)\n                (pow (- (+ 4.815 (* y 8.13008))) 2)))\n              0.0625)\n             (fmax\n              (fmax\n               (fmax (- (+ 4.975 (* y 8.13008))) (+ 4.8125 (* y 8.13008)))\n               (- 2.00117 (* x 5.42005)))\n              (- (* x 5.42005) 2.16367))))\n           (-\n            (sqrt\n             (+\n              (pow (- (+ 4.8125 (* y 8.13008))) 2)\n              (pow (- 2.00117 (* x 5.42005)) 2)))\n            0.1625)))\n         (fmin\n          (fmax\n           (-\n            (fmin\n             (fmax\n              (fmax\n               (fmax (- (+ 5.0375 (* y 8.13008))) (- (* x 5.42005) 2.00117))\n               (- 1.83867 (* x 5.42005)))\n              (+ 4.875 (* y 8.13008)))\n             (-\n              (sqrt\n               (+\n                (pow (+ 5.035 (* y 8.13008)) 2)\n                (pow (- (* x 3.61337) 1.33578) 2)))\n              0.0625)))\n           (-\n            (sqrt\n             (+\n              (pow (+ 5.0375 (* y 8.13008)) 2)\n              (pow (- (* x 5.42005) 2.00117) 2)))\n            0.1625))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (+ 4.2 (* y 8.13008)) (- (+ 4.95 (* y 8.13008))))\n             (- (* x 8.13008) 1.808))\n            (- 1.708 (* x 8.13008)))\n           (fmax\n            (fmax\n             (fmax (+ 4.55 (* y 8.13008)) (- (+ 4.65 (* y 8.13008))))\n             (- (* x 8.13008) 1.958))\n            (- 1.558 (* x 8.13008))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (+ 5.2 (* y 8.13008))) (+ 4.95 (* y 8.13008)))\n              (- (* x 8.13008) 1.958))\n             (- 1.558 (* x 8.13008)))\n            (-\n             0.15\n             (sqrt\n              (+\n               (pow (+ 4.95 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) 1.958) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 4.95 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 1.958) 2)))\n            0.25))\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (+ 4.2 (* y 8.13008)) (- (+ 5.2 (* y 8.13008))))\n              (- 4.8205 (* x 8.13008)))\n             (- (* x 8.13008) 5.5455))\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (+ 4.925 (* y 8.13008)) 2)\n               (pow (- 5.54551 (* x 8.13008)) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 4.925 (* y 8.13008)) 2)\n              (pow (- 5.54551 (* x 8.13008)) 2)))\n            0.275)))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 5.2 (* y 8.13008))) (+ 4.875 (* y 8.13008)))\n            (- (* x 8.13008) 5.1955))\n           (- 5.0955 (* x 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (+ 5.2 (* y 8.13008))) (+ 4.65 (* y 8.13008)))\n             (- (* x 8.13008) 4.7455))\n            (- 4.6455 (* x 8.13008)))\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (+ 4.65 (* y 8.13008)) (- (* x 8.13008) 5.1955))\n               (- 4.6455 (* x 8.13008)))\n              (- (+ 4.875 (* y 8.13008))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (+ 4.925 (* y 8.13008)) 2)\n                (pow (- (* x 8.13008) 4.9205) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 4.925 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) 4.9205) 2)))\n             0.275))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 5.2 (* y 8.13008))) (+ 4.65 (* y 8.13008)))\n            (- (* x 8.13008) 4.5455))\n           (- 4.4455 (* x 8.13008)))\n          (fmax\n           (fmax\n            (fmax (+ 4.65 (* y 8.13008)) (- (+ 4.925 (* y 8.13008))))\n            (- (* x 8.13008) 4.0955))\n           (- 3.9955 (* x 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (+ 5.2 (* y 8.13008))) (+ 4.925 (* y 8.13008)))\n              (- (* x 8.13008) 4.5455))\n             (- 3.9955 (* x 8.13008)))\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (+ 4.925 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) 4.2705) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 4.925 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 4.2705) 2)))\n            0.275))\n          (fmin\n           (fmax\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (+ 4.925 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) 3.6205) 2))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 4.925 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) 3.6205) 2)))\n             0.275))\n           (fmax\n            (fmax\n             (fmax (- (+ 5.2 (* y 8.13008))) (+ 0.142001 (* x 8.13008)))\n             (- (+ 0.242001 (* x 8.13008))))\n            (+ 4.85 (* y 8.13008))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 5.2 (* y 8.13008))) (+ 0.392001 (* x 8.13008)))\n            (- (+ 0.492001 (* x 8.13008))))\n           (+ 4.675 (* y 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax (+ 4.55 (* y 8.13008)) (- (+ 0.492001 (* x 8.13008))))\n              (- (* x 8.13008) 0.157999))\n             (fmin\n              (fmax\n               (-\n                0.075\n                (sqrt\n                 (+\n                  (pow (+ 0.0670004 (* x 8.13008)) 2)\n                  (pow (+ 4.85 (* y 8.13008)) 2))))\n               (-\n                (sqrt\n                 (+\n                  (pow (+ 0.0670004 (* x 8.13008)) 2)\n                  (pow (+ 4.85 (* y 8.13008)) 2)))\n                0.175))\n              (fmax\n               (-\n                0.075\n                (sqrt\n                 (+\n                  (pow (+ 0.317 (* x 8.13008)) 2)\n                  (pow (+ 4.85 (* y 8.13008)) 2))))\n               (-\n                (sqrt\n                 (+\n                  (pow (+ 0.317 (* x 8.13008)) 2)\n                  (pow (+ 4.85 (* y 8.13008)) 2)))\n                0.175))))\n            (- (+ 4.85 (* y 8.13008))))\n           (fmax\n            (fmax\n             (fmax (- (+ 5.2 (* y 8.13008))) (+ 4.65 (* y 8.13008)))\n             (+ 0.592 (* x 8.13008)))\n            (- (+ 0.692001 (* x 8.13008))))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 4.65 (* y 8.13008)) (- (+ 4.925 (* y 8.13008))))\n            (+ 1.042 (* x 8.13008)))\n           (- (+ 1.142 (* x 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- (+ 5.2 (* y 8.13008))) (+ 4.925 (* y 8.13008)))\n               (+ 0.592 (* x 8.13008)))\n              (- (+ 1.142 (* x 8.13008))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (+ 4.925 (* y 8.13008)) 2)\n                (pow (+ 0.867001 (* x 8.13008)) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 4.925 (* y 8.13008)) 2)\n               (pow (+ 0.867001 (* x 8.13008)) 2)))\n             0.275))\n           (fmax\n            (fmax\n             (fmax (+ 4.2 (* y 8.13008)) (- (+ 5.2 (* y 8.13008))))\n             (+ 1.267 (* x 8.13008)))\n            (- (+ 1.367 (* x 8.13008))))))))))\n     (fmin\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 4.65 (* y 8.13008)) (- (+ 5.575 (* y 8.13008))))\n            (+ 1.942 (* x 8.13008)))\n           (- (+ 2.042 (* x 8.13008))))\n          (fmax\n           (-\n            (sqrt\n             (+\n              (pow (+ 4.925 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 1.183) 2)))\n            0.275)\n           (fmin\n            (fmax\n             (fmax\n              (fmax (+ 4.885 (* y 8.13008)) (- (+ 4.975 (* y 8.13008))))\n              (- (* x 8.13008) 1.458))\n             (- 0.958001 (* x 8.13008)))\n            (fmax\n             (fmax\n              (-\n               (sqrt\n                (+\n                 (pow (+ 4.925 (* y 8.13008)) 2)\n                 (pow (- (* x 8.13008) 1.183) 2)))\n               0.275)\n              (-\n               (fmin\n                (fmax\n                 (fmax\n                  (+ 3.20125 (* y 5.28455))\n                  (- (* x 2.23577) (+ 1.1947 (* y 1.21951))))\n                 (- (+ (+ 2.1853 (* x 2.23577)) (* y 4.06504))))\n                (fmax\n                 (fmax\n                  (+ (+ 2.1853 (* x 2.23577)) (* y 4.06504))\n                  (- (+ 1.1947 (* y 1.21951)) (* x 2.23577)))\n                 (- (+ 3.20125 (* y 5.28455)))))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (+ 4.925 (* y 8.13008)) 2)\n                (pow (- (* x 8.13008) 1.183) 2))))))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 5.2 (* y 8.13008))) (+ 4.85 (* y 8.13008)))\n            (- (* x 8.13008) 0.808001))\n           (- 0.708 (* x 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (+ 5.2 (* y 8.13008))) (+ 4.85 (* y 8.13008)))\n             (- (* x 8.13008) 0.558001))\n            (- 0.458 (* x 8.13008)))\n           (fmax\n            (fmax\n             (fmax (- (+ 5.2 (* y 8.13008))) (+ 4.675 (* y 8.13008)))\n             (- (* x 8.13008) 0.308001))\n            (- 0.208 (* x 8.13008))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax (+ 4.55 (* y 8.13008)) (- 0.208 (* x 8.13008)))\n             (- (+ 4.85 (* y 8.13008))))\n            (- (* x 8.13008) 0.858))\n           (fmin\n            (fmax\n             (-\n              0.075\n              (sqrt\n               (+\n                (pow (+ 4.85 (* y 8.13008)) 2)\n                (pow (- (* x 8.13008) 0.633) 2))))\n             (-\n              (sqrt\n               (+\n                (pow (+ 4.85 (* y 8.13008)) 2)\n                (pow (- (* x 8.13008) 0.633) 2)))\n              0.175))\n            (fmax\n             (-\n              0.075\n              (sqrt\n               (+\n                (pow (+ 4.85 (* y 8.13008)) 2)\n                (pow (- (* x 8.13008) 0.383) 2))))\n             (-\n              (sqrt\n               (+\n                (pow (+ 4.85 (* y 8.13008)) 2)\n                (pow (- (* x 8.13008) 0.383) 2)))\n              0.175))))\n          (fmax\n           (fmax\n            (fmax (- (+ 5.2 (* y 8.13008))) (+ 4.85 (* y 8.13008)))\n            (- (* x 8.13008) 0.108))\n           (- 0.00799942 (* x 8.13008))))\n         (fmin\n          (fmax\n           (-\n            0.175\n            (sqrt\n             (+\n              (pow (+ 4.925 (* y 8.13008)) 2)\n              (pow (+ 1.767 (* x 8.13008)) 2))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 4.925 (* y 8.13008)) 2)\n              (pow (+ 1.767 (* x 8.13008)) 2)))\n            0.275))\n          (fmin\n           (fmax\n            (fmax\n             (+ (+ (* y 2.84553) 4.13) (* x 4.47154))\n             (- (+ 0.52 (* y 0.813008))))\n            (- (+ (+ (* y 2.03252) 3.665) (* x 4.47154))))\n           (fmax\n            (fmax\n             (- (+ (+ (* y 2.84553) 4.13) (* x 4.47154)))\n             (+ 0.52 (* y 0.813008)))\n            (+ (+ (* y 2.03252) 3.665) (* x 4.47154)))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (+ (+ (* y 2.84553) 4.13) (* x 4.47154)))\n            (+ (+ (* y 2.03252) 3.61) (* x 4.47154)))\n           (+ 0.465 (* y 0.813008)))\n          (fmax\n           (fmax\n            (+ (+ (* y 2.84553) 4.13) (* x 4.47154))\n            (- (+ (+ (* y 2.03252) 3.61) (* x 4.47154))))\n           (- (+ 0.465 (* y 0.813008)))))\n         (fmin\n          (fmax\n           (-\n            (sqrt\n             (+\n              (pow (+ 4.925 (* y 8.13008)) 2)\n              (pow (+ 4.925 (* x 8.13008)) 2)))\n            0.275)\n           (fmin\n            (fmax\n             (fmax\n              (fmax (+ 4.885 (* y 8.13008)) (- (+ 4.975 (* y 8.13008))))\n              (+ 4.65 (* x 8.13008)))\n             (- (+ 5.15 (* x 8.13008))))\n            (fmax\n             (fmax\n              (-\n               (sqrt\n                (+\n                 (pow (+ 4.925 (* y 8.13008)) 2)\n                 (pow (+ 4.925 (* x 8.13008)) 2)))\n               0.275)\n              (-\n               (fmin\n                (fmax\n                 (fmax\n                  (+ 3.20125 (* y 5.28455))\n                  (- (+ 0.485 (* x 2.23577)) (* y 1.21951)))\n                 (- (+ (+ (* x 2.23577) 3.865) (* y 4.06504))))\n                (fmax\n                 (fmax\n                  (- (+ 3.20125 (* y 5.28455)))\n                  (+ (+ (* x 2.23577) 3.865) (* y 4.06504)))\n                 (- (* y 1.21951) (+ 0.485 (* x 2.23577)))))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (+ 4.925 (* y 8.13008)) 2)\n                (pow (+ 4.925 (* x 8.13008)) 2)))))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (+ 3.1 (* y 8.13008)) (- (+ 4.1 (* y 8.13008))))\n             (- 7.531 (* x 8.13008)))\n            (- (* x 8.13008) 7.631))\n           (fmax\n            (fmax\n             (fmax (+ 3.55 (* y 8.13008)) (- (+ 3.65 (* y 8.13008))))\n             (- 7.35601 (* x 8.13008)))\n            (- (* x 8.13008) 7.531)))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 4.1 (* y 8.13008))) (- 7.35601 (* x 8.13008)))\n            (- (* x 8.13008) 7.531))\n           (+ 4 (* y 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (+ 3.1 (* y 8.13008)) (- (+ 4.1 (* y 8.13008))))\n               (- 6.631 (* x 8.13008)))\n              (- (* x 8.13008) 7.356))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (+ 3.825 (* y 8.13008)) 2)\n                (pow (- 7.35601 (* x 8.13008)) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 3.825 (* y 8.13008)) 2)\n               (pow (- 7.35601 (* x 8.13008)) 2)))\n             0.275))\n           (fmax\n            (fmax\n             (fmax (- (+ 5.2 (* y 8.13008))) (+ 4.65 (* y 8.13008)))\n             (+ 3.1 (* x 8.13008)))\n            (- (+ 3.2 (* x 8.13008))))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (+ 5.2 (* y 8.13008))) (+ 4.65 (* y 8.13008)))\n              (+ 4.02143 (* x 11.6144)))\n             (- (+ 4.57143 (* x 11.6144))))\n            (-\n             0.45\n             (sqrt\n              (+\n               (pow (+ 5.2 (* y 8.13008)) 2)\n               (pow (+ 5.02679 (* x 14.518)) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 5.2 (* y 8.13008)) 2)\n              (pow (+ 4.02143 (* x 11.6144)) 2)))\n            0.55))\n          (fmin\n           (fmax\n            (-\n             (sqrt\n              (+\n               (pow (+ 4.925 (* y 8.13008)) 2)\n               (pow (+ 3.575 (* x 8.13008)) 2)))\n             0.275)\n            (fmin\n             (fmax\n              (fmax\n               (fmax (+ 4.885 (* y 8.13008)) (- (+ 4.975 (* y 8.13008))))\n               (+ 3.3 (* x 8.13008)))\n              (- (+ 3.8 (* x 8.13008))))\n             (fmax\n              (fmax\n               (-\n                (sqrt\n                 (+\n                  (pow (+ 4.925 (* y 8.13008)) 2)\n                  (pow (+ 3.575 (* x 8.13008)) 2)))\n                0.275)\n               (-\n                (fmin\n                 (fmax\n                  (fmax\n                   (+ 3.20125 (* y 5.28455))\n                   (- (+ 0.11375 (* x 2.23577)) (* y 1.21951)))\n                  (- (+ (+ (* x 2.23577) 3.49375) (* y 4.06504))))\n                 (fmax\n                  (fmax\n                   (- (+ 3.20125 (* y 5.28455)))\n                   (+ (+ (* x 2.23577) 3.49375) (* y 4.06504)))\n                  (- (* y 1.21951) (+ 0.11375 (* x 2.23577)))))))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (+ 4.925 (* y 8.13008)) 2)\n                 (pow (+ 3.575 (* x 8.13008)) 2)))))))\n           (fmax\n            (fmax\n             (- (+ 0.52 (* y 0.813008)))\n             (- (+ 1.01 (* x 4.47154)) (* y 2.03252)))\n            (- (* y 2.84553) (+ 0.545 (* x 4.47154)))))))))\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (+ 0.52 (* y 0.813008))\n            (- (+ 0.545 (* x 4.47154)) (* y 2.84553)))\n           (- (* y 2.03252) (+ 1.01 (* x 4.47154))))\n          (fmax\n           (fmax\n            (- (+ 0.545 (* x 4.47154)) (* y 2.84553))\n            (+ 0.465 (* y 0.813008)))\n           (- (* y 2.03252) (+ 1.065 (* x 4.47154)))))\n         (fmin\n          (fmax\n           (fmax\n            (- (* y 2.84553) (+ 0.545 (* x 4.47154)))\n            (- (+ 1.065 (* x 4.47154)) (* y 2.03252)))\n           (- (+ 0.465 (* y 0.813008))))\n          (fmin\n           (-\n            (sqrt\n             (+\n              (pow (+ 6.225 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 5.733) 2)))\n            0.075)\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (-\n                (fmin\n                 (fmin\n                  (fmin\n                   (fmax\n                    (fmax (+ 2.65 (* y 4.06504)) (- (* x 4.06504) 2.829))\n                    (- (+ 0.0709989 (* (+ x y) 4.06504))))\n                   (fmax\n                    (fmax\n                     (+ 0.0709989 (* (+ x y) 4.06504))\n                     (- 2.829 (* x 4.06504)))\n                    (- (+ 2.65 (* y 4.06504)))))\n                  (fmin\n                   (fmax\n                    (fmax\n                     (- (* x 8.13008) (+ (* y 0.813008) 6.188))\n                     (- (+ (+ 0.0706995 (* y 2.60163)) (* x 2.84553))))\n                    (- (+ (* y 3.41463) 5.9037) (* x 5.28455)))\n                   (fmax\n                    (fmax\n                     (- (* x 5.28455) (+ (* y 3.41463) 5.9037))\n                     (+ (+ 0.0706992 (* y 2.60163)) (* x 2.84553)))\n                    (- (+ (* y 0.813008) 6.188) (* x 8.13008)))))\n                 (fmin\n                  (fmin\n                   (fmax\n                    (fmax (- (+ 1.728 (* y 2.19512))) (- 1.8053 (* x 2.84553)))\n                    (- (+ (* y 2.19512) (* x 2.84553)) 0.171801))\n                   (fmax\n                    (fmax\n                     (+ 1.728 (* y 2.19512))\n                     (- 0.171801 (+ (* y 2.19512) (* x 2.84553))))\n                    (- (* x 2.84553) 1.8053)))\n                  (fmin\n                   (fmax\n                    (fmax\n                     (+ 2.12 (* y 3.25203))\n                     (- (* x 4.47154) (+ (* y 3.25203) 5.1769)))\n                    (- 2.8369 (* x 4.47154)))\n                   (fmax\n                    (fmax\n                     (- (* x 4.47154) 2.8369)\n                     (- (+ (* y 3.25203) 5.1769) (* x 4.47154)))\n                    (- (+ 2.12 (* y 3.25203))))))))\n               (+ 5.3 (* y 8.13008)))\n              (- (+ 6.3 (* y 8.13008))))\n             (- (* x 8.13008) 5.558))\n            (- 5.058 (* x 8.13008))))))\n        (fmin\n         (fmin\n          (fmax\n           (-\n            0.175\n            (sqrt\n             (+\n              (pow (+ 6.025 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 4.683) 2))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 6.025 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 4.683) 2)))\n            0.275))\n          (fmax\n           (-\n            0.175\n            (sqrt\n             (+\n              (pow (+ 6.025 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 4.033) 2))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 6.025 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 4.033) 2)))\n            0.275)))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* x 8.13008) 3.233) (- 3.133 (* x 8.13008)))\n            (+ 5.3 (* y 8.13008)))\n           (- (+ 6.3 (* y 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (+ 5.75 (* y 8.13008)) (- (+ 5.85 (* y 8.13008))))\n             (- (* x 8.13008) 3.408))\n            (- 3.233 (* x 8.13008)))\n           (fmax\n            (fmax\n             (fmax (- (* x 8.13008) 3.408) (- 3.233 (* x 8.13008)))\n             (+ 6.2 (* y 8.13008)))\n            (- (+ 6.3 (* y 8.13008))))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (* x 8.13008) 4.133) (- 3.408 (* x 8.13008)))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (+ 6.025 (* y 8.13008)) 2)\n                 (pow (- (* x 8.13008) 3.408) 2)))))\n             (-\n              (sqrt\n               (+\n                (pow (+ 6.025 (* y 8.13008)) 2)\n                (pow (- (* x 8.13008) 3.408) 2)))\n              0.275))\n            (+ 5.3 (* y 8.13008)))\n           (- (+ 6.3 (* y 8.13008))))\n          (fmax\n           (fmax\n            (- (+ 0.685 (* y 0.813008)))\n            (- (* x 4.47154) (+ (* y 1.82927) 2.5769)))\n           (- (+ (* y 2.64228) 3.2069) (* x 4.47154))))\n         (fmin\n          (fmax\n           (fmax\n            (+ 0.685 (* y 0.813008))\n            (- (* x 4.47154) (+ (* y 2.64228) 3.2069)))\n           (- (+ (* y 1.82927) 2.5769) (* x 4.47154)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- 1.083 (* x 8.13008)) (+ 5.65 (* y 8.13008)))\n              (- (+ 5.95 (* y 8.13008))))\n             (- (* x 8.13008) 1.733))\n            (fmin\n             (fmax\n              (-\n               0.075\n               (sqrt\n                (+\n                 (pow (+ 5.95 (* y 8.13008)) 2)\n                 (pow (- (* x 8.13008) 1.508) 2))))\n              (-\n               (sqrt\n                (+\n                 (pow (+ 5.95 (* y 8.13008)) 2)\n                 (pow (- (* x 8.13008) 1.508) 2)))\n               0.175))\n             (fmax\n              (-\n               0.075\n               (sqrt\n                (+\n                 (pow (+ 5.95 (* y 8.13008)) 2)\n                 (pow (- (* x 8.13008) 1.258) 2))))\n              (-\n               (sqrt\n                (+\n                 (pow (+ 5.95 (* y 8.13008)) 2)\n                 (pow (- (* x 8.13008) 1.258) 2)))\n               0.175))))\n           (fmax\n            (fmax\n             (fmax (- (+ 6.3 (* y 8.13008))) (+ 5.975 (* y 8.13008)))\n             (- (* x 8.13008) 0.282999))\n            (- 0.182999 (* x 8.13008))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 5.75 (* y 8.13008)) (- (+ 6.3 (* y 8.13008))))\n            (+ 0.167001 (* x 8.13008)))\n           (- (+ 0.267001 (* x 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (+ 5.75 (* y 8.13008)) (- (* x 8.13008) 0.282999))\n               (- (+ 0.267001 (* x 8.13008))))\n              (- (+ 5.975 (* y 8.13008))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (+ 6.025 (* y 8.13008)) 2)\n                (pow (- (* x 8.13008) 0.00799847) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 6.025 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) 0.00799847) 2)))\n             0.275))\n           (fmax\n            (fmax\n             (- (* x 4.47154) (+ 1.23565 (* y 2.03252)))\n             (- (+ 1.81065 (* y 2.84553)) (* x 4.47154)))\n            (- (+ 0.63 (* y 0.813008))))))\n         (fmin\n          (fmax\n           (fmax\n            (- (* x 4.47154) (+ 1.81065 (* y 2.84553)))\n            (- (+ 1.23565 (* y 2.03252)) (* x 4.47154)))\n           (+ 0.63 (* y 0.813008)))\n          (fmin\n           (fmax\n            (fmax\n             (- (* x 4.47154) (+ 1.81065 (* y 2.84553)))\n             (- (+ 1.18065 (* y 2.03252)) (* x 4.47154)))\n            (+ 0.575 (* y 0.813008)))\n           (fmax\n            (fmax\n             (- (+ 1.81065 (* y 2.84553)) (* x 4.47154))\n             (- (* x 4.47154) (+ 1.18065 (* y 2.03252))))\n            (- (+ 0.575 (* y 0.813008)))))))))))\n    (fmin\n     (fmin\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (+ (+ 1.96935 (* y 2.03252)) (* x 4.47154)))\n            (+ (+ 2.54435 (* y 2.84553)) (* x 4.47154)))\n           (- (+ 0.63 (* y 0.813008))))\n          (fmax\n           (fmax\n            (+ (+ 1.96935 (* y 2.03252)) (* x 4.47154))\n            (- (+ (+ 2.54435 (* y 2.84553)) (* x 4.47154))))\n           (+ 0.63 (* y 0.813008))))\n         (fmin\n          (fmax\n           (fmax\n            (- (+ (+ 2.54435 (* y 2.84553)) (* x 4.47154)))\n            (+ (+ 1.91435 (* y 2.03252)) (* x 4.47154)))\n           (+ 0.575 (* y 0.813008)))\n          (fmin\n           (fmax\n            (fmax\n             (+ (+ 2.54435 (* y 2.84553)) (* x 4.47154))\n             (- (+ (+ 1.91435 (* y 2.03252)) (* x 4.47154))))\n            (- (+ 0.575 (* y 0.813008))))\n           (fmax\n            (fmax\n             (- (* x 4.47154) (+ 0.96065 (* y 2.03252)))\n             (- (+ 1.53565 (* y 2.84553)) (* x 4.47154)))\n            (- (+ 0.63 (* y 0.813008)))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (* x 4.47154) (+ 1.53565 (* y 2.84553)))\n            (- (+ 0.96065 (* y 2.03252)) (* x 4.47154)))\n           (+ 0.63 (* y 0.813008)))\n          (fmax\n           (fmax\n            (- (* x 4.47154) (+ 1.53565 (* y 2.84553)))\n            (- (+ 0.90565 (* y 2.03252)) (* x 4.47154)))\n           (+ 0.575 (* y 0.813008))))\n         (fmin\n          (fmax\n           (fmax\n            (- (* x 4.47154) (+ (* y 2.64228) 3.2069))\n            (+ 0.63 (* y 0.813008)))\n           (- (+ (* y 1.82927) 2.5219) (* x 4.47154)))\n          (fmin\n           (fmax\n            (fmax\n             (- (+ (* y 2.64228) 3.2069) (* x 4.47154))\n             (- (* x 4.47154) (+ (* y 1.82927) 2.5219)))\n            (- (+ 0.63 (* y 0.813008))))\n           (fmax\n            (fmax\n             (- (* x 4.47154) (+ (* y 1.82927) 2.5769))\n             (- (+ 0.63 (* y 0.813008))))\n            (- (+ (* y 2.64228) 3.1519) (* x 4.47154)))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (+ (* y 1.82927) 2.5769) (* x 4.47154))\n            (+ 0.63 (* y 0.813008)))\n           (- (* x 4.47154) (+ (* y 2.64228) 3.1519)))\n          (fmax\n           (fmax\n            (- (+ (* y 1.82927) 2.5219) (* x 4.47154))\n            (- (* x 4.47154) (+ (* y 2.64228) 3.1519)))\n           (+ 0.575 (* y 0.813008))))\n         (fmin\n          (fmax\n           (fmax\n            (- (* x 4.47154) (+ (* y 1.82927) 2.5219))\n            (- (+ (* y 2.64228) 3.1519) (* x 4.47154)))\n           (- (+ 0.575 (* y 0.813008))))\n          (fmin\n           (fmax\n            (fmax\n             (- (+ 0.63 (* y 0.813008)))\n             (- (+ (+ 0.3131 (* y 1.82927)) (* x 4.47154))))\n            (+ (+ 0.8881 (* y 2.64228)) (* x 4.47154)))\n           (fmax\n            (fmax\n             (+ 0.63 (* y 0.813008))\n             (+ (+ 0.3131 (* y 1.82927)) (* x 4.47154)))\n            (- (+ (+ 0.8881 (* y 2.64228)) (* x 4.47154)))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (+ 0.575 (* y 0.813008))\n            (- (+ (+ 0.8881 (* y 2.64228)) (* x 4.47154))))\n           (+ (+ 0.2581 (* y 1.82927)) (* x 4.47154)))\n          (fmax\n           (fmax\n            (- (+ 0.575 (* y 0.813008)))\n            (+ (+ 0.8881 (* y 2.64228)) (* x 4.47154)))\n           (- (+ (+ 0.2581 (* y 1.82927)) (* x 4.47154)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 6.3 (* y 8.13008))) (+ 5.95 (* y 8.13008)))\n            (- (* x 8.13008) 1.683))\n           (- 1.583 (* x 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (+ 6.3 (* y 8.13008))) (+ 5.95 (* y 8.13008)))\n             (- (* x 8.13008) 1.433))\n            (- 1.333 (* x 8.13008)))\n           (fmax\n            (fmax\n             (fmax (- (+ 6.3 (* y 8.13008))) (+ 5.775 (* y 8.13008)))\n             (- (* x 8.13008) 1.183))\n            (- 1.083 (* x 8.13008))))))))\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 2.65 (* y 8.13008)) (- (* x 8.13008) 1.498))\n            (- 1.398 (* x 8.13008)))\n           (- (+ 3 (* y 8.13008))))\n          (fmax\n           (fmax\n            (fmax (+ 2.65 (* y 8.13008)) (- (* x 8.13008) 1.248))\n            (- 1.148 (* x 8.13008)))\n           (- (+ 3 (* y 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 2.475 (* y 8.13008)) (- (* x 8.13008) 0.998001))\n            (- 0.898001 (* x 8.13008)))\n           (- (+ 3 (* y 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- 0.898001 (* x 8.13008)) (- (+ 2.65 (* y 8.13008))))\n              (- (* x 8.13008) 1.548))\n             (fmin\n              (fmax\n               (-\n                0.075\n                (sqrt\n                 (+\n                  (pow (+ 2.65 (* y 8.13008)) 2)\n                  (pow (- (* x 8.13008) 1.323) 2))))\n               (-\n                (sqrt\n                 (+\n                  (pow (+ 2.65 (* y 8.13008)) 2)\n                  (pow (- (* x 8.13008) 1.323) 2)))\n                0.175))\n              (fmax\n               (-\n                0.075\n                (sqrt\n                 (+\n                  (pow (+ 2.65 (* y 8.13008)) 2)\n                  (pow (- (* x 8.13008) 1.073) 2))))\n               (-\n                (sqrt\n                 (+\n                  (pow (+ 2.65 (* y 8.13008)) 2)\n                  (pow (- (* x 8.13008) 1.073) 2)))\n                0.175))))\n            (+ 2.35 (* y 8.13008)))\n           (fmax\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (- (* x 8.13008) 0.523) 2)\n               (pow (+ 2.725 (* y 8.13008)) 2))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* x 8.13008) 0.523) 2)\n               (pow (+ 2.725 (* y 8.13008)) 2)))\n             0.275)))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* x 8.13008) 0.0979996) (- (+ 0.00200015 (* x 8.13008))))\n            (- (+ 3 (* y 8.13008))))\n           (+ 2.725 (* y 8.13008)))\n          (fmax\n           (fmax\n            (fmax (+ 0.352 (* x 8.13008)) (- (+ 0.452 (* x 8.13008))))\n            (- (+ 3 (* y 8.13008))))\n           (+ 2 (* y 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (* x 8.13008) 0.0979996) (- (+ 0.452 (* x 8.13008))))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (+ 0.177 (* x 8.13008)) 2)\n                 (pow (+ 2.725 (* y 8.13008)) 2)))))\n             (-\n              (sqrt\n               (+\n                (pow (+ 0.177 (* x 8.13008)) 2)\n                (pow (+ 2.725 (* y 8.13008)) 2)))\n              0.275))\n            (+ 2.45 (* y 8.13008)))\n           (- (+ 2.725 (* y 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax\n                (-\n                 0.175\n                 (sqrt\n                  (+\n                   (pow (- (* x 8.13008) 3.4105) 2)\n                   (pow (+ 2.725 (* y 8.13008)) 2))))\n                (-\n                 (sqrt\n                  (+\n                   (pow (- (* x 8.13008) 3.4105) 2)\n                   (pow (+ 2.725 (* y 8.13008)) 2)))\n                 0.275))\n               (+ 2.45 (* y 8.13008)))\n              (- (* x 8.13008) 3.6855))\n             (- 3.1355 (* x 8.13008)))\n            (- (+ 2.675 (* y 8.13008))))\n           (fmax\n            (fmax\n             (fmax (- (* x 8.13008) 3.0105) (- 2.9105 (* x 8.13008)))\n             (- (+ 3 (* y 8.13008))))\n            (+ 2.45 (* y 8.13008)))))))\n       (fmin\n        (fmin\n         (fmin\n          (-\n           (sqrt\n            (+ (pow (+ 2.3 (* y 8.13008)) 2) (pow (- (* x 8.13008) 2.9605) 2)))\n           0.075)\n          (fmax\n           (-\n            (fmin\n             (fmax\n              (fmax\n               (fmax (- (+ 2.775 (* y 8.13008))) (+ 2.6125 (* y 8.13008)))\n               (- 1.22783 (* x 5.42005)))\n              (- (* x 5.42005) 1.39033))\n             (-\n              (sqrt\n               (+\n                (pow (- (+ 2.615 (* y 8.13008))) 2)\n                (pow (- 0.81689 (* x 3.61337)) 2)))\n              0.0625)))\n           (-\n            (sqrt\n             (+\n              (pow (- (+ 2.6125 (* y 8.13008))) 2)\n              (pow (- 1.22783 (* x 5.42005)) 2)))\n            0.1625)))\n         (fmin\n          (fmax\n           (-\n            (fmin\n             (fmax\n              (fmax\n               (fmax (- (+ 2.8375 (* y 8.13008))) (- (* x 5.42005) 1.22783))\n               (- 1.06533 (* x 5.42005)))\n              (+ 2.675 (* y 8.13008)))\n             (-\n              (sqrt\n               (+\n                (pow (+ 2.835 (* y 8.13008)) 2)\n                (pow (- (* x 3.61337) 0.820223) 2)))\n              0.0625)))\n           (-\n            (sqrt\n             (+\n              (pow (+ 2.8375 (* y 8.13008)) 2)\n              (pow (- (* x 5.42005) 1.22783) 2)))\n            0.1625))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax\n                (-\n                 0.175\n                 (sqrt\n                  (+\n                   (pow (+ 3.207 (* x 8.13008)) 2)\n                   (pow (+ 2.725 (* y 8.13008)) 2))))\n                (-\n                 (sqrt\n                  (+\n                   (pow (+ 3.207 (* x 8.13008)) 2)\n                   (pow (+ 2.725 (* y 8.13008)) 2)))\n                 0.275))\n               (+ 2.932 (* x 8.13008)))\n              (- (+ 3.482 (* x 8.13008))))\n             (+ 2.45 (* y 8.13008)))\n            (- (+ 2.675 (* y 8.13008))))\n           (fmax\n            (fmax\n             (fmax (+ 3.607 (* x 8.13008)) (- (+ 3.707 (* x 8.13008))))\n             (- (+ 3 (* y 8.13008))))\n            (+ 2.45 (* y 8.13008))))))\n        (fmin\n         (fmin\n          (-\n           (sqrt\n            (+ (pow (+ 2.3 (* y 8.13008)) 2) (pow (+ 3.657 (* x 8.13008)) 2)))\n           0.075)\n          (fmin\n           (fmax\n            (fmax\n             (fmax (+ 2.65 (* y 8.13008)) (+ 3.852 (* x 8.13008)))\n             (- (+ 3.952 (* x 8.13008))))\n            (- (+ 3 (* y 8.13008))))\n           (fmax\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (- (+ 3.35486 (* x 8.13008)) (* y 2.32288)) 2)\n               (pow (+ 2.725 (* y 8.13008)) 2))))\n            (-\n             (sqrt\n              (+\n               (pow (- (+ 3.35486 (* x 8.13008)) (* y 2.32288)) 2)\n               (pow (+ 2.725 (* y 8.13008)) 2)))\n             0.275))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 4.662 (* x 8.13008)) (- (+ 4.762 (* x 8.13008))))\n            (+ 2 (* y 8.13008)))\n           (- (+ 2.75 (* y 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (+ 4.512 (* x 8.13008)) (- (+ 4.912 (* x 8.13008))))\n             (+ 2.35 (* y 8.13008)))\n            (- (+ 2.45 (* y 8.13008))))\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (+ 4.512 (* x 8.13008)) (- (+ 4.912 (* x 8.13008))))\n               (-\n                0.15\n                (sqrt\n                 (+\n                  (pow (+ 4.512 (* x 8.13008)) 2)\n                  (pow (+ 2.75 (* y 8.13008)) 2)))))\n              (-\n               (sqrt\n                (+\n                 (pow (+ 4.512 (* x 8.13008)) 2)\n                 (pow (+ 2.75 (* y 8.13008)) 2)))\n               0.25))\n             (- (+ 3 (* y 8.13008))))\n            (+ 2.75 (* y 8.13008)))))))))\n     (fmin\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 5.27 (* x 8.13008)) (- (+ 5.37 (* x 8.13008))))\n            (- (+ 3 (* y 8.13008))))\n           (+ 2.45 (* y 8.13008)))\n          (fmax\n           (fmax\n            (fmax (+ 0.702 (* x 8.13008)) (- (+ 0.802 (* x 8.13008))))\n            (+ 2 (* y 8.13008)))\n           (- (+ 2.75 (* y 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 0.552 (* x 8.13008)) (- (+ 0.952 (* x 8.13008))))\n            (+ 2.35 (* y 8.13008)))\n           (- (+ 2.45 (* y 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (+ 0.552 (* x 8.13008)) (- (+ 0.952 (* x 8.13008))))\n               (-\n                0.15\n                (sqrt\n                 (+\n                  (pow (+ 0.552 (* x 8.13008)) 2)\n                  (pow (+ 2.75 (* y 8.13008)) 2)))))\n              (-\n               (sqrt\n                (+\n                 (pow (+ 0.552 (* x 8.13008)) 2)\n                 (pow (+ 2.75 (* y 8.13008)) 2)))\n               0.25))\n             (- (+ 3 (* y 8.13008))))\n            (+ 2.75 (* y 8.13008)))\n           (fmax\n            (fmax\n             (fmax (+ 2.65 (* y 8.13008)) (+ 1.072 (* x 8.13008)))\n             (- (+ 1.172 (* x 8.13008))))\n            (- (+ 3 (* y 8.13008)))))))\n        (fmin\n         (fmin\n          (fmax\n           (-\n            0.175\n            (sqrt\n             (+\n              (pow (- (+ 0.574857 (* x 8.13008)) (* y 2.32288)) 2)\n              (pow (+ 2.725 (* y 8.13008)) 2))))\n           (-\n            (sqrt\n             (+\n              (pow (- (+ 0.574857 (* x 8.13008)) (* y 2.32288)) 2)\n              (pow (+ 2.725 (* y 8.13008)) 2)))\n            0.275))\n          (fmax\n           (fmax\n            (fmax (+ 2.25 (* y 8.13008)) (+ 1.882 (* x 8.13008)))\n            (- (+ 1.982 (* x 8.13008))))\n           (- (+ 3 (* y 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 2.55 (* y 8.13008))) (+ 1.732 (* x 8.13008)))\n            (- (+ 2.132 (* x 8.13008))))\n           (+ 2.45 (* y 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (+ 1.732 (* x 8.13008)) (- (+ 2.132 (* x 8.13008))))\n               (- (+ 2.25 (* y 8.13008))))\n              (-\n               0.15\n               (sqrt\n                (+\n                 (pow (+ 2.25 (* y 8.13008)) 2)\n                 (pow (+ 1.732 (* x 8.13008)) 2)))))\n             (-\n              (sqrt\n               (+\n                (pow (+ 2.25 (* y 8.13008)) 2)\n                (pow (+ 1.732 (* x 8.13008)) 2)))\n              0.25))\n            (+ 2 (* y 8.13008)))\n           (fmax\n            (fmax\n             (fmax (+ 2.932 (* x 8.13008)) (- (+ 3.032 (* x 8.13008))))\n             (- (+ 3 (* y 8.13008))))\n            (+ 2.675 (* y 8.13008)))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 3.382 (* x 8.13008)) (- (+ 3.482 (* x 8.13008))))\n            (- (+ 3 (* y 8.13008))))\n           (+ 2.45 (* y 8.13008)))\n          (fmax\n           (fmax\n            (fmax (+ 1.25 (* y 8.13008)) (- (+ 1.35 (* y 8.13008))))\n            (- (* x 8.13008) 6.6385))\n           (- 6.2385 (* x 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (* x 8.13008) 6.6385) (- 6.2385 (* x 8.13008)))\n              (- (+ 1.9 (* y 8.13008))))\n             (-\n              0.15\n              (sqrt\n               (+\n                (pow (+ 1.65 (* y 8.13008)) 2)\n                (pow (- (* x 8.13008) 6.6385) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 1.65 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) 6.6385) 2)))\n             0.25))\n           (+ 1.65 (* y 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (+ 1.9 (* y 8.13008))) (+ 1.35 (* y 8.13008)))\n             (- (* x 8.13008) 6.1135))\n            (- 6.0135 (* x 8.13008)))\n           (-\n            (sqrt\n             (+\n              (pow (+ 1.2 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 6.0635) 2)))\n            0.075))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (+ 0.245 (* y 0.813008)))\n            (- (* x 4.47154) (+ (* y 1.82927) 3.15743)))\n           (- (+ (* y 2.64228) 3.34743) (* x 4.47154)))\n          (fmin\n           (fmax\n            (fmax\n             (+ 0.245 (* y 0.813008))\n             (- (* x 4.47154) (+ (* y 2.64228) 3.34743)))\n            (- (+ (* y 1.82927) 3.15743) (* x 4.47154)))\n           (fmax\n            (fmax\n             (- (* x 4.47154) (+ (* y 2.64228) 3.34743))\n             (+ 0.19 (* y 0.813008)))\n            (- (+ (* y 1.82927) 3.10243) (* x 4.47154)))))\n         (fmin\n          (fmax\n           (fmax\n            (- (+ (* y 2.64228) 3.34743) (* x 4.47154))\n            (- (* x 4.47154) (+ (* y 1.82927) 3.10243)))\n           (- (+ 0.19 (* y 0.813008))))\n          (fmin\n           (fmax\n            (fmax\n             (- (* x 4.47154) (+ (* y 1.82927) 3.15743))\n             (- (+ 0.19 (* y 0.813008))))\n            (- (+ (* y 2.64228) 3.29243) (* x 4.47154)))\n           (fmax\n            (fmax\n             (- (+ (* y 1.82927) 3.15743) (* x 4.47154))\n             (+ 0.19 (* y 0.813008)))\n            (- (* x 4.47154) (+ (* y 2.64228) 3.29243))))))))\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (+ (* y 1.82927) 3.10243) (* x 4.47154))\n            (- (* x 4.47154) (+ (* y 2.64228) 3.29243)))\n           (+ 0.135 (* y 0.813008)))\n          (fmax\n           (fmax\n            (- (* x 4.47154) (+ (* y 1.82927) 3.10243))\n            (- (+ (* y 2.64228) 3.29243) (* x 4.47154)))\n           (- (+ 0.135 (* y 0.813008)))))\n         (fmin\n          (fmax\n           (fmax\n            (- (+ 0.19 (* y 0.813008)))\n            (- 2.24743 (+ (* y 1.82927) (* x 4.47154))))\n           (- (+ (* y 2.64228) (* x 4.47154)) 2.11243))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (+ 7.12143 (* x 11.6144)) (- (+ 7.67143 (* x 11.6144))))\n               (-\n                0.45\n                (sqrt\n                 (+\n                  (pow (+ 3 (* y 8.13008)) 2)\n                  (pow (+ 8.90179 (* x 14.518)) 2)))))\n              (-\n               (sqrt\n                (+\n                 (pow (+ 3 (* y 8.13008)) 2)\n                 (pow (+ 7.12143 (* x 11.6144)) 2)))\n               0.55))\n             (- (+ 3 (* y 8.13008))))\n            (+ 2.45 (* y 8.13008)))\n           (fmax\n            (-\n             (sqrt\n              (+\n               (pow (+ 5.745 (* x 8.13008)) 2)\n               (pow (+ 2.725 (* y 8.13008)) 2)))\n             0.275)\n            (fmin\n             (fmax\n              (fmax\n               (fmax (+ 5.47 (* x 8.13008)) (- (+ 5.97 (* x 8.13008))))\n               (+ 2.685 (* y 8.13008)))\n              (- (+ 2.775 (* y 8.13008))))\n             (fmax\n              (fmax\n               (-\n                (sqrt\n                 (+\n                  (pow (+ 5.745 (* x 8.13008)) 2)\n                  (pow (+ 2.725 (* y 8.13008)) 2)))\n                0.275)\n               (-\n                (fmin\n                 (fmax\n                  (fmax\n                   (- (+ 1.0405 (* x 2.23577)) (* y 1.21951))\n                   (- (+ (+ (* x 2.23577) 2.9905) (* y 4.06504))))\n                  (+ 1.77125 (* y 5.28455)))\n                 (fmax\n                  (fmax\n                   (+ (+ (* x 2.23577) 2.9905) (* y 4.06504))\n                   (- (* y 1.21951) (+ 1.0405 (* x 2.23577))))\n                  (- (+ 1.77125 (* y 5.28455)))))))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (+ 5.745 (* x 8.13008)) 2)\n                 (pow (+ 2.725 (* y 8.13008)) 2))))))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (-\n             (fmin\n              (fmax\n               (fmax\n                (- (* y 2.23577) (+ 1.02163 (* x 2.27642)))\n                (+ 3.35775 (* x 4.5122)))\n               (- (+ (* (+ x y) 2.23577) 2.48875)))\n              (fmax\n               (fmax\n                (+ (* (+ x y) 2.23577) 2.48875)\n                (- (+ 3.35775 (* x 4.5122))))\n               (- (+ 1.02162 (* x 2.27642)) (* y 2.23577)))))\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (+ 6.325 (* x 8.13008)) 2)\n               (pow (+ 2.725 (* y 8.13008)) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 6.325 (* x 8.13008)) 2)\n              (pow (+ 2.725 (* y 8.13008)) 2)))\n            0.275))\n          (fmax\n           (fmax\n            (fmax (+ 0.9 (* y 8.13008)) (- (+ 1.65 (* y 8.13008))))\n            (- (* x 8.13008) 6.4885))\n           (- 6.3885 (* x 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (+ 1.9 (* y 8.13008))) (+ 0.9 (* y 8.13008)))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (+ 1.625 (* y 8.13008)) 2)\n                 (pow (- (* x 8.13008) 3.1805) 2)))))\n             (-\n              (sqrt\n               (+\n                (pow (+ 1.625 (* y 8.13008)) 2)\n                (pow (- (* x 8.13008) 3.1805) 2)))\n              0.275))\n            (- (* x 8.13008) 3.9055))\n           (- 3.1805 (* x 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax\n                (-\n                 (fmin\n                  (fmax\n                   (fmax\n                    (- (* x 2.84553) (+ (* y 0.813008) 0.880675))\n                    (- (+ (+ 0.590637 (* x 1.82927)) (* y 4.06504))))\n                   (- (+ 1.27381 (* y 4.87805)) (* x 1.01626)))\n                  (fmax\n                   (fmax\n                    (+ (+ 0.590637 (* x 1.82927)) (* y 4.06504))\n                    (- (* x 1.01626) (+ 1.27381 (* y 4.87805))))\n                   (- (+ (* y 0.813008) 0.880675) (* x 2.84553)))))\n                (+ 1.825 (* y 8.13008)))\n               (- (+ 2.05 (* y 8.13008))))\n              (- (* x 8.13008) 2.0805))\n             (- 1.9305 (* x 8.13008)))\n            (-\n             (sqrt\n              (+\n               (pow (+ 0.608333 (* y 2.71003)) 2)\n               (pow (- (* x 8.13008) 2.0055) 2)))\n             0.075))\n           (-\n            (sqrt\n             (+\n              (pow (+ 1.825 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 2.0305) 2)))\n            0.075)))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 1.9 (* y 8.13008))) (+ 1.15 (* y 8.13008)))\n            (- (* x 8.13008) 1.6805))\n           (- 1.5805 (* x 8.13008)))\n          (fmax\n           (fmax\n            (fmax (+ 1.35 (* y 8.13008)) (- (* x 8.13008) 1.8305))\n            (- 1.4305 (* x 8.13008)))\n           (- (+ 1.45 (* y 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (+ 0.9 (* y 8.13008)) (- (* x 8.13008) 1.8305))\n              (- 1.4305 (* x 8.13008)))\n             (- (+ 1.15 (* y 8.13008))))\n            (-\n             0.15\n             (sqrt\n              (+\n               (pow (+ 1.15 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) 1.8305) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 1.15 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 1.8305) 2)))\n            0.25))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (+ 1.9 (* y 8.13008))) (+ 1.15 (* y 8.13008)))\n             (- (* x 8.13008) 1.1805))\n            (- 1.0805 (* x 8.13008)))\n           (fmax\n            (fmax\n             (+ 0.19 (* y 0.813008))\n             (- 2.11243 (+ (* y 2.64228) (* x 4.47154))))\n            (- (+ (* y 1.82927) (* x 4.47154)) 2.24743)))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (+ 0.135 (* y 0.813008))\n            (- 2.11243 (+ (* y 2.64228) (* x 4.47154))))\n           (- (+ (* y 1.82927) (* x 4.47154)) 2.30243))\n          (fmin\n           (fmax\n            (fmax\n             (- (+ 0.135 (* y 0.813008)))\n             (- (+ (* y 2.64228) (* x 4.47154)) 2.11243))\n            (- 2.30243 (+ (* y 1.82927) (* x 4.47154))))\n           (fmax\n            (fmax\n             (fmax (- (+ 1.9 (* y 8.13008))) (+ 1.35 (* y 8.13008)))\n             (- (* x 8.13008) 4.2805))\n            (- 4.1805 (* x 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (+ 1.9 (* y 8.13008))) (+ 1.35 (* y 8.13008)))\n              (- (* x 11.6144) 6.52214))\n             (- 5.97215 (* x 11.6144)))\n            (-\n             0.45\n             (sqrt\n              (+\n               (pow (+ 1.9 (* y 8.13008)) 2)\n               (pow (- (* x 14.518) 8.15268) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 1.9 (* y 8.13008)) 2)\n              (pow (- (* x 11.6144) 6.52214) 2)))\n            0.55))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (+ 1.9 (* y 8.13008))) (+ 1.35 (* y 8.13008)))\n             (- (* x 8.13008) 4.0805))\n            (- 3.9805 (* x 8.13008)))\n           (fmax\n            (fmax\n             (fmax (+ 1.35 (* y 8.13008)) (- (+ 1.625 (* y 8.13008))))\n             (- (* x 8.13008) 3.6305))\n            (- 3.5305 (* x 8.13008)))))))))))\n   (fmin\n    (fmin\n     (fmin\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (+ 1.9 (* y 8.13008))) (- (* x 8.13008) 4.0805))\n              (- 3.5305 (* x 8.13008)))\n             (+ 1.625 (* y 8.13008)))\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (+ 1.625 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) 3.8055) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 1.625 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 3.8055) 2)))\n            0.275))\n          (fmax\n           (fmax\n            (fmax (- (+ 1.9 (* y 8.13008))) (+ 0.9 (* y 8.13008)))\n            (- (* x 8.13008) 3.0055))\n           (- 2.9055 (* x 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 1.35 (* y 8.13008)) (- (+ 1.45 (* y 8.13008))))\n            (- (* x 8.13008) 3.1805))\n           (- 3.0055 (* x 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (+ 1.9 (* y 8.13008))) (- (* x 8.13008) 3.1805))\n             (- 3.0055 (* x 8.13008)))\n            (+ 1.8 (* y 8.13008)))\n           (fmax\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (+ 3.825 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) (+ (* y 2.32288) 5.57243)) 2))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 3.825 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) (+ (* y 2.32288) 5.57243)) 2)))\n             0.275)))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 4.1 (* y 8.13008))) (+ 3.825 (* y 8.13008)))\n            (- (* x 8.13008) 4.051))\n           (- 3.951 (* x 8.13008)))\n          (fmax\n           (fmax\n            (fmax (+ 3.1 (* y 8.13008)) (- (+ 4.1 (* y 8.13008))))\n            (- (* x 8.13008) 3.601))\n           (- 3.501 (* x 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (+ 3.55 (* y 8.13008)) (- (* x 8.13008) 4.051))\n              (- 3.501 (* x 8.13008)))\n             (- (+ 3.825 (* y 8.13008))))\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (+ 3.825 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) 3.776) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 3.825 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 3.776) 2)))\n            0.275))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (+ 3.1 (* y 8.13008)) (- (+ 3.85 (* y 8.13008))))\n             (- (* x 8.13008) 3.251))\n            (- 3.151 (* x 8.13008)))\n           (fmax\n            (fmax\n             (fmax (+ 3.45 (* y 8.13008)) (- (+ 3.55 (* y 8.13008))))\n             (- (* x 8.13008) 3.401))\n            (- 3.001 (* x 8.13008)))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (+ 4.1 (* y 8.13008))) (+ 3.85 (* y 8.13008)))\n              (- (* x 8.13008) 3.401))\n             (- 3.001 (* x 8.13008)))\n            (-\n             0.15\n             (sqrt\n              (+\n               (pow (+ 3.85 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) 3.401) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 3.85 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 3.401) 2)))\n            0.25))\n          (fmax\n           (fmax\n            (fmax (- (+ 4.1 (* y 8.13008))) (+ 3.55 (* y 8.13008)))\n            (- (* x 8.13008) 1.943))\n           (- 1.843 (* x 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (+ 4.1 (* y 8.13008))) (+ 3.55 (* y 8.13008)))\n              (- (* x 11.6144) 3.18286))\n             (- 2.63286 (* x 11.6144)))\n            (-\n             0.45\n             (sqrt\n              (+\n               (pow (+ 4.1 (* y 8.13008)) 2)\n               (pow (- (* x 14.518) 3.97857) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 4.1 (* y 8.13008)) 2)\n              (pow (- (* x 11.6144) 3.18286) 2)))\n            0.55))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (+ 4.1 (* y 8.13008))) (+ 3.55 (* y 8.13008)))\n             (- (* x 8.13008) 6.981))\n            (- 6.881 (* x 8.13008)))\n           (-\n            (sqrt\n             (+ (pow (+ 3.4 (* y 8.13008)) 2) (pow (- (* x 8.13008) 6.931) 2)))\n            0.075))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 3.1 (* y 8.13008)) (- (+ 4.1 (* y 8.13008))))\n            (- 6.656 (* x 8.13008)))\n           (- (* x 8.13008) 6.756))\n          (fmax\n           (fmax\n            (fmax (+ 3.55 (* y 8.13008)) (- (+ 3.65 (* y 8.13008))))\n            (- 6.48101 (* x 8.13008)))\n           (- (* x 8.13008) 6.656)))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 4.1 (* y 8.13008))) (+ 4 (* y 8.13008)))\n            (- 6.48101 (* x 8.13008)))\n           (- (* x 8.13008) 6.656))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (+ 3.1 (* y 8.13008)) (- (+ 4.1 (* y 8.13008))))\n               (- 5.756 (* x 8.13008)))\n              (- (* x 8.13008) 6.481))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (+ 3.825 (* y 8.13008)) 2)\n                (pow (- 6.48101 (* x 8.13008)) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 3.825 (* y 8.13008)) 2)\n               (pow (- 6.48101 (* x 8.13008)) 2)))\n             0.275))\n           (fmax\n            (fmax\n             (fmax (- (+ 4.1 (* y 8.13008))) (+ 3.775 (* y 8.13008)))\n             (- (* x 8.13008) 5.431))\n            (- 5.331 (* x 8.13008))))))))\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 4.1 (* y 8.13008))) (+ 3.55 (* y 8.13008)))\n            (- (* x 8.13008) 4.981))\n           (- 4.881 (* x 8.13008)))\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (+ 3.55 (* y 8.13008)) (- (* x 8.13008) 5.431))\n              (- 4.881 (* x 8.13008)))\n             (- (+ 3.775 (* y 8.13008))))\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (+ 3.825 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) 5.156) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 3.825 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 5.156) 2)))\n            0.275)))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 4.1 (* y 8.13008))) (+ 3.75 (* y 8.13008)))\n            (- (* x 8.13008) 4.761))\n           (- 4.661 (* x 8.13008)))\n          (fmin\n           (fmax\n            (fmin\n             (fmax\n              (fmax\n               (-\n                0.175\n                (sqrt\n                 (+\n                  (pow (+ 3.825 (* y 8.13008)) 2)\n                  (pow (- (* x 8.13008) 0.167999) 2))))\n               (-\n                (sqrt\n                 (+\n                  (pow (+ 3.825 (* y 8.13008)) 2)\n                  (pow (- (* x 8.13008) 0.167999) 2)))\n                0.275))\n              (-\n               (fmin\n                (fmax\n                 (fmax\n                  (+ 2.48625 (* y 5.28455))\n                  (- (* x 2.23577) (+ 0.750575 (* y 1.21951))))\n                 (- (+ (+ 1.91443 (* x 2.23577)) (* y 4.06504))))\n                (fmax\n                 (fmax\n                  (- (+ 2.48625 (* y 5.28455)))\n                  (+ (+ 1.91443 (* x 2.23577)) (* y 4.06504)))\n                 (- (+ 0.750575 (* y 1.21951)) (* x 2.23577))))))\n             (fmax\n              (fmax\n               (fmax (+ 3.785 (* y 8.13008)) (- (+ 3.875 (* y 8.13008))))\n               (- (* x 8.13008) 0.443))\n              (- (+ 0.0570004 (* x 8.13008)))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 3.825 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) 0.167999) 2)))\n             0.275))\n           (fmax\n            (-\n             (sqrt\n              (+\n               (pow (+ 3.825 (* y 8.13008)) 2)\n               (pow (+ 0.482 (* x 8.13008)) 2)))\n             0.275)\n            (fmin\n             (fmax\n              (fmax\n               (fmax (+ 0.207 (* x 8.13008)) (- (+ 0.707 (* x 8.13008))))\n               (+ 3.785 (* y 8.13008)))\n              (- (+ 3.875 (* y 8.13008))))\n             (fmax\n              (fmax\n               (-\n                (sqrt\n                 (+\n                  (pow (+ 3.825 (* y 8.13008)) 2)\n                  (pow (+ 0.482 (* x 8.13008)) 2)))\n                0.275)\n               (-\n                (fmin\n                 (fmax\n                  (fmax\n                   (- (* x 2.23577) (+ 0.571825 (* y 1.21951)))\n                   (- (+ (+ 2.09318 (* x 2.23577)) (* y 4.06504))))\n                  (+ 2.48625 (* y 5.28455)))\n                 (fmax\n                  (fmax\n                   (+ (+ 2.09318 (* x 2.23577)) (* y 4.06504))\n                   (- (+ 0.571825 (* y 1.21951)) (* x 2.23577)))\n                  (- (+ 2.48625 (* y 5.28455)))))))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (+ 3.825 (* y 8.13008)) 2)\n                 (pow (+ 0.482 (* x 8.13008)) 2))))))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 3.1 (* y 8.13008)) (- (+ 4.1 (* y 8.13008))))\n            (- (+ 0.957 (* x 8.13008))))\n           (+ 0.857 (* x 8.13008)))\n          (fmax\n           (fmax\n            (fmax (+ 3.55 (* y 8.13008)) (- (+ 3.65 (* y 8.13008))))\n            (- (+ 1.132 (* x 8.13008))))\n           (+ 0.957 (* x 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 4.1 (* y 8.13008))) (+ 4 (* y 8.13008)))\n            (- (+ 1.132 (* x 8.13008))))\n           (+ 0.957 (* x 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (+ 3.1 (* y 8.13008)) (- (+ 4.1 (* y 8.13008))))\n               (- (+ 1.857 (* x 8.13008))))\n              (+ 1.132 (* x 8.13008)))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (+ 3.825 (* y 8.13008)) 2)\n                (pow (- (+ 1.132 (* x 8.13008))) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 3.825 (* y 8.13008)) 2)\n               (pow (- (+ 1.132 (* x 8.13008))) 2)))\n             0.275))\n           (fmax\n            (fmax\n             (fmax (+ 3.1 (* y 8.13008)) (- (+ 4.1 (* y 8.13008))))\n             (- (+ 2.282 (* x 8.13008))))\n            (+ 2.182 (* x 8.13008)))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 3.55 (* y 8.13008)) (- (+ 3.65 (* y 8.13008))))\n            (+ 2.282 (* x 8.13008)))\n           (- (+ 2.457 (* x 8.13008))))\n          (fmax\n           (fmax\n            (fmax (- (+ 4.1 (* y 8.13008))) (+ 4 (* y 8.13008)))\n            (+ 2.282 (* x 8.13008)))\n           (- (+ 2.457 (* x 8.13008)))))\n         (fmin\n          (fmax\n           (-\n            (sqrt\n             (+\n              (pow (+ 3.825 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 1.468) 2)))\n            0.275)\n           (fmin\n            (fmax\n             (fmax\n              (fmax (+ 3.785 (* y 8.13008)) (- (+ 3.875 (* y 8.13008))))\n              (- (* x 8.13008) 1.743))\n             (- 1.243 (* x 8.13008)))\n            (fmax\n             (fmax\n              (-\n               (sqrt\n                (+\n                 (pow (+ 3.825 (* y 8.13008)) 2)\n                 (pow (- (* x 8.13008) 1.468) 2)))\n               0.275)\n              (-\n               (fmin\n                (fmax\n                 (fmax\n                  (+ 2.48625 (* y 5.28455))\n                  (- (* x 2.23577) (+ 1.10808 (* y 1.21951))))\n                 (- (+ (+ 1.55693 (* x 2.23577)) (* y 4.06504))))\n                (fmax\n                 (fmax\n                  (+ (+ 1.55693 (* x 2.23577)) (* y 4.06504))\n                  (- (+ 1.10808 (* y 1.21951)) (* x 2.23577)))\n                 (- (+ 2.48625 (* y 5.28455)))))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (+ 3.825 (* y 8.13008)) 2)\n                (pow (- (* x 8.13008) 1.468) 2)))))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (+ 3.55 (* y 8.13008)) (- (+ 4.475 (* y 8.13008))))\n             (- (* x 8.13008) 0.643001))\n            (- 0.543 (* x 8.13008)))\n           (fmax\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (+ 3.825 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) 0.818) 2))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 3.825 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) 0.818) 2)))\n             0.275)))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (-\n                (sqrt\n                 (+\n                  (pow (+ 4.937 (* x 8.13008)) 2)\n                  (pow (+ 1.34167 (* y 2.71003)) 2)))\n                0.075)\n               (-\n                (fmin\n                 (fmax\n                  (fmax\n                   (- (+ 1.3292 (* x 2.84553)) (* y 0.813008))\n                   (- (+ (+ (* x 1.82927) 3.2527) (* y 4.06504))))\n                  (- (+ 1.726 (* y 4.87805)) (* x 1.01626)))\n                 (fmax\n                  (fmax\n                   (- (* x 1.01626) (+ 1.726 (* y 4.87805)))\n                   (+ (+ (* x 1.82927) 3.2527) (* y 4.06504)))\n                  (- (* y 0.813008) (+ 1.3292 (* x 2.84553)))))))\n              (+ 4.025 (* y 8.13008)))\n             (- (+ 4.25 (* y 8.13008))))\n            (+ 4.862 (* x 8.13008)))\n           (- (+ 5.012 (* x 8.13008))))\n          (fmin\n           (-\n            (sqrt\n             (+\n              (pow (+ 4.025 (* y 8.13008)) 2)\n              (pow (+ 4.912 (* x 8.13008)) 2)))\n            0.075)\n           (fmax\n            (fmax\n             (fmax (- (+ 4.1 (* y 8.13008))) (+ 3.825 (* y 8.13008)))\n             (+ 5.162 (* x 8.13008)))\n            (- (+ 5.262 (* x 8.13008))))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 3.1 (* y 8.13008)) (- (+ 4.1 (* y 8.13008))))\n            (+ 5.612 (* x 8.13008)))\n           (- (+ 5.712 (* x 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (+ 3.55 (* y 8.13008)) (- (+ 3.825 (* y 8.13008))))\n               (+ 5.162 (* x 8.13008)))\n              (- (+ 5.712 (* x 8.13008))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (+ 3.825 (* y 8.13008)) 2)\n                (pow (+ 5.437 (* x 8.13008)) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 3.825 (* y 8.13008)) 2)\n               (pow (+ 5.437 (* x 8.13008)) 2)))\n             0.275))\n           (fmax\n            (fmax\n             (fmax (+ 3.1 (* y 8.13008)) (- (+ 3.85 (* y 8.13008))))\n             (+ 5.962 (* x 8.13008)))\n            (- (+ 6.062 (* x 8.13008))))))))))\n     (fmin\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 3.45 (* y 8.13008)) (- (+ 3.55 (* y 8.13008))))\n            (+ 5.812 (* x 8.13008)))\n           (- (+ 6.212 (* x 8.13008))))\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (+ 4.1 (* y 8.13008))) (+ 3.85 (* y 8.13008)))\n              (+ 5.812 (* x 8.13008)))\n             (- (+ 6.212 (* x 8.13008))))\n            (-\n             0.15\n             (sqrt\n              (+\n               (pow (+ 3.85 (* y 8.13008)) 2)\n               (pow (+ 5.812 (* x 8.13008)) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 3.85 (* y 8.13008)) 2)\n              (pow (+ 5.812 (* x 8.13008)) 2)))\n            0.25)))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 4.1 (* y 8.13008))) (+ 3.55 (* y 8.13008)))\n            (+ 6.57 (* x 8.13008)))\n           (- (+ 6.67 (* x 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (+ 3.1 (* y 8.13008)) (- (+ 4.1 (* y 8.13008))))\n               (+ 2.457 (* x 8.13008)))\n              (- (+ 3.182 (* x 8.13008))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (+ 3.825 (* y 8.13008)) 2)\n                (pow (- (+ 2.457 (* x 8.13008))) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 3.825 (* y 8.13008)) 2)\n               (pow (- (+ 2.457 (* x 8.13008))) 2)))\n             0.275))\n           (fmax\n            (fmax\n             (fmax (- (+ 4.1 (* y 8.13008))) (+ 3.775 (* y 8.13008)))\n             (+ 2.807 (* x 8.13008)))\n            (- (+ 2.907 (* x 8.13008)))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 4.1 (* y 8.13008))) (+ 3.55 (* y 8.13008)))\n            (+ 3.257 (* x 8.13008)))\n           (- (+ 3.357 (* x 8.13008))))\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (+ 3.55 (* y 8.13008)) (- (+ 3.775 (* y 8.13008))))\n              (+ 2.807 (* x 8.13008)))\n             (- (+ 3.357 (* x 8.13008))))\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (+ 3.825 (* y 8.13008)) 2)\n               (pow (+ 3.082 (* x 8.13008)) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 3.825 (* y 8.13008)) 2)\n              (pow (+ 3.082 (* x 8.13008)) 2)))\n            0.275)))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 4.1 (* y 8.13008))) (+ 3.75 (* y 8.13008)))\n            (+ 3.477 (* x 8.13008)))\n           (- (+ 3.577 (* x 8.13008))))\n          (fmin\n           (fmax\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (+ 3.825 (* y 8.13008)) 2)\n               (pow (- (+ 2.66557 (* x 8.13008)) (* y 2.32288)) 2))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 3.825 (* y 8.13008)) 2)\n               (pow (- (+ 2.66557 (* x 8.13008)) (* y 2.32288)) 2)))\n             0.275))\n           (fmax\n            (fmin\n             (fmax\n              (fmax\n               (-\n                (sqrt\n                 (+\n                  (pow (+ 2.725 (* y 8.13008)) 2)\n                  (pow (- (* x 8.13008) 5.9605) 2)))\n                0.275)\n               (-\n                (fmin\n                 (fmax\n                  (fmax\n                   (+ 1.77125 (* y 5.28455))\n                   (- (* x 2.23577) (+ (* y 1.21951) 2.17851)))\n                  (- 0.228514 (+ (* x 2.23577) (* y 4.06504))))\n                 (fmax\n                  (fmax\n                   (- (+ (* x 2.23577) (* y 4.06504)) 0.228514)\n                   (- (+ (* y 1.21951) 2.17851) (* x 2.23577)))\n                  (- (+ 1.77125 (* y 5.28455)))))))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (+ 2.725 (* y 8.13008)) 2)\n                 (pow (- (* x 8.13008) 5.9605) 2)))))\n             (fmax\n              (fmax\n               (fmax (+ 2.685 (* y 8.13008)) (- (+ 2.775 (* y 8.13008))))\n               (- (* x 8.13008) 6.23551))\n              (- 5.73551 (* x 8.13008))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 2.725 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) 5.9605) 2)))\n             0.275))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 3 (* y 8.13008))) (- (* x 8.13008) 5.5355))\n            (- 5.4355 (* x 8.13008)))\n           (+ 2.725 (* y 8.13008)))\n          (fmax\n           (fmax\n            (fmax (- (+ 3 (* y 8.13008))) (+ 2 (* y 8.13008)))\n            (- (* x 8.13008) 5.0855))\n           (- 4.9855 (* x 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (* x 8.13008) 5.5355) (- 4.9855 (* x 8.13008)))\n              (+ 2.45 (* y 8.13008)))\n             (- (+ 2.725 (* y 8.13008))))\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (- (* x 8.13008) 5.2605) 2)\n               (pow (+ 2.725 (* y 8.13008)) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* x 8.13008) 5.2605) 2)\n              (pow (+ 2.725 (* y 8.13008)) 2)))\n            0.275))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (+ 2 (* y 8.13008)) (- (+ 2.75 (* y 8.13008))))\n             (- (* x 8.13008) 4.7355))\n            (- 4.6355 (* x 8.13008)))\n           (fmax\n            (fmax\n             (fmax (+ 2.35 (* y 8.13008)) (- (+ 2.45 (* y 8.13008))))\n             (- (* x 8.13008) 4.8855))\n            (- 4.4855 (* x 8.13008))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (+ 3 (* y 8.13008))) (+ 2.75 (* y 8.13008)))\n              (- (* x 8.13008) 4.8855))\n             (- 4.4855 (* x 8.13008)))\n            (-\n             0.15\n             (sqrt\n              (+\n               (pow (+ 2.75 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) 4.8855) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 2.75 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 4.8855) 2)))\n            0.25))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (+ 3 (* y 8.13008))) (+ 2.675 (* y 8.13008)))\n             (- (* x 8.13008) 3.6855))\n            (- 3.5855 (* x 8.13008)))\n           (fmax\n            (fmax\n             (fmax (- (+ 3 (* y 8.13008))) (+ 2.45 (* y 8.13008)))\n             (- (* x 8.13008) 3.2355))\n            (- 3.1355 (* x 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (+ 4.1 (* y 8.13008))) (+ 3.55 (* y 8.13008)))\n              (+ 8.97857 (* x 11.6144)))\n             (- (+ 9.52857 (* x 11.6144))))\n            (-\n             0.45\n             (sqrt\n              (+\n               (pow (+ 4.1 (* y 8.13008)) 2)\n               (pow (+ 11.2232 (* x 14.518)) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 4.1 (* y 8.13008)) 2)\n              (pow (+ 8.97857 (* x 11.6144)) 2)))\n            0.55))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (+ 4.1 (* y 8.13008))) (+ 3.75 (* y 8.13008)))\n             (+ 6.79 (* x 8.13008)))\n            (- (+ 6.89 (* x 8.13008))))\n           (fmax\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (+ 3.825 (* y 8.13008)) 2)\n               (pow (- (+ 5.97857 (* x 8.13008)) (* y 2.32288)) 2))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 3.825 (* y 8.13008)) 2)\n               (pow (- (+ 5.97857 (* x 8.13008)) (* y 2.32288)) 2)))\n             0.275)))))))\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (-\n            (sqrt\n             (+\n              (pow (+ 3.825 (* y 8.13008)) 2)\n              (pow (+ 7.725 (* x 8.13008)) 2)))\n            0.275)\n           (fmin\n            (fmax\n             (fmax\n              (fmax (+ 3.785 (* y 8.13008)) (- (+ 3.875 (* y 8.13008))))\n              (+ 7.45 (* x 8.13008)))\n             (- (+ 7.95 (* x 8.13008))))\n            (fmax\n             (fmax\n              (-\n               (sqrt\n                (+\n                 (pow (+ 3.825 (* y 8.13008)) 2)\n                 (pow (+ 7.725 (* x 8.13008)) 2)))\n               0.275)\n              (-\n               (fmin\n                (fmax\n                 (fmax\n                  (+ 2.48625 (* y 5.28455))\n                  (- (+ 1.42 (* x 2.23577)) (* y 1.21951)))\n                 (- (+ (+ (* x 2.23577) (* y 4.06504)) 4.085)))\n                (fmax\n                 (fmax\n                  (- (+ 2.48625 (* y 5.28455)))\n                  (+ (+ (* x 2.23577) (* y 4.06504)) 4.085))\n                 (- (* y 1.21951) (+ 1.42 (* x 2.23577)))))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (+ 3.825 (* y 8.13008)) 2)\n                (pow (+ 7.725 (* x 8.13008)) 2)))))))\n          (fmax\n           (fmax\n            (- (* y 1.82927) (+ 1.44223 (* x 4.47154)))\n            (- (+ 1.30723 (* x 4.47154)) (* y 2.64228)))\n           (+ 0.08 (* y 0.813008))))\n         (fmin\n          (fmax\n           (fmax\n            (- (+ 1.44223 (* x 4.47154)) (* y 1.82927))\n            (- (+ 0.08 (* y 0.813008))))\n           (- (* y 2.64228) (+ 1.30723 (* x 4.47154))))\n          (fmin\n           (fmax\n            (fmax\n             (- (+ 0.08 (* y 0.813008)))\n             (- (* y 2.64228) (+ 1.36223 (* x 4.47154))))\n            (- (+ 1.38723 (* x 4.47154)) (* y 1.82927)))\n           (fmax\n            (fmax\n             (+ 0.08 (* y 0.813008))\n             (- (+ 1.36223 (* x 4.47154)) (* y 2.64228)))\n            (- (* y 1.82927) (+ 1.38723 (* x 4.47154)))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (* y 1.82927) (+ 1.44223 (* x 4.47154)))\n            (- (+ 1.36223 (* x 4.47154)) (* y 2.64228)))\n           (+ 0.025 (* y 0.813008)))\n          (fmax\n           (fmax\n            (- (+ 1.44223 (* x 4.47154)) (* y 1.82927))\n            (- (* y 2.64228) (+ 1.36223 (* x 4.47154))))\n           (- (+ 0.025 (* y 0.813008)))))\n         (fmin\n          (fmax\n           (fmax\n            (- (+ 0.08 (* y 0.813008)))\n            (- (+ (+ 1.80223 (* y 1.82927)) (* x 4.47154))))\n           (+ (+ 1.82723 (* y 2.64228)) (* x 4.47154)))\n          (fmin\n           (fmax\n            (fmax\n             (+ 0.08 (* y 0.813008))\n             (+ (+ 1.80223 (* y 1.82927)) (* x 4.47154)))\n            (- (+ (+ 1.82723 (* y 2.64228)) (* x 4.47154))))\n           (fmax\n            (fmax\n             (+ 0.025 (* y 0.813008))\n             (- (+ (+ 1.82723 (* y 2.64228)) (* x 4.47154))))\n            (+ (+ 1.74723 (* y 1.82927)) (* x 4.47154)))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (+ 0.025 (* y 0.813008)))\n            (+ (+ 1.82723 (* y 2.64228)) (* x 4.47154)))\n           (- (+ (+ 1.74723 (* y 1.82927)) (* x 4.47154))))\n          (fmax\n           (fmax\n            (fmax (+ 3.5325 (* x 8.13008)) (- (+ 3.6325 (* x 8.13008))))\n            (+ 0.25 (* y 8.13008)))\n           (- (+ 0.8 (* y 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (+ 4.63929 (* x 11.6144)) (- (+ 5.18929 (* x 11.6144))))\n              (-\n               0.45\n               (sqrt\n                (+\n                 (pow (+ 5.79911 (* x 14.518)) 2)\n                 (pow (+ 0.8 (* y 8.13008)) 2)))))\n             (-\n              (sqrt\n               (+\n                (pow (+ 4.63929 (* x 11.6144)) 2)\n                (pow (+ 0.8 (* y 8.13008)) 2)))\n              0.55))\n            (+ 0.25 (* y 8.13008)))\n           (- (+ 0.8 (* y 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (+ 3.7575 (* x 8.13008)) (- (+ 3.8575 (* x 8.13008))))\n             (+ 0.25 (* y 8.13008)))\n            (- (+ 0.8 (* y 8.13008))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 3.8075 (* x 8.13008)) 2)\n              (pow (+ 0.0999999 (* y 8.13008)) 2)))\n            0.075))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 4.0025 (* x 8.13008)) (- (+ 4.1025 (* x 8.13008))))\n            (- (+ 0.8 (* y 8.13008))))\n           (+ 0.45 (* y 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (* x 8.13008) 0.0154991) (- (+ 0.084501 (* x 8.13008))))\n             (- (+ 0.8 (* y 8.13008))))\n            (+ 0.45 (* y 8.13008)))\n           (fmax\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (- (+ 0.11593 (* x 8.13008)) (* y 2.32288)) 2)\n               (pow (+ 0.525 (* y 8.13008)) 2))))\n            (-\n             (sqrt\n              (+\n               (pow (- (+ 0.11593 (* x 8.13008)) (* y 2.32288)) 2)\n               (pow (+ 0.525 (* y 8.13008)) 2)))\n             0.275))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 0.6945 (* x 8.13008)) (- (+ 0.794501 (* x 8.13008))))\n            (+ 0.525 (* y 8.13008)))\n           (- (+ 0.8 (* y 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (+ 1.1445 (* x 8.13008)) (- (+ 1.2445 (* x 8.13008))))\n             (- (* y 8.13008) 0.2))\n            (- (+ 0.8 (* y 8.13008))))\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (+ 0.6945 (* x 8.13008)) (- (+ 1.2445 (* x 8.13008))))\n               (- (+ 0.525 (* y 8.13008))))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (+ 0.969501 (* x 8.13008)) 2)\n                 (pow (+ 0.525 (* y 8.13008)) 2)))))\n             (-\n              (sqrt\n               (+\n                (pow (+ 0.969501 (* x 8.13008)) 2)\n                (pow (+ 0.525 (* y 8.13008)) 2)))\n              0.275))\n            (+ 0.25 (* y 8.13008))))))))))\n    (fmin\n     (fmin\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (-\n             (fmin\n              (fmax\n               (fmax\n                (- (* y 2.23577) (+ 0.289485 (* x 2.27642)))\n                (+ 0.707348 (* x 4.5122)))\n               (- (+ 0.570488 (* (+ x y) 2.23577))))\n              (fmax\n               (fmax\n                (+ 0.570488 (* (+ x y) 2.23577))\n                (- (+ 0.707348 (* x 4.5122))))\n               (- (+ 0.289485 (* x 2.27642)) (* y 2.23577)))))\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (+ 1.5495 (* x 8.13008)) 2)\n               (pow (+ 0.525 (* y 8.13008)) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 1.5495 (* x 8.13008)) 2)\n              (pow (+ 0.525 (* y 8.13008)) 2)))\n            0.275))\n          (fmax\n           (fmax\n            (- (+ 0.135 (* y 0.813008)))\n            (- (+ 1.38723 (* x 4.47154)) (* y 1.82927)))\n           (- (* y 2.64228) (+ 1.30723 (* x 4.47154)))))\n         (fmin\n          (fmax\n           (fmax\n            (+ 0.135 (* y 0.813008))\n            (- (+ 1.30723 (* x 4.47154)) (* y 2.64228)))\n           (- (* y 1.82927) (+ 1.38723 (* x 4.47154))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- (+ 0.525 (* y 8.13008))) (+ 6.25 (* x 8.13008)))\n               (- (+ 6.8 (* x 8.13008))))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (+ 6.525 (* x 8.13008)) 2)\n                 (pow (+ 0.525 (* y 8.13008)) 2)))))\n             (-\n              (sqrt\n               (+\n                (pow (+ 6.525 (* x 8.13008)) 2)\n                (pow (+ 0.525 (* y 8.13008)) 2)))\n              0.275))\n            (+ 0.25 (* y 8.13008)))\n           (fmax\n            (fmax\n             (fmax (- (+ 0.55 (* y 8.13008))) (+ 7.05 (* x 8.13008)))\n             (- (+ 7.15 (* x 8.13008))))\n            (- (* y 8.13008) 0.2)))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 6.9 (* x 8.13008)) (- (+ 7.3 (* x 8.13008))))\n            (- (+ 0.25 (* y 8.13008))))\n           (+ 0.15 (* y 8.13008)))\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (+ 0.55 (* y 8.13008)) (+ 6.9 (* x 8.13008)))\n              (- (+ 7.3 (* x 8.13008))))\n             (-\n              0.15\n              (sqrt\n               (+\n                (pow (+ 0.55 (* y 8.13008)) 2)\n                (pow (+ 6.9 (* x 8.13008)) 2)))))\n            (-\n             (sqrt\n              (+ (pow (+ 0.55 (* y 8.13008)) 2) (pow (+ 6.9 (* x 8.13008)) 2)))\n             0.25))\n           (- (+ 0.8 (* y 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 1.3) (- 0.55 (* y 8.13008)))\n            (- (* x 8.13008) 7.72551))\n           (- 7.62551 (* x 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (* y 8.13008) 0.95) (- 0.85 (* y 8.13008)))\n             (- (* x 8.13008) 7.87551))\n            (- 7.47551 (* x 8.13008)))\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- (* x 8.13008) 7.87551) (- 7.47551 (* x 8.13008)))\n               (- (* y 8.13008) 0.55))\n              (- 0.3 (* y 8.13008)))\n             (-\n              0.15\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 0.55) 2)\n                (pow (- (* x 8.13008) 7.87551) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 0.55) 2)\n               (pow (- (* x 8.13008) 7.87551) 2)))\n             0.25))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 0.3 (* y 8.13008)) (- (* y 8.13008) 0.65))\n            (- (* x 8.13008) 7.35551))\n           (- 7.25551 (* x 8.13008)))\n          (fmax\n           (-\n            0.175\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 0.575) 2)\n              (pow (- (* x 8.13008) (+ (* y 2.32288) 6.90979)) 2))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 0.575) 2)\n              (pow (- (* x 8.13008) (+ (* y 2.32288) 6.90979)) 2)))\n            0.275)))\n         (fmin\n          (fmax\n           (-\n            0.175\n            (sqrt\n             (+\n              (pow (- (+ 4.13393 (* x 8.13008)) (* y 2.32288)) 2)\n              (pow (+ 0.525 (* y 8.13008)) 2))))\n           (-\n            (sqrt\n             (+\n              (pow (- (+ 4.13393 (* x 8.13008)) (* y 2.32288)) 2)\n              (pow (+ 0.525 (* y 8.13008)) 2)))\n            0.275))\n          (fmin\n           (fmax\n            (-\n             (fmin\n              (fmax\n               (fmax\n                (fmax (- (+ 3.7375 (* x 5.42005))) (+ 3.575 (* x 5.42005)))\n                (- (+ 0.575 (* y 8.13008))))\n               (+ 0.4125 (* y 8.13008)))\n              (-\n               (sqrt\n                (+\n                 (pow (- (+ 2.49333 (* x 3.61337))) 2)\n                 (pow (- (+ 0.415 (* y 8.13008))) 2)))\n               0.0625)))\n            (-\n             (sqrt\n              (+\n               (pow (- (+ 3.7375 (* x 5.42005))) 2)\n               (pow (- (+ 0.4125 (* y 8.13008))) 2)))\n             0.1625))\n           (fmax\n            (-\n             (fmin\n              (fmax\n               (fmax\n                (fmax (+ 3.7375 (* x 5.42005)) (- (+ 3.9 (* x 5.42005))))\n                (+ 0.475 (* y 8.13008)))\n               (- (+ 0.6375 (* y 8.13008))))\n              (-\n               (sqrt\n                (+\n                 (pow (+ 2.49 (* x 3.61337)) 2)\n                 (pow (+ 0.635 (* y 8.13008)) 2)))\n               0.0625)))\n            (-\n             (sqrt\n              (+\n               (pow (+ 3.7375 (* x 5.42005)) 2)\n               (pow (+ 0.6375 (* y 8.13008)) 2)))\n             0.1625)))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 6.075 (* x 8.13008))) (+ 5.975 (* x 8.13008)))\n            (+ 0.25 (* y 8.13008)))\n           (- (+ 0.8 (* y 8.13008))))\n          (fmin\n           (-\n            (sqrt\n             (+\n              (pow (+ 6.025 (* x 8.13008)) 2)\n              (pow (+ 0.0999999 (* y 8.13008)) 2)))\n            0.075)\n           (fmax\n            (fmax\n             (fmax (+ 6.25 (* x 8.13008)) (- (+ 6.35 (* x 8.13008))))\n             (+ 0.525 (* y 8.13008)))\n            (- (+ 0.8 (* y 8.13008))))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 6.7 (* x 8.13008)) (- (+ 6.8 (* x 8.13008))))\n            (- (* y 8.13008) 0.2))\n           (- (+ 0.8 (* y 8.13008))))\n          (fmin\n           (fmax\n            (-\n             (fmin\n              (-\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 0.465) 2)\n                 (pow (- (* x 3.61337) 2.02467) 2)))\n               0.0625)\n              (fmax\n               (fmax\n                (fmax (- (* y 8.13008) 0.625) (- 0.4625 (* y 8.13008)))\n                (- (* x 5.42005) 3.0345))\n               (- 2.872 (* x 5.42005)))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 0.4625) 2)\n               (pow (- (* x 5.42005) 3.0345) 2)))\n             0.1625))\n           (fmax\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 0.575) 2)\n               (pow (- (* x 8.13008) 3.933) 2)))\n             0.275)\n            (fmin\n             (fmax\n              (fmax\n               (fmax (- (* y 8.13008) 0.615) (- 0.525 (* y 8.13008)))\n               (- (* x 8.13008) 4.208))\n              (- 3.708 (* x 8.13008)))\n             (fmax\n              (fmax\n               (-\n                (sqrt\n                 (+\n                  (pow (- (* y 8.13008) 0.575) 2)\n                  (pow (- (* x 8.13008) 3.933) 2)))\n                0.275)\n               (-\n                (fmin\n                 (fmax\n                  (fmax\n                   (- (* y 5.28455) 0.37375)\n                   (- (* x 2.23577) (+ 1.12595 (* y 1.21951))))\n                  (- 1.32095 (+ (* x 2.23577) (* y 4.06504))))\n                 (fmax\n                  (fmax\n                   (- (+ (* x 2.23577) (* y 4.06504)) 1.32095)\n                   (- (+ 1.12595 (* y 1.21951)) (* x 2.23577)))\n                  (- 0.37375 (* y 5.28455))))))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 0.575) 2)\n                 (pow (- (* x 8.13008) 3.933) 2))))))))))))\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (-\n            (fmin\n             (fmax\n              (fmax\n               (fmax (- 2.2095 (* x 5.42005)) (- (* x 5.42005) 2.372))\n               (- 0.525 (* y 8.13008)))\n              (- (* y 8.13008) 0.6875))\n             (-\n              (sqrt\n               (+\n                (pow (- 1.47133 (* x 3.61337)) 2)\n                (pow (- 0.685 (* y 8.13008)) 2)))\n              0.0625)))\n           (-\n            (sqrt\n             (+\n              (pow (- 2.2095 (* x 5.42005)) 2)\n              (pow (- 0.6875 (* y 8.13008)) 2)))\n            0.1625))\n          (fmax\n           (fmax\n            (fmax (- 0.3 (* y 8.13008)) (- (* y 8.13008) 0.575))\n            (- (* x 8.13008) 6.6455))\n           (- 6.5455 (* x 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 1.3) (- 0.3 (* y 8.13008)))\n            (- (* x 8.13008) 6.19551))\n           (- 6.0955 (* x 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- (* x 8.13008) 6.6455) (- 6.0955 (* x 8.13008)))\n               (- (* y 8.13008) 0.85))\n              (- 0.575 (* y 8.13008)))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 0.575) 2)\n                (pow (- (* x 8.13008) 6.3705) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 0.575) 2)\n               (pow (- (* x 8.13008) 6.3705) 2)))\n             0.275))\n           (fmax\n            (fmax\n             (fmax (- (* y 8.13008) 1.3) (- 0.55 (* y 8.13008)))\n             (- (* x 8.13008) 5.8455))\n            (- 5.7455 (* x 8.13008))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 0.95) (- 0.85 (* y 8.13008)))\n            (- (* x 8.13008) 5.9955))\n           (- 5.5955 (* x 8.13008)))\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (* y 8.13008) 0.55) (- 0.3 (* y 8.13008)))\n              (- (* x 8.13008) 5.9955))\n             (- 5.5955 (* x 8.13008)))\n            (-\n             0.15\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 0.55) 2)\n               (pow (- (* x 8.13008) 5.9955) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 0.55) 2)\n              (pow (- (* x 8.13008) 5.9955) 2)))\n            0.25)))\n         (fmin\n          (fmax\n           (-\n            (fmin\n             (fmax\n              (fmax\n               (fmax (- 0.525 (* y 8.13008)) (- (* y 8.13008) 0.6875))\n               (- 3.0345 (* x 5.42005)))\n              (- (* x 5.42005) 3.197))\n             (-\n              (sqrt\n               (+\n                (pow (- 0.685 (* y 8.13008)) 2)\n                (pow (- 2.02133 (* x 3.61337)) 2)))\n              0.0625)))\n           (-\n            (sqrt\n             (+\n              (pow (- 0.6875 (* y 8.13008)) 2)\n              (pow (- 3.0345 (* x 5.42005)) 2)))\n            0.1625))\n          (fmin\n           (fmax\n            (-\n             (fmin\n              (fmax\n               (fmax\n                (fmax (- (* y 8.13008) 0.625) (- 0.4625 (* y 8.13008)))\n                (- 0.788667 (* x 5.42005)))\n               (- (* x 5.42005) 0.951167))\n              (-\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 0.465) 2)\n                 (pow (- (* x 3.61337) 0.635778) 2)))\n               0.0625)))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 0.4625) 2)\n               (pow (- (* x 5.42005) 0.951167) 2)))\n             0.1625))\n           (fmax\n            (fmax\n             (fmax (- 0.3 (* y 8.13008)) (- (* y 8.13008) 0.85))\n             (- (* x 8.13008) 0.125))\n            (- 0.0249996 (* x 8.13008)))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- 0.3 (* y 8.13008)) (- (* y 8.13008) 0.85))\n              (- (* x 11.6144) 0.585714))\n             (- 0.0357141 (* x 11.6144)))\n            (-\n             0.45\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 0.3) 2)\n               (pow (- (* x 14.518) 0.732143) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 0.3) 2)\n              (pow (- (* x 11.6144) 0.585714) 2)))\n            0.55))\n          (fmax\n           (fmax\n            (fmax (- 0.3 (* y 8.13008)) (- (* y 8.13008) 0.85))\n            (+ 0.1 (* x 8.13008)))\n           (- (+ 0.2 (* x 8.13008)))))\n         (fmin\n          (-\n           (sqrt\n            (+ (pow (- (* y 8.13008) 1) 2) (pow (+ 0.150001 (* x 8.13008)) 2)))\n           0.075)\n          (fmin\n           (fmax\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 0.575) 2)\n               (pow (+ 0.6 (* x 8.13008)) 2)))\n             0.275)\n            (fmin\n             (fmax\n              (fmax\n               (fmax (- (* y 8.13008) 0.615) (- 0.525 (* y 8.13008)))\n               (+ 0.325 (* x 8.13008)))\n              (- (+ 0.825 (* x 8.13008))))\n             (fmax\n              (fmax\n               (-\n                (sqrt\n                 (+\n                  (pow (- (* y 8.13008) 0.575) 2)\n                  (pow (+ 0.6 (* x 8.13008)) 2)))\n                0.275)\n               (-\n                (fmin\n                 (fmax\n                  (fmax\n                   (- (* y 5.28455) 0.37375)\n                   (- (+ 0.120625 (* x 2.23577)) (* y 1.21951)))\n                  (- 0.0743749 (+ (* x 2.23577) (* y 4.06504))))\n                 (fmax\n                  (fmax\n                   (- 0.37375 (* y 5.28455))\n                   (- (+ (* x 2.23577) (* y 4.06504)) 0.0743749))\n                  (- (* y 1.21951) (+ 0.120625 (* x 2.23577)))))))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 0.575) 2)\n                 (pow (+ 0.6 (* x 8.13008)) 2)))))))\n           (fmax\n            (-\n             (fmin\n              (fmax\n               (fmax\n                (fmax (- (* x 5.42005) 2.2095) (- 2.047 (* x 5.42005)))\n                (- (* y 8.13008) 0.625))\n               (- 0.4625 (* y 8.13008)))\n              (-\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 0.465) 2)\n                 (pow (- (* x 3.61337) 1.47467) 2)))\n               0.0625)))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 0.4625) 2)\n               (pow (- (* x 5.42005) 2.2095) 2)))\n             0.1625)))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 0.3 (* y 8.13008)) (- (* y 8.13008) 0.625))\n            (- (* x 8.13008) 2.9705))\n           (- 2.8705 (* x 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- 0.3 (* y 8.13008)) (- (* y 8.13008) 0.85))\n             (- (* x 8.13008) 2.5205))\n            (- 2.4205 (* x 8.13008)))\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- (* y 8.13008) 0.85) (- (* x 8.13008) 2.9705))\n               (- 2.4205 (* x 8.13008)))\n              (- 0.625 (* y 8.13008)))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 0.575) 2)\n                (pow (- (* x 8.13008) 2.6955) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 0.575) 2)\n               (pow (- (* x 8.13008) 2.6955) 2)))\n             0.275))))\n         (fmin\n          (fmax\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 0.575) 2)\n              (pow (- (* x 8.13008) 2.0455) 2)))\n            0.275)\n           (fmin\n            (fmax\n             (fmax\n              (fmax (- (* y 8.13008) 0.615) (- 0.525 (* y 8.13008)))\n              (- (* x 8.13008) 2.3205))\n             (- 1.8205 (* x 8.13008)))\n            (fmax\n             (fmax\n              (-\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 0.575) 2)\n                 (pow (- (* x 8.13008) 2.0455) 2)))\n               0.275)\n              (-\n               (fmin\n                (fmax\n                 (fmax\n                  (- (* y 5.28455) 0.37375)\n                  (- (* x 2.23577) (+ 0.606888 (* y 1.21951))))\n                 (- 0.801888 (+ (* x 2.23577) (* y 4.06504))))\n                (fmax\n                 (fmax\n                  (- 0.37375 (* y 5.28455))\n                  (- (+ (* x 2.23577) (* y 4.06504)) 0.801888))\n                 (- (+ 0.606888 (* y 1.21951)) (* x 2.23577))))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 0.575) 2)\n                (pow (- (* x 8.13008) 2.0455) 2)))))))\n          (fmin\n           (fmax\n            (-\n             (fmin\n              (fmax\n               (fmax\n                (fmax (- 0.525 (* y 8.13008)) (- (* y 8.13008) 0.6875))\n                (- 0.951167 (* x 5.42005)))\n               (- (* x 5.42005) 1.11367))\n              (-\n               (sqrt\n                (+\n                 (pow (- 0.685 (* y 8.13008)) 2)\n                 (pow (- 0.632445 (* x 3.61337)) 2)))\n               0.0625)))\n            (-\n             (sqrt\n              (+\n               (pow (- 0.6875 (* y 8.13008)) 2)\n               (pow (- 0.951167 (* x 5.42005)) 2)))\n             0.1625))\n           (fmax\n            (-\n             (sqrt\n              (+\n               (pow (- (+ 1.5125 (* y 8.13008))) 2)\n               (pow (- (+ 0.3955 (* x 5.42005))) 2)))\n             0.1625)\n            (-\n             (fmin\n              (fmax\n               (fmax\n                (fmax (- (+ 1.675 (* y 8.13008))) (+ 1.5125 (* y 8.13008)))\n                (- (+ 0.3955 (* x 5.42005))))\n               (+ 0.233001 (* x 5.42005)))\n              (-\n               (sqrt\n                (+\n                 (pow (- (+ 1.515 (* y 8.13008))) 2)\n                 (pow (- (+ 0.265334 (* x 3.61337))) 2)))\n               0.0625))))))))))\n     (fmin\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (-\n            (fmin\n             (fmax\n              (fmax\n               (fmax (+ 1.575 (* y 8.13008)) (- (+ 1.7375 (* y 8.13008))))\n               (+ 0.395501 (* x 5.42005)))\n              (- (+ 0.558001 (* x 5.42005))))\n             (-\n              (sqrt\n               (+\n                (pow (+ 1.735 (* y 8.13008)) 2)\n                (pow (+ 0.262 (* x 3.61337)) 2)))\n              0.0625)))\n           (-\n            (sqrt\n             (+\n              (pow (+ 1.7375 (* y 8.13008)) 2)\n              (pow (+ 0.395501 (* x 5.42005)) 2)))\n            0.1625))\n          (fmax\n           (fmax\n            (- (+ 0.245 (* y 0.813008)))\n            (- (+ 0.596601 (* x 4.47154)) (* y 1.82927)))\n           (- (* y 2.64228) (+ 0.4066 (* x 4.47154)))))\n         (fmin\n          (fmax\n           (fmax\n            (+ 0.245 (* y 0.813008))\n            (- (+ 0.4066 (* x 4.47154)) (* y 2.64228)))\n           (- (* y 1.82927) (+ 0.596601 (* x 4.47154))))\n          (fmin\n           (fmax\n            (fmax\n             (+ 0.19 (* y 0.813008))\n             (- (+ 0.4066 (* x 4.47154)) (* y 2.64228)))\n            (- (* y 1.82927) (+ 0.6516 (* x 4.47154))))\n           (fmax\n            (fmax\n             (- (+ 0.19 (* y 0.813008)))\n             (- (* y 2.64228) (+ 0.4066 (* x 4.47154))))\n            (- (+ 0.6516 (* x 4.47154)) (* y 1.82927))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (+ 0.19 (* y 0.813008)))\n            (- (+ 0.5966 (* x 4.47154)) (* y 1.82927)))\n           (- (* y 2.64228) (+ 0.461601 (* x 4.47154))))\n          (fmax\n           (fmax\n            (+ 0.19 (* y 0.813008))\n            (- (* y 1.82927) (+ 0.596601 (* x 4.47154))))\n           (- (+ 0.461601 (* x 4.47154)) (* y 2.64228))))\n         (fmin\n          (fmax\n           (fmax\n            (+ 0.135 (* y 0.813008))\n            (- (* y 1.82927) (+ 0.6516 (* x 4.47154))))\n           (- (+ 0.461601 (* x 4.47154)) (* y 2.64228)))\n          (fmin\n           (fmax\n            (fmax\n             (- (+ 0.135 (* y 0.813008)))\n             (- (+ 0.6516 (* x 4.47154)) (* y 1.82927)))\n            (- (* y 2.64228) (+ 0.461601 (* x 4.47154))))\n           (fmax\n            (fmax\n             (- (+ 0.19 (* y 0.813008)))\n             (- (+ (+ 1.5066 (* y 1.82927)) (* x 4.47154))))\n            (+ (+ 1.6416 (* y 2.64228)) (* x 4.47154)))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (+ 0.19 (* y 0.813008))\n            (- (+ (+ 1.6416 (* y 2.64228)) (* x 4.47154))))\n           (+ (+ 1.5066 (* y 1.82927)) (* x 4.47154)))\n          (fmax\n           (fmax\n            (+ 0.135 (* y 0.813008))\n            (- (+ (+ 1.6416 (* y 2.64228)) (* x 4.47154))))\n           (+ (+ 1.4516 (* y 1.82927)) (* x 4.47154))))\n         (fmin\n          (fmax\n           (fmax\n            (- (+ 0.135 (* y 0.813008)))\n            (+ (+ 1.6416 (* y 2.64228)) (* x 4.47154)))\n           (- (+ (+ 1.4516 (* y 1.82927)) (* x 4.47154))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (+ 1.35 (* y 8.13008)) (- (+ 1.45 (* y 8.13008))))\n             (- (* x 8.13008) 1.3305))\n            (- 0.9305 (* x 8.13008)))\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (+ 0.9 (* y 8.13008)) (- (+ 1.15 (* y 8.13008))))\n               (- (* x 8.13008) 1.3305))\n              (- 0.9305 (* x 8.13008)))\n             (-\n              0.15\n              (sqrt\n               (+\n                (pow (+ 1.15 (* y 8.13008)) 2)\n                (pow (- (* x 8.13008) 1.3305) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 1.15 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) 1.3305) 2)))\n             0.25)))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 1.9 (* y 8.13008))) (+ 1.55 (* y 8.13008)))\n            (- (* x 8.13008) 0.8105))\n           (- 0.7105 (* x 8.13008)))\n          (fmin\n           (fmax\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (+ 1.625 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) (+ 0.993357 (* y 2.32288))) 2))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 1.625 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) (+ 0.993357 (* y 2.32288))) 2)))\n             0.275))\n           (fmax\n            (fmax\n             (fmax (+ 0.9 (* y 8.13008)) (- (+ 1.65 (* y 8.13008))))\n             (- (* x 8.13008) 0.000499725))\n            (- (+ 0.0995007 (* x 8.13008))))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 1.25 (* y 8.13008)) (- (+ 1.35 (* y 8.13008))))\n            (- (* x 8.13008) 0.150499))\n           (- (+ 0.249501 (* x 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- (+ 1.9 (* y 8.13008))) (+ 1.65 (* y 8.13008)))\n               (- (* x 8.13008) 0.150499))\n              (- (+ 0.249501 (* x 8.13008))))\n             (-\n              0.15\n              (sqrt\n               (+\n                (pow (+ 1.65 (* y 8.13008)) 2)\n                (pow (- (* x 8.13008) 0.150499) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 1.65 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) 0.150499) 2)))\n             0.25))\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (+ 1.9 (* y 8.13008))) (+ 0.9 (* y 8.13008)))\n              (-\n               (fmin\n                (fmin\n                 (fmin\n                  (fmax\n                   (fmax\n                    (- (+ 1.66785 (* x 4.47154)) (* y 3.25203))\n                    (- (+ 2.24785 (* x 4.47154))))\n                   (+ 0.36 (* y 3.25203)))\n                  (fmax\n                   (fmax\n                    (+ 2.24785 (* x 4.47154))\n                    (- (* y 3.25203) (+ 1.66785 (* x 4.47154))))\n                   (- (+ 0.36 (* y 3.25203)))))\n                 (fmin\n                  (fmax\n                   (fmax (+ 0.45 (* y 4.06504)) (+ 1.7935 (* x 4.06504)))\n                   (- (+ 2.4935 (* (+ x y) 4.06504))))\n                  (fmax\n                   (fmax\n                    (+ 2.4935 (* (+ x y) 4.06504))\n                    (- (+ 1.7935 (* x 4.06504))))\n                   (- (+ 0.45 (* y 4.06504))))))\n                (fmin\n                 (fmin\n                  (fmax\n                   (fmax\n                    (- (+ 3.497 (* x 8.13008)) (* y 0.813008))\n                    (- (+ (+ 1.89845 (* y 2.60163)) (* x 2.84553))))\n                   (- (* y 3.41463) (+ 1.95355 (* x 5.28455))))\n                  (fmax\n                   (fmax\n                    (- (+ 1.95355 (* x 5.28455)) (* y 3.41463))\n                    (+ (+ 1.89845 (* y 2.60163)) (* x 2.84553)))\n                   (- (* y 0.813008) (+ 3.497 (* x 8.13008)))))\n                 (fmin\n                  (fmax\n                   (fmax\n                    (- (+ 0.54 (* y 2.19512)))\n                    (- (+ 1.43045 (* x 2.84553))))\n                   (+ (+ 1.87595 (* y 2.19512)) (* x 2.84553)))\n                  (fmax\n                   (fmax (+ 0.54 (* y 2.19512)) (+ 1.43045 (* x 2.84553)))\n                   (- (+ (+ 1.87595 (* y 2.19512)) (* x 2.84553)))))))))\n             (+ 3.687 (* x 8.13008)))\n            (- (+ 4.187 (* x 8.13008)))))))))\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 1.9 (* y 8.13008))) (+ 1.55 (* y 8.13008)))\n            (+ 4.307 (* x 8.13008)))\n           (- (+ 4.407 (* x 8.13008))))\n          (fmax\n           (-\n            0.175\n            (sqrt\n             (+\n              (pow (+ 1.625 (* y 8.13008)) 2)\n              (pow (- (+ 4.12414 (* x 8.13008)) (* y 2.32288)) 2))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 1.625 (* y 8.13008)) 2)\n              (pow (- (+ 4.12414 (* x 8.13008)) (* y 2.32288)) 2)))\n            0.275)))\n         (fmin\n          (fmax\n           (-\n            (sqrt\n             (+\n              (pow (+ 1.625 (* y 8.13008)) 2)\n              (pow (+ 5.242 (* x 8.13008)) 2)))\n            0.275)\n           (fmin\n            (fmax\n             (fmax\n              (fmax (+ 1.585 (* y 8.13008)) (- (+ 1.675 (* y 8.13008))))\n              (+ 4.967 (* x 8.13008)))\n             (- (+ 5.467 (* x 8.13008))))\n            (fmax\n             (fmax\n              (-\n               (sqrt\n                (+\n                 (pow (+ 1.625 (* y 8.13008)) 2)\n                 (pow (+ 5.242 (* x 8.13008)) 2)))\n               0.275)\n              (-\n               (fmin\n                (fmax\n                 (fmax\n                  (+ 1.05625 (* y 5.28455))\n                  (- (+ 1.06718 (* x 2.23577)) (* y 1.21951)))\n                 (- (+ (+ (* x 2.23577) 2.30217) (* y 4.06504))))\n                (fmax\n                 (fmax\n                  (+ (+ (* x 2.23577) 2.30217) (* y 4.06504))\n                  (- (* y 1.21951) (+ 1.06718 (* x 2.23577))))\n                 (- (+ 1.05625 (* y 5.28455)))))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (+ 1.625 (* y 8.13008)) 2)\n                (pow (+ 5.242 (* x 8.13008)) 2)))))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (+ 1.9 (* y 8.13008))) (+ 1.35 (* y 8.13008)))\n             (+ 5.875 (* x 8.13008)))\n            (- (+ 5.975 (* x 8.13008))))\n           (fmax\n            (fmax\n             (fmax (- (+ 1.9 (* y 8.13008))) (+ 2.287 (* x 8.13008)))\n             (- (+ 2.387 (* x 8.13008))))\n            (+ 1.55 (* y 8.13008))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 1.9 (* y 8.13008))) (+ 1.55 (* y 8.13008)))\n            (+ 2.537 (* x 8.13008)))\n           (- (+ 2.637 (* x 8.13008))))\n          (fmax\n           (fmax\n            (fmax (- (+ 1.9 (* y 8.13008))) (+ 1.375 (* y 8.13008)))\n            (+ 2.787 (* x 8.13008)))\n           (- (+ 2.887 (* x 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax (+ 1.25 (* y 8.13008)) (- (+ 2.887 (* x 8.13008))))\n             (- (+ 1.55 (* y 8.13008))))\n            (+ 2.237 (* x 8.13008)))\n           (fmin\n            (fmax\n             (-\n              0.075\n              (sqrt\n               (+\n                (pow (+ 1.55 (* y 8.13008)) 2)\n                (pow (+ 2.462 (* x 8.13008)) 2))))\n             (-\n              (sqrt\n               (+\n                (pow (+ 1.55 (* y 8.13008)) 2)\n                (pow (+ 2.462 (* x 8.13008)) 2)))\n              0.175))\n            (fmax\n             (-\n              0.075\n              (sqrt\n               (+\n                (pow (+ 1.55 (* y 8.13008)) 2)\n                (pow (+ 2.712 (* x 8.13008)) 2))))\n             (-\n              (sqrt\n               (+\n                (pow (+ 1.55 (* y 8.13008)) 2)\n                (pow (+ 2.712 (* x 8.13008)) 2)))\n              0.175))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax\n                (-\n                 (fmin\n                  (fmax\n                   (fmax\n                    (- (* x 2.84553) (+ (* y 0.813008) 1.89365))\n                    (- 0.681276 (+ (* x 1.82927) (* y 4.06504))))\n                   (- (+ 1.01488 (* y 4.87805)) (* x 1.01626)))\n                  (fmax\n                   (fmax\n                    (- (* x 1.01626) (+ 1.01488 (* y 4.87805)))\n                    (- (+ (* x 1.82927) (* y 4.06504)) 0.681276))\n                   (- (+ (* y 0.813008) 1.89365) (* x 2.84553)))))\n                (+ 0.725 (* y 8.13008)))\n               (- (+ 0.95 (* y 8.13008))))\n              (- (* x 8.13008) 5.289))\n             (- 5.139 (* x 8.13008)))\n            (-\n             (sqrt\n              (+\n               (pow (+ 0.241667 (* y 2.71003)) 2)\n               (pow (- (* x 8.13008) 5.214) 2)))\n             0.075))\n           (-\n            (sqrt\n             (+\n              (pow (+ 0.725 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 5.239) 2)))\n            0.075)))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 0.25 (* y 8.13008)) (- (* x 8.13008) 4.781))\n            (- 4.681 (* x 8.13008)))\n           (- (+ 0.8 (* y 8.13008))))\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (+ 0.25 (* y 8.13008)) (- (* x 11.6144) 7.23715))\n              (- 6.68715 (* x 11.6144)))\n             (-\n              0.45\n              (sqrt\n               (+\n                (pow (+ 0.8 (* y 8.13008)) 2)\n                (pow (- (* x 14.518) 9.04643) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 0.8 (* y 8.13008)) 2)\n               (pow (- (* x 11.6144) 7.23715) 2)))\n             0.55))\n           (- (+ 0.8 (* y 8.13008)))))\n         (fmin\n          (fmax\n           (-\n            0.175\n            (sqrt\n             (+\n              (pow (+ 0.525 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 4.306) 2))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 0.525 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 4.306) 2)))\n            0.275))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- (+ 1.9 (* y 8.13008))) (+ 1.35 (* y 8.13008)))\n               (+ 7.98571 (* x 11.6144)))\n              (- (+ 8.53571 (* x 11.6144))))\n             (-\n              0.45\n              (sqrt\n               (+\n                (pow (+ 1.9 (* y 8.13008)) 2)\n                (pow (+ 9.98214 (* x 14.518)) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 1.9 (* y 8.13008)) 2)\n               (pow (+ 7.98571 (* x 11.6144)) 2)))\n             0.55))\n           (fmax\n            (fmax\n             (fmax (- (+ 1.9 (* y 8.13008))) (+ 0.9 (* y 8.13008)))\n             (+ 6.5 (* x 8.13008)))\n            (- (+ 6.6 (* x 8.13008)))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 1.35 (* y 8.13008)) (+ 6.325 (* x 8.13008)))\n            (- (+ 1.45 (* y 8.13008))))\n           (- (+ 6.5 (* x 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (+ 1.9 (* y 8.13008))) (+ 6.325 (* x 8.13008)))\n             (+ 1.8 (* y 8.13008)))\n            (- (+ 6.5 (* x 8.13008))))\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- (+ 1.9 (* y 8.13008))) (+ 0.9 (* y 8.13008)))\n               (+ 5.6 (* x 8.13008)))\n              (- (+ 6.325 (* x 8.13008))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (+ 6.325 (* x 8.13008)) 2)\n                (pow (+ 1.625 (* y 8.13008)) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (+ 6.325 (* x 8.13008)) 2)\n               (pow (+ 1.625 (* y 8.13008)) 2)))\n             0.275))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 0.2) (- (+ 0.8 (* y 8.13008))))\n            (- (* x 8.13008) 7.28901))\n           (- 7.18901 (* x 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (* y 8.13008) 0.2) (- (+ 0.8 (* y 8.13008))))\n             (- (* x 8.13008) 7.03901))\n            (- 6.93901 (* x 8.13008)))\n           (fmax\n            (fmax\n             (fmax (- (* y 8.13008) 4.76837e-7) (- (+ 0.25 (* y 8.13008))))\n             (- (* x 8.13008) 6.81401))\n            (- 6.71401 (* x 8.13008))))))))))))\n  (fmin\n   (fmin\n    (fmin\n     (fmin\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 0.2) (- 0.1 (* y 8.13008)))\n            (- (* x 8.13008) 6.61401))\n           (- 6.11401 (* x 8.13008)))\n          (fmax\n           (fmax\n            (fmax (- (+ 0.8 (* y 8.13008))) (- (* x 8.13008) 6.61401))\n            (- 6.11401 (* x 8.13008)))\n           (+ 0.7 (* y 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 0.2) (- (+ 0.8 (* y 8.13008))))\n            (- (* x 8.13008) 6.41401))\n           (- 6.314 (* x 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (+ 0.25 (* y 8.13008)) (- (+ 0.8 (* y 8.13008))))\n             (- (* x 8.13008) 2.1185))\n            (- 2.0185 (* x 8.13008)))\n           (-\n            (sqrt\n             (+\n              (pow (+ 0.0999999 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 2.0685) 2)))\n            0.075))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 0.8 (* y 8.13008))) (+ 0.45 (* y 8.13008)))\n            (- (* x 8.13008) 1.1935))\n           (- 1.0935 (* x 8.13008)))\n          (fmax\n           (fmax\n            (fmax (- (+ 0.8 (* y 8.13008))) (+ 0.45 (* y 8.13008)))\n            (- (* x 8.13008) 0.943501))\n           (- 0.8435 (* x 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 0.8 (* y 8.13008))) (+ 0.275 (* y 8.13008)))\n            (- (* x 8.13008) 0.693501))\n           (- 0.5935 (* x 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- 0.5935 (* x 8.13008)) (+ 0.15 (* y 8.13008)))\n              (- (+ 0.45 (* y 8.13008))))\n             (- (* x 8.13008) 1.2435))\n            (fmin\n             (fmax\n              (-\n               0.075\n               (sqrt\n                (+\n                 (pow (+ 0.45 (* y 8.13008)) 2)\n                 (pow (- (* x 8.13008) 1.0185) 2))))\n              (-\n               (sqrt\n                (+\n                 (pow (+ 0.45 (* y 8.13008)) 2)\n                 (pow (- (* x 8.13008) 1.0185) 2)))\n               0.175))\n             (fmax\n              (-\n               0.075\n               (sqrt\n                (+\n                 (pow (+ 0.45 (* y 8.13008)) 2)\n                 (pow (- (* x 8.13008) 0.7685) 2))))\n              (-\n               (sqrt\n                (+\n                 (pow (+ 0.45 (* y 8.13008)) 2)\n                 (pow (- (* x 8.13008) 0.7685) 2)))\n               0.175))))\n           (fmax\n            (fmax\n             (fmax (+ 0.25 (* y 8.13008)) (- (+ 0.8 (* y 8.13008))))\n             (- (* x 8.13008) 0.2355))\n            (- 0.1355 (* x 8.13008)))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 0.0499997 (* y 8.13008)) (- (* x 8.13008) 3.781))\n            (- (+ 0.8 (* y 8.13008))))\n           (- 3.681 (* x 8.13008)))\n          (fmax\n           (fmax\n            (fmax (+ 0.25 (* y 8.13008)) (- (+ 0.35 (* y 8.13008))))\n            (- (* x 8.13008) 3.931))\n           (- 3.531 (* x 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (* y 8.13008) 0.2) (- (* x 8.13008) 3.931))\n              (- 3.531 (* x 8.13008)))\n             (- (+ 0.0499997 (* y 8.13008))))\n            (-\n             0.15\n             (sqrt\n              (+\n               (pow (+ 0.0499997 (* y 8.13008)) 2)\n               (pow (- (* x 8.13008) 3.931) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 0.0499997 (* y 8.13008)) 2)\n              (pow (- (* x 8.13008) 3.931) 2)))\n            0.25))\n          (fmin\n           (fmax\n            (-\n             (fmin\n              (fmax\n               (fmax\n                (fmax (- (+ 0.575 (* y 8.13008))) (+ 0.4125 (* y 8.13008)))\n                (- 1.65817 (* x 5.42005)))\n               (- (* x 5.42005) 1.82067))\n              (-\n               (sqrt\n                (+\n                 (pow (- (+ 0.415 (* y 8.13008))) 2)\n                 (pow (- 1.10378 (* x 3.61337)) 2)))\n               0.0625)))\n            (-\n             (sqrt\n              (+\n               (pow (- (+ 0.4125 (* y 8.13008))) 2)\n               (pow (- 1.65817 (* x 5.42005)) 2)))\n             0.1625))\n           (fmax\n            (-\n             (fmin\n              (fmax\n               (fmax\n                (fmax (+ 0.475 (* y 8.13008)) (- (+ 0.6375 (* y 8.13008))))\n                (- (* x 5.42005) 1.65817))\n               (- 1.49567 (* x 5.42005)))\n              (-\n               (sqrt\n                (+\n                 (pow (+ 0.635 (* y 8.13008)) 2)\n                 (pow (- (* x 3.61337) 1.10711) 2)))\n               0.0625)))\n            (-\n             (sqrt\n              (+\n               (pow (+ 0.6375 (* y 8.13008)) 2)\n               (pow (- (* x 5.42005) 1.65817) 2)))\n             0.1625)))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (+ 0.25 (* y 8.13008)) (- (+ 0.8 (* y 8.13008))))\n              (- (* x 11.6144) 0.743571))\n             (- 0.193571 (* x 11.6144)))\n            (-\n             0.45\n             (sqrt\n              (+\n               (pow (+ 0.8 (* y 8.13008)) 2)\n               (pow (- (* x 14.518) 0.929465) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 0.8 (* y 8.13008)) 2)\n              (pow (- (* x 11.6144) 0.743571) 2)))\n            0.55))\n          100000000.0)\n         (fmin\n          (fmax\n           (-\n            (sqrt\n             (+\n              (pow (- (* x 8.13008) 7.12751) 2)\n              (pow (- (* y 8.13008) 2.775) 2)))\n            0.275)\n           (fmin\n            (fmax\n             (fmax\n              (fmax (- (* y 8.13008) 2.815) (- 2.725 (* y 8.13008)))\n              (- (* x 8.13008) 7.40251))\n             (- 6.90251 (* x 8.13008)))\n            (fmax\n             (fmax\n              (-\n               (sqrt\n                (+\n                 (pow (- (* x 8.13008) 7.12751) 2)\n                 (pow (- (* y 8.13008) 2.775) 2)))\n               0.275)\n              (-\n               (fmin\n                (fmax\n                 (fmax\n                  (- (* y 5.28455) 1.80375)\n                  (- (* x 2.23577) (+ (* y 1.21951) 1.67444)))\n                 (- 3.29944 (+ (* x 2.23577) (* y 4.06504))))\n                (fmax\n                 (fmax\n                  (- (+ (* x 2.23577) (* y 4.06504)) 3.29944)\n                  (- (+ (* y 1.21951) 1.67444) (* x 2.23577)))\n                 (- 1.80375 (* y 5.28455))))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (- (* x 8.13008) 7.12751) 2)\n                (pow (- (* y 8.13008) 2.775) 2)))))))\n          (fmin\n           (fmax\n            (fmax\n             (- 0.25 (* y 0.813008))\n             (- (* x 4.47154) (+ (* y 2.03252) 2.95138)))\n            (- (+ 2.64638 (* y 2.84553)) (* x 4.47154)))\n           (fmax\n            (fmax\n             (- (* x 4.47154) (+ 2.64638 (* y 2.84553)))\n             (- (+ (* y 2.03252) 2.95138) (* x 4.47154)))\n            (- (* y 0.813008) 0.25)))))))\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (* x 4.47154) (+ 2.64638 (* y 2.84553)))\n            (- (* y 0.813008) 0.305))\n           (- (+ (* y 2.03252) 2.89638) (* x 4.47154)))\n          (fmax\n           (fmax\n            (- (+ 2.64638 (* y 2.84553)) (* x 4.47154))\n            (- (* x 4.47154) (+ (* y 2.03252) 2.89638)))\n           (- 0.305 (* y 0.813008))))\n         (fmin\n          (fmax\n           (fmax\n            (- 0.25 (* y 0.813008))\n            (- 4.14638 (+ (* y 2.03252) (* x 4.47154))))\n           (- (+ (* y 2.84553) (* x 4.47154)) 4.45138))\n          (fmin\n           (fmax\n            (fmax\n             (- (* y 0.813008) 0.25)\n             (- 4.45138 (+ (* y 2.84553) (* x 4.47154))))\n            (- (+ (* y 2.03252) (* x 4.47154)) 4.14638))\n           (fmax\n            (fmax\n             (- (* y 0.813008) 0.305)\n             (- 4.45138 (+ (* y 2.84553) (* x 4.47154))))\n            (- (+ (* y 2.03252) (* x 4.47154)) 4.20138)))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- 0.305 (* y 0.813008))\n            (- (+ (* y 2.84553) (* x 4.47154)) 4.45138))\n           (- 4.20138 (+ (* y 2.03252) (* x 4.47154))))\n          (fmax\n           (fmax\n            (- (+ (+ (* y 2.03252) 2.8125) (* x 4.47154)))\n            (+ (+ 2.6175 (* y 2.84553)) (* x 4.47154)))\n           (- 0.14 (* y 0.813008))))\n         (fmin\n          (fmax\n           (fmax\n            (+ (+ (* y 2.03252) 2.8125) (* x 4.47154))\n            (- (+ (+ 2.6175 (* y 2.84553)) (* x 4.47154))))\n           (- (* y 0.813008) 0.14))\n          (fmin\n           (fmax\n            (fmax\n             (- (+ (+ 2.6175 (* y 2.84553)) (* x 4.47154)))\n             (+ (+ (* y 2.03252) 2.7575) (* x 4.47154)))\n            (- (* y 0.813008) 0.195))\n           (fmax\n            (fmax\n             (+ (+ 2.6175 (* y 2.84553)) (* x 4.47154))\n             (- (+ (+ (* y 2.03252) 2.7575) (* x 4.47154))))\n            (- 0.195 (* y 0.813008)))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (-\n            0.175\n            (sqrt\n             (+\n              (pow (+ 6.375 (* x 8.13008)) 2)\n              (pow (- (* y 8.13008) 1.675) 2))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 6.375 (* x 8.13008)) 2)\n              (pow (- (* y 8.13008) 1.675) 2)))\n            0.275))\n          (fmax\n           (fmax\n            (fmax (+ 6.75 (* x 8.13008)) (- (+ 6.85 (* x 8.13008))))\n            (- (* y 8.13008) 1.725))\n           (- 1.4 (* y 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 7.3 (* x 8.13008))) (+ 7.2 (* x 8.13008)))\n            (- 1.4 (* y 8.13008)))\n           (- (* y 8.13008) 1.95))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- (+ 7.3 (* x 8.13008))) (+ 6.75 (* x 8.13008)))\n               (-\n                0.175\n                (sqrt\n                 (+\n                  (pow (+ 7.025 (* x 8.13008)) 2)\n                  (pow (- (* y 8.13008) 1.675) 2)))))\n              (-\n               (sqrt\n                (+\n                 (pow (+ 7.025 (* x 8.13008)) 2)\n                 (pow (- (* y 8.13008) 1.675) 2)))\n               0.275))\n             (- 1.725 (* y 8.13008)))\n            (- (* y 8.13008) 1.95))\n           (fmax\n            (fmax\n             (fmax (- (* y 8.13008) 2.825) (- 2.5 (* y 8.13008)))\n             (- (* x 8.13008) 8.05251))\n            (- 7.95251 (* x 8.13008))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 2.5 (* y 8.13008)) (- (* y 8.13008) 3.05))\n            (- (* x 8.13008) 7.60251))\n           (- 7.50251 (* x 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- (* x 8.13008) 8.05251) (- (* y 8.13008) 3.05))\n               (- 7.50251 (* x 8.13008)))\n              (- 2.825 (* y 8.13008)))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 2.775) 2)\n                (pow (- (* x 8.13008) 7.77751) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 2.775) 2)\n               (pow (- (* x 8.13008) 7.77751) 2)))\n             0.275))\n           (fmax\n            (fmax\n             (fmax (- 2.5 (* y 8.13008)) (- (* y 8.13008) 2.775))\n             (- (* x 8.13008) 3.1225))\n            (- 3.0225 (* x 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 2.5 (* y 8.13008)) (- (* x 8.13008) 2.6725))\n            (- 2.5725 (* x 8.13008)))\n           (- (* y 8.13008) 3.5))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- (* y 8.13008) 3.05) (- 2.5725 (* x 8.13008)))\n               (-\n                0.175\n                (sqrt\n                 (+\n                  (pow (- (* y 8.13008) 2.775) 2)\n                  (pow (- (* x 8.13008) 2.8475) 2)))))\n              (-\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 2.775) 2)\n                 (pow (- (* x 8.13008) 2.8475) 2)))\n               0.275))\n             (- 2.775 (* y 8.13008)))\n            (- (* x 8.13008) 3.1225))\n           (fmax\n            (fmax\n             (- 0.25 (* y 0.813008))\n             (- (* x 4.47154) (+ 0.597376 (* y 2.03252))))\n            (- (+ 0.292376 (* y 2.84553)) (* x 4.47154)))))))))\n     (fmin\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (* y 0.813008) 0.25)\n            (- (* x 4.47154) (+ 0.292376 (* y 2.84553))))\n           (- (+ 0.597376 (* y 2.03252)) (* x 4.47154)))\n          (fmax\n           (fmax\n            (- (* y 0.813008) 0.305)\n            (- (* x 4.47154) (+ 0.292376 (* y 2.84553))))\n           (- (+ 0.542376 (* y 2.03252)) (* x 4.47154))))\n         (fmin\n          (fmax\n           (fmax\n            (- 0.305 (* y 0.813008))\n            (- (+ 0.292376 (* y 2.84553)) (* x 4.47154)))\n           (- (* x 4.47154) (+ 0.542376 (* y 2.03252))))\n          (fmin\n           (fmax\n            (fmax\n             (- 0.25 (* y 0.813008))\n             (- 1.79238 (+ (* y 2.03252) (* x 4.47154))))\n            (- (+ (* y 2.84553) (* x 4.47154)) 2.09738))\n           (fmax\n            (fmax\n             (- (* y 0.813008) 0.25)\n             (- 2.09738 (+ (* y 2.84553) (* x 4.47154))))\n            (- (+ (* y 2.03252) (* x 4.47154)) 1.79238)))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (* y 0.813008) 0.305)\n            (- 2.09738 (+ (* y 2.84553) (* x 4.47154))))\n           (- (+ (* y 2.03252) (* x 4.47154)) 1.84738))\n          (fmax\n           (fmax\n            (- 0.305 (* y 0.813008))\n            (- (+ (* y 2.84553) (* x 4.47154)) 2.09738))\n           (- 1.84738 (+ (* y 2.03252) (* x 4.47154)))))\n         (fmin\n          (fmax\n           (fmax\n            (- 0.25 (* y 0.813008))\n            (- (* x 4.47154) (+ 0.322376 (* y 2.03252))))\n           (- (+ 0.0173756 (* y 2.84553)) (* x 4.47154)))\n          (fmin\n           (fmax\n            (fmax\n             (- (* y 0.813008) 0.25)\n             (- (* x 4.47154) (+ 0.0173756 (* y 2.84553))))\n            (- (+ 0.322376 (* y 2.03252)) (* x 4.47154)))\n           (fmax\n            (fmax\n             (- (* y 0.813008) 0.305)\n             (- (* x 4.47154) (+ 0.0173756 (* y 2.84553))))\n            (- (+ 0.267376 (* y 2.03252)) (* x 4.47154)))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- 0.305 (* y 0.813008))\n            (- (+ 0.0173756 (* y 2.84553)) (* x 4.47154)))\n           (- (* x 4.47154) (+ 0.267376 (* y 2.03252))))\n          (fmax\n           (fmax\n            (- 0.25 (* y 0.813008))\n            (- 1.51738 (+ (* y 2.03252) (* x 4.47154))))\n           (- (+ (* y 2.84553) (* x 4.47154)) 1.82238)))\n         (fmin\n          (fmax\n           (fmax\n            (- (* y 0.813008) 0.25)\n            (- 1.82238 (+ (* y 2.84553) (* x 4.47154))))\n           (- (+ (* y 2.03252) (* x 4.47154)) 1.51738))\n          (fmin\n           (fmax\n            (fmax\n             (- (* y 0.813008) 0.305)\n             (- 1.82238 (+ (* y 2.84553) (* x 4.47154))))\n            (- (+ (* y 2.03252) (* x 4.47154)) 1.57238))\n           (fmax\n            (fmax\n             (- 0.305 (* y 0.813008))\n             (- (+ (* y 2.84553) (* x 4.47154)) 1.82238))\n            (- 1.57238 (+ (* y 2.03252) (* x 4.47154)))))))\n        (fmin\n         (fmin\n          (fmax\n           (-\n            (sqrt\n             (+\n              (pow (- (* x 8.13008) 5.7775) 2)\n              (pow (- (* y 8.13008) 2.775) 2)))\n            0.275)\n           (fmin\n            (fmax\n             (fmax\n              (fmax (- (* y 8.13008) 2.815) (- 2.725 (* y 8.13008)))\n              (- (* x 8.13008) 6.0525))\n             (- 5.5525 (* x 8.13008)))\n            (fmax\n             (fmax\n              (-\n               (sqrt\n                (+\n                 (pow (- (* x 8.13008) 5.7775) 2)\n                 (pow (- (* y 8.13008) 2.775) 2)))\n               0.275)\n              (-\n               (fmin\n                (fmax\n                 (fmax\n                  (- (* y 5.28455) 1.80375)\n                  (- (* x 2.23577) (+ (* y 1.21951) 1.30319)))\n                 (- 2.92819 (+ (* x 2.23577) (* y 4.06504))))\n                (fmax\n                 (fmax\n                  (- 1.80375 (* y 5.28455))\n                  (- (+ (* x 2.23577) (* y 4.06504)) 2.92819))\n                 (- (+ (* y 1.21951) 1.30319) (* x 2.23577))))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (- (* x 8.13008) 5.7775) 2)\n                (pow (- (* y 8.13008) 2.775) 2)))))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- 2.5 (* y 8.13008)) (- (* y 8.13008) 2.775))\n             (- (* x 8.13008) 4.6525))\n            (- 4.5525 (* x 8.13008)))\n           (fmax\n            (fmax\n             (fmax (- 2.5 (* y 8.13008)) (- (* y 8.13008) 3.5))\n             (- (* x 8.13008) 4.2025))\n            (- 4.1025 (* x 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (* y 8.13008) 3.05) (- (* x 8.13008) 4.6525))\n              (- 4.1025 (* x 8.13008)))\n             (- 2.775 (* y 8.13008)))\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 2.775) 2)\n               (pow (- (* x 8.13008) 4.3775) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 2.775) 2)\n              (pow (- (* x 8.13008) 4.3775) 2)))\n            0.275))\n          (fmin\n           (fmax\n            (fmax\n             (-\n              (fmin\n               (fmax\n                (fmax\n                 (- (+ 0.300176 (* y 2.23577)) (* x 2.27642))\n                 (- (* x 4.5122) 2.26024))\n                (- 1.80744 (* (+ x y) 2.23577)))\n               (fmax\n                (fmax (- (* (+ x y) 2.23577) 1.80744) (- 2.26024 (* x 4.5122)))\n                (- (* x 2.27642) (+ 0.300176 (* y 2.23577))))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 2.775) 2)\n                (pow (- (* x 8.13008) 3.7975) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 2.775) 2)\n               (pow (- (* x 8.13008) 3.7975) 2)))\n             0.275))\n           (fmax\n            (fmax\n             (fmax (- 2.5 (* y 8.13008)) (- (* y 8.13008) 3.05))\n             (- (* x 8.13008) 3.3975))\n            (- 3.2975 (* x 8.13008))))))))\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (-\n           (sqrt\n            (+ (pow (- (* y 8.13008) 3.2) 2) (pow (- (* x 8.13008) 3.3475) 2)))\n           0.075)\n          (fmax\n           (-\n            (fmin\n             (fmax\n              (fmax\n               (fmax (- 2.725 (* y 8.13008)) (- (* y 8.13008) 2.8875))\n               (- (+ 0.5175 (* x 5.42005))))\n              (+ 0.355 (* x 5.42005)))\n             (-\n              (sqrt\n               (+\n                (pow (- 2.885 (* y 8.13008)) 2)\n                (pow (- (+ 0.346667 (* x 3.61337))) 2)))\n              0.0625)))\n           (-\n            (sqrt\n             (+\n              (pow (- 2.8875 (* y 8.13008)) 2)\n              (pow (- (+ 0.5175 (* x 5.42005))) 2)))\n            0.1625)))\n         (fmin\n          (fmax\n           (-\n            (fmin\n             (fmax\n              (fmax\n               (fmax (- (* y 8.13008) 2.825) (- 2.6625 (* y 8.13008)))\n               (+ 0.5175 (* x 5.42005)))\n              (- (+ 0.68 (* x 5.42005))))\n             (-\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 2.665) 2)\n                (pow (+ 0.343334 (* x 3.61337)) 2)))\n              0.0625)))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 2.6625) 2)\n              (pow (+ 0.5175 (* x 5.42005)) 2)))\n            0.1625))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- 2.5 (* y 8.13008)) (- (* y 8.13008) 3.05))\n             (+ 1.12 (* x 8.13008)))\n            (- (+ 1.22 (* x 8.13008))))\n           (fmax\n            (fmax\n             (fmax (- (* y 8.13008) 3.05) (- 2.775 (* y 8.13008)))\n             (+ 1.57 (* x 8.13008)))\n            (- (+ 1.67 (* x 8.13008)))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- 2.5 (* y 8.13008)) (- (* y 8.13008) 2.775))\n              (+ 1.12 (* x 8.13008)))\n             (- (+ 1.67 (* x 8.13008))))\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 2.775) 2)\n               (pow (+ 1.395 (* x 8.13008)) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 2.775) 2)\n              (pow (+ 1.395 (* x 8.13008)) 2)))\n            0.275))\n          (fmax\n           (fmax\n            (fmax (- 2.5 (* y 8.13008)) (- (* y 8.13008) 2.85))\n            (+ 1.77 (* x 8.13008)))\n           (- (+ 1.87 (* x 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 2.5 (* y 8.13008)) (- (* y 8.13008) 2.85))\n            (+ 2.02 (* x 8.13008)))\n           (- (+ 2.12 (* x 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax\n                (-\n                 (fmin\n                  (fmax\n                   (fmax\n                    (- (+ 0.0958748 (* x 2.84553)) (* y 0.813008))\n                    (- 1.26444 (+ (* x 1.82927) (* y 4.06504))))\n                   (- (* y 4.87805) (+ (* x 1.01626) 1.55781)))\n                  (fmax\n                   (fmax\n                    (- (+ (* x 1.01626) 1.55781) (* y 4.87805))\n                    (- (+ (* x 1.82927) (* y 4.06504)) 1.26444))\n                   (- (* y 0.813008) (+ 0.095875 (* x 2.84553))))))\n                (- (* y 8.13008) 2.575))\n               (- 2.35 (* y 8.13008)))\n              (- (* x 8.13008) 0.5475))\n             (- 0.3975 (* x 8.13008)))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 2.71003) 0.858333) 2)\n               (pow (- (* x 8.13008) 0.4725) 2)))\n             0.075))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 2.575) 2)\n              (pow (- (* x 8.13008) 0.4975) 2)))\n            0.075)))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (-\n             (fmin\n              (fmax\n               (fmax\n                (- (* y 2.23577) (+ 0.737225 (* x 2.27642)))\n                (- (* x 4.5122) 0.203962))\n               (- 0.788562 (* (+ x y) 2.23577)))\n              (fmax\n               (fmax\n                (- (* (+ x y) 2.23577) 0.788562)\n                (- 0.203962 (* x 4.5122)))\n               (- (+ 0.737225 (* x 2.27642)) (* y 2.23577)))))\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 2.775) 2)\n               (pow (- (* x 8.13008) 0.0924997) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 2.775) 2)\n              (pow (- (* x 8.13008) 0.0924997) 2)))\n            0.275))\n          (fmax\n           (fmax\n            (fmax (- 2.5 (* y 8.13008)) (- (* y 8.13008) 3.05))\n            (+ 0.3075 (* x 8.13008)))\n           (- (+ 0.4075 (* x 8.13008)))))\n         (fmin\n          (-\n           (sqrt\n            (+\n             (pow (- (* y 8.13008) 3.2) 2)\n             (pow (+ 0.357501 (* x 8.13008)) 2)))\n           0.075)\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- 2.5 (* y 8.13008)) (- (* y 8.13008) 3.5))\n             (+ 3.845 (* x 8.13008)))\n            (- (+ 3.945 (* x 8.13008))))\n           (fmax\n            (fmax\n             (fmax (- (* y 8.13008) 2.825) (- 2.5 (* y 8.13008)))\n             (+ 4.07 (* x 8.13008)))\n            (- (+ 4.17 (* x 8.13008)))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 2.5 (* y 8.13008)) (- (* y 8.13008) 3.05))\n            (+ 4.52 (* x 8.13008)))\n           (- (+ 4.62 (* x 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- (* y 8.13008) 3.05) (- 2.825 (* y 8.13008)))\n               (+ 4.07 (* x 8.13008)))\n              (- (+ 4.62 (* x 8.13008))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 2.775) 2)\n                (pow (+ 4.345 (* x 8.13008)) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 2.775) 2)\n               (pow (+ 4.345 (* x 8.13008)) 2)))\n             0.275))\n           (fmax\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 2.775) 2)\n               (pow (+ 4.995 (* x 8.13008)) 2)))\n             0.275)\n            (fmin\n             (fmax\n              (fmax\n               (fmax (- (* y 8.13008) 2.815) (- 2.725 (* y 8.13008)))\n               (+ 4.72 (* x 8.13008)))\n              (- (+ 5.22 (* x 8.13008))))\n             (fmax\n              (fmax\n               (-\n                (sqrt\n                 (+\n                  (pow (- (* y 8.13008) 2.775) 2)\n                  (pow (+ 4.995 (* x 8.13008)) 2)))\n                0.275)\n               (-\n                (fmin\n                 (fmax\n                  (fmax\n                   (- (* y 5.28455) 1.80375)\n                   (- (+ 1.65925 (* x 2.23577)) (* y 1.21951)))\n                  (- (+ (+ 0.03425 (* x 2.23577)) (* y 4.06504))))\n                 (fmax\n                  (fmax\n                   (- 1.80375 (* y 5.28455))\n                   (+ (+ 0.03425 (* x 2.23577)) (* y 4.06504)))\n                  (- (* y 1.21951) (+ 1.65925 (* x 2.23577)))))))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 2.775) 2)\n                 (pow (+ 4.995 (* x 8.13008)) 2)))))))))\n         (fmin\n          (fmax\n           (fmax\n            (- 0.25 (* y 0.813008))\n            (- (+ 3.716 (* x 4.47154)) (* y 2.03252)))\n           (- (* y 2.84553) (+ 4.021 (* x 4.47154))))\n          (fmin\n           (fmax\n            (fmax\n             (- (* y 0.813008) 0.25)\n             (- (+ 4.021 (* x 4.47154)) (* y 2.84553)))\n            (- (* y 2.03252) (+ 3.716 (* x 4.47154))))\n           (fmax\n            (fmax\n             (- (* y 0.813008) 0.305)\n             (- (+ 4.021 (* x 4.47154)) (* y 2.84553)))\n            (- (* y 2.03252) (+ 3.771 (* x 4.47154)))))))))))\n    (fmin\n     (fmin\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- 0.305 (* y 0.813008))\n            (- (* y 2.84553) (+ 4.021 (* x 4.47154))))\n           (- (+ 3.771 (* x 4.47154)) (* y 2.03252)))\n          (fmax\n           (fmax\n            (- 0.25 (* y 0.813008))\n            (- (+ (+ (* y 2.03252) 2.521) (* x 4.47154))))\n           (+ (+ 2.216 (* y 2.84553)) (* x 4.47154))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 2.5 (* y 8.13008)) (- (* y 8.13008) 3.025))\n            (+ 2.27 (* x 8.13008)))\n           (- (+ 2.37 (* x 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (+ 2.37 (* x 8.13008))) (- (* y 8.13008) 3.15))\n              (- 2.85 (* y 8.13008)))\n             (+ 1.72 (* x 8.13008)))\n            (fmin\n             (fmax\n              (-\n               0.075\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 2.85) 2)\n                 (pow (+ 1.945 (* x 8.13008)) 2))))\n              (-\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 2.85) 2)\n                 (pow (+ 1.945 (* x 8.13008)) 2)))\n               0.175))\n             (fmax\n              (-\n               0.075\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 2.85) 2)\n                 (pow (+ 2.195 (* x 8.13008)) 2))))\n              (-\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 2.85) 2)\n                 (pow (+ 2.195 (* x 8.13008)) 2)))\n               0.175))))\n           (fmax\n            (fmax\n             (- 0.195 (* y 0.813008))\n             (- (+ 2.42975 (* x 4.47154)) (* y 1.82927)))\n            (- (* y 2.64228) (+ 2.67975 (* x 4.47154)))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (+ 2.67975 (* x 4.47154)) (* y 2.64228))\n            (- (* y 1.82927) (+ 2.42975 (* x 4.47154))))\n           (- (* y 0.813008) 0.195))\n          (fmax\n           (fmax\n            (- (+ 2.67975 (* x 4.47154)) (* y 2.64228))\n            (- (* y 0.813008) 0.25))\n           (- (* y 1.82927) (+ 2.48475 (* x 4.47154)))))\n         (fmin\n          (fmax\n           (fmax\n            (- (* y 2.64228) (+ 2.67975 (* x 4.47154)))\n            (- (+ 2.48475 (* x 4.47154)) (* y 1.82927)))\n           (- 0.25 (* y 0.813008)))\n          (fmin\n           (fmax\n            (fmax\n             (- 0.25 (* y 0.813008))\n             (- (+ 2.42975 (* x 4.47154)) (* y 1.82927)))\n            (- (* y 2.64228) (+ 2.73475 (* x 4.47154))))\n           (fmax\n            (fmax\n             (- (* y 0.813008) 0.25)\n             (- (* y 1.82927) (+ 2.42975 (* x 4.47154))))\n            (- (+ 2.73475 (* x 4.47154)) (* y 2.64228)))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (* y 0.813008) 0.305)\n            (- (* y 1.82927) (+ 2.48475 (* x 4.47154))))\n           (- (+ 2.73475 (* x 4.47154)) (* y 2.64228)))\n          (fmax\n           (fmax\n            (- 0.305 (* y 0.813008))\n            (- (+ 2.48475 (* x 4.47154)) (* y 1.82927)))\n           (- (* y 2.64228) (+ 2.73475 (* x 4.47154)))))\n         (fmin\n          (fmax\n           (fmax\n            (- 0.25 (* y 0.813008))\n            (- (+ (+ 1.35975 (* y 1.82927)) (* x 4.47154))))\n           (+ (+ 1.05475 (* y 2.64228)) (* x 4.47154)))\n          (fmin\n           (fmax\n            (fmax\n             (- (* y 0.813008) 0.25)\n             (+ (+ 1.35975 (* y 1.82927)) (* x 4.47154)))\n            (- (+ (+ 1.05475 (* y 2.64228)) (* x 4.47154))))\n           (fmax\n            (fmax\n             (- (* y 0.813008) 0.305)\n             (- (+ (+ 1.05475 (* y 2.64228)) (* x 4.47154))))\n            (+ (+ 1.30475 (* y 1.82927)) (* x 4.47154))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- 0.305 (* y 0.813008))\n            (+ (+ 1.05475 (* y 2.64228)) (* x 4.47154)))\n           (- (+ (+ 1.30475 (* y 1.82927)) (* x 4.47154))))\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 0.85) (- (+ 4.725 (* x 8.13008))))\n            (- (+ 0.0749998 (* y 8.13008))))\n           (+ 4.625 (* x 8.13008))))\n         (fmin\n          (fmax\n           (-\n            0.175\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 0.575) 2)\n              (pow (+ 4.45 (* x 8.13008)) 2))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 0.575) 2)\n              (pow (+ 4.45 (* x 8.13008)) 2)))\n            0.275))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- 0.3 (* y 8.13008)) (- (* y 8.13008) 0.85))\n             (+ 4.825 (* x 8.13008)))\n            (- (+ 4.925 (* x 8.13008))))\n           (fmax\n            (fmax\n             (fmax (- (* y 8.13008) 0.85) (- 0.575 (* y 8.13008)))\n             (+ 5.275 (* x 8.13008)))\n            (- (+ 5.375 (* x 8.13008)))))))))\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- 0.3 (* y 8.13008)) (- (* y 8.13008) 0.575))\n              (+ 4.825 (* x 8.13008)))\n             (- (+ 5.375 (* x 8.13008))))\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 0.575) 2)\n               (pow (+ 5.1 (* x 8.13008)) 2)))))\n           (-\n            (sqrt\n             (+ (pow (- (* y 8.13008) 0.575) 2) (pow (+ 5.1 (* x 8.13008)) 2)))\n            0.275))\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 1.3) (- 0.3 (* y 8.13008)))\n            (- (+ 6.275 (* x 8.13008))))\n           (+ 6.175 (* x 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 0.85) (- 0.75 (* y 8.13008)))\n            (- (+ 6.45 (* x 8.13008))))\n           (+ 6.275 (* x 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- 0.3 (* y 8.13008)) (- (+ 6.45 (* x 8.13008))))\n             (+ 6.275 (* x 8.13008)))\n            (- (* y 8.13008) 0.4))\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- (* y 8.13008) 1.3) (- 0.3 (* y 8.13008)))\n               (+ 6.45 (* x 8.13008)))\n              (- (+ 7.175 (* x 8.13008))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 0.575) 2)\n                (pow (- (+ 6.45 (* x 8.13008))) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 0.575) 2)\n               (pow (- (+ 6.45 (* x 8.13008))) 2)))\n             0.275)))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 0.3 (* y 8.13008)) (+ 6.8 (* x 8.13008)))\n            (- (* y 8.13008) 0.625))\n           (- (+ 6.9 (* x 8.13008))))\n          (fmax\n           (fmax\n            (fmax (- 0.3 (* y 8.13008)) (- (* y 8.13008) 0.85))\n            (+ 7.25 (* x 8.13008)))\n           (- (+ 7.35 (* x 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 0.3 (* y 8.13008)) (- (* y 8.13008) 0.575))\n            (+ 1.025 (* x 8.13008)))\n           (- (+ 1.125 (* x 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (* y 8.13008) 1.3) (- 0.3 (* y 8.13008)))\n             (+ 1.475 (* x 8.13008)))\n            (- (+ 1.575 (* x 8.13008))))\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- (* y 8.13008) 0.85) (- 0.575 (* y 8.13008)))\n               (+ 1.025 (* x 8.13008)))\n              (- (+ 1.575 (* x 8.13008))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 0.575) 2)\n                (pow (+ 1.3 (* x 8.13008)) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 0.575) 2)\n               (pow (+ 1.3 (* x 8.13008)) 2)))\n             0.275))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 1.3) (- 0.55 (* y 8.13008)))\n            (+ 1.825 (* x 8.13008)))\n           (- (+ 1.925 (* x 8.13008))))\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 0.95) (- 0.85 (* y 8.13008)))\n            (+ 1.675 (* x 8.13008)))\n           (- (+ 2.075 (* x 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (* y 8.13008) 0.55) (- 0.3 (* y 8.13008)))\n              (+ 1.675 (* x 8.13008)))\n             (- (+ 2.075 (* x 8.13008))))\n            (-\n             0.15\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 0.55) 2)\n               (pow (+ 1.675 (* x 8.13008)) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 0.55) 2)\n              (pow (+ 1.675 (* x 8.13008)) 2)))\n            0.25))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- 0.3 (* y 8.13008)) (- (* y 8.13008) 0.625))\n             (+ 2.875 (* x 8.13008)))\n            (- (+ 2.975 (* x 8.13008))))\n           (fmax\n            (fmax\n             (fmax (- 0.3 (* y 8.13008)) (- (* y 8.13008) 0.85))\n             (+ 3.325 (* x 8.13008)))\n            (- (+ 3.425 (* x 8.13008)))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (* y 8.13008) 0.85) (- 0.625 (* y 8.13008)))\n              (+ 2.875 (* x 8.13008)))\n             (- (+ 3.425 (* x 8.13008))))\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 0.575) 2)\n               (pow (+ 3.15 (* x 8.13008)) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 0.575) 2)\n              (pow (+ 3.15 (* x 8.13008)) 2)))\n            0.275))\n          (fmin\n           (fmax\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 0.575) 2)\n               (pow (+ 3.8 (* x 8.13008)) 2))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 0.575) 2)\n               (pow (+ 3.8 (* x 8.13008)) 2)))\n             0.275))\n           (fmax\n            (fmax\n             (fmax (- 1.4 (* y 8.13008)) (- (* y 8.13008) 1.95))\n             (- (* x 8.13008) 5.958))\n            (- 5.858 (* x 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (- 1.725 (* y 8.13008))\n               (-\n                0.175\n                (sqrt\n                 (+\n                  (pow (- (* x 8.13008) 6.133) 2)\n                  (pow (- (* y 8.13008) 1.675) 2)))))\n              (-\n               (sqrt\n                (+\n                 (pow (- (* x 8.13008) 6.133) 2)\n                 (pow (- (* y 8.13008) 1.675) 2)))\n               0.275))\n             (- (* x 8.13008) 6.408))\n            (- (* y 8.13008) 1.95))\n           (- 5.858 (* x 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (* x 8.13008) 5.733) (- 5.633 (* x 8.13008)))\n             (- 1.4 (* y 8.13008)))\n            (- (* y 8.13008) 1.95))\n           (-\n            (sqrt\n             (+ (pow (- (* y 8.13008) 2.1) 2) (pow (- (* x 8.13008) 5.683) 2)))\n            0.075)))))))\n     (fmin\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 1.75) (- (* x 8.13008) 5.508))\n            (- 5.408 (* x 8.13008)))\n           (- 1.4 (* y 8.13008)))\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 1.75) (- (* x 8.13008) 5.258))\n            (- 5.158 (* x 8.13008)))\n           (- 1.4 (* y 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 1.925) (- (* x 8.13008) 5.008))\n            (- 4.908 (* x 8.13008)))\n           (- 1.4 (* y 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- 4.908 (* x 8.13008)) (- (* y 8.13008) 2.05))\n              (- 1.75 (* y 8.13008)))\n             (- (* x 8.13008) 5.558))\n            (fmin\n             (fmax\n              (-\n               0.075\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 1.75) 2)\n                 (pow (- (* x 8.13008) 5.333) 2))))\n              (-\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 1.75) 2)\n                 (pow (- (* x 8.13008) 5.333) 2)))\n               0.175))\n             (fmax\n              (-\n               0.075\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 1.75) 2)\n                 (pow (- (* x 8.13008) 5.083) 2))))\n              (-\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 1.75) 2)\n                 (pow (- (* x 8.13008) 5.083) 2)))\n               0.175))))\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (+ 6.8 (* x 8.13008)) (- (* y 8.13008) 0.85))\n               (- 0.625 (* y 8.13008)))\n              (- (+ 7.35 (* x 8.13008))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 0.575) 2)\n                (pow (+ 7.075 (* x 8.13008)) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 0.575) 2)\n               (pow (+ 7.075 (* x 8.13008)) 2)))\n             0.275)))))\n        (fmin\n         (fmin\n          (fmax\n           (-\n            (sqrt\n             (+\n              (pow (+ 7.725 (* x 8.13008)) 2)\n              (pow (- (* y 8.13008) 0.575) 2)))\n            0.275)\n           (fmin\n            (fmax\n             (fmax\n              (fmax (+ 7.45 (* x 8.13008)) (- (+ 7.95 (* x 8.13008))))\n              (- (* y 8.13008) 0.615))\n             (- 0.525 (* y 8.13008)))\n            (fmax\n             (fmax\n              (-\n               (sqrt\n                (+\n                 (pow (+ 7.725 (* x 8.13008)) 2)\n                 (pow (- (* y 8.13008) 0.575) 2)))\n               0.275)\n              (-\n               (fmin\n                (fmax\n                 (fmax\n                  (- (* y 5.28455) 0.37375)\n                  (- (+ 2.08 (* x 2.23577)) (* y 1.21951)))\n                 (- (+ (+ 1.885 (* x 2.23577)) (* y 4.06504))))\n                (fmax\n                 (fmax\n                  (- 0.37375 (* y 5.28455))\n                  (+ (+ 1.885 (* x 2.23577)) (* y 4.06504)))\n                 (- (* y 1.21951) (+ 2.08 (* x 2.23577)))))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (+ 7.725 (* x 8.13008)) 2)\n                (pow (- (* y 8.13008) 0.575) 2)))))))\n          (fmax\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 1.675) 2)\n              (pow (- (* x 8.13008) 6.783) 2)))\n            0.275)\n           (fmin\n            (fmax\n             (fmax\n              (fmax (- (* y 8.13008) 1.715) (- 1.625 (* y 8.13008)))\n              (- (* x 8.13008) 7.058))\n             (- 6.558 (* x 8.13008)))\n            (fmax\n             (fmax\n              (-\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 1.675) 2)\n                 (pow (- (* x 8.13008) 6.783) 2)))\n               0.275)\n              (-\n               (fmin\n                (fmax\n                 (fmax\n                  (- (* y 5.28455) 1.08875)\n                  (- (* x 2.23577) (+ (* y 1.21951) 1.7447)))\n                 (- 2.6547 (+ (* x 2.23577) (* y 4.06504))))\n                (fmax\n                 (fmax\n                  (- (+ (* x 2.23577) (* y 4.06504)) 2.6547)\n                  (- (+ (* y 1.21951) 1.7447) (* x 2.23577)))\n                 (- 1.08875 (* y 5.28455))))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 1.675) 2)\n                (pow (- (* x 8.13008) 6.783) 2))))))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 1.725) (- 1.4 (* y 8.13008)))\n            (- (* x 8.13008) 6.408))\n           (- 6.308 (* x 8.13008)))\n          (fmin\n           (fmax\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 1.675) 2)\n               (pow (- (* x 8.13008) 2.775) 2)))\n             0.275)\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 1.675) 2)\n               (pow (- (* x 8.13008) 2.775) 2)))))\n           (fmax\n            (fmax\n             (- 0.14 (* y 0.813008))\n             (- (* x 4.47154) (+ 0.8325 (* y 2.03252))))\n            (- (+ 0.6375 (* y 2.84553)) (* x 4.47154)))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (* x 4.47154) (+ 0.6375 (* y 2.84553)))\n            (- (+ 0.8325 (* y 2.03252)) (* x 4.47154)))\n           (- (* y 0.813008) 0.14))\n          (fmax\n           (fmax\n            (- (* x 4.47154) (+ 0.6375 (* y 2.84553)))\n            (- (* y 0.813008) 0.195))\n           (- (+ 0.7775 (* y 2.03252)) (* x 4.47154))))\n         (fmin\n          (fmax\n           (fmax\n            (- (+ 0.6375 (* y 2.84553)) (* x 4.47154))\n            (- (* x 4.47154) (+ 0.7775 (* y 2.03252))))\n           (- 0.195 (* y 0.813008)))\n          (fmin\n           (fmax\n            (fmax\n             (- 0.14 (* y 0.813008))\n             (- 1.4775 (+ (* y 2.03252) (* x 4.47154))))\n            (- (+ (* y 2.84553) (* x 4.47154)) 1.6725))\n           (fmax\n            (fmax\n             (- (* y 0.813008) 0.14)\n             (- 1.6725 (+ (* y 2.84553) (* x 4.47154))))\n            (- (+ (* y 2.03252) (* x 4.47154)) 1.4775)))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (* y 0.813008) 0.195)\n            (- 1.6725 (+ (* y 2.84553) (* x 4.47154))))\n           (- (+ (* y 2.03252) (* x 4.47154)) 1.5325))\n          (fmin\n           (fmax\n            (fmax\n             (- 0.195 (* y 0.813008))\n             (- (+ (* y 2.84553) (* x 4.47154)) 1.6725))\n            (- 1.5325 (+ (* y 2.03252) (* x 4.47154))))\n           (fmax\n            (fmax\n             (- 0.14 (* y 0.813008))\n             (- (* x 4.47154) (+ 0.5575 (* y 2.03252))))\n            (- (+ 0.3625 (* y 2.84553)) (* x 4.47154)))))\n         (fmin\n          (fmax\n           (fmax\n            (- (* y 0.813008) 0.14)\n            (- (* x 4.47154) (+ 0.3625 (* y 2.84553))))\n           (- (+ 0.5575 (* y 2.03252)) (* x 4.47154)))\n          (fmin\n           (fmax\n            (fmax\n             (- (* y 0.813008) 0.195)\n             (- (* x 4.47154) (+ 0.3625 (* y 2.84553))))\n            (- (+ 0.5025 (* y 2.03252)) (* x 4.47154)))\n           (fmax\n            (fmax\n             (- 0.195 (* y 0.813008))\n             (- (+ 0.3625 (* y 2.84553)) (* x 4.47154)))\n            (- (* x 4.47154) (+ 0.5025 (* y 2.03252)))))))))\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- 0.14 (* y 0.813008))\n            (- 1.2025 (+ (* y 2.03252) (* x 4.47154))))\n           (- (+ (* y 2.84553) (* x 4.47154)) 1.3975))\n          (fmax\n           (fmax\n            (- (* y 0.813008) 0.14)\n            (- 1.3975 (+ (* y 2.84553) (* x 4.47154))))\n           (- (+ (* y 2.03252) (* x 4.47154)) 1.2025)))\n         (fmin\n          (fmax\n           (fmax\n            (- (* y 0.813008) 0.195)\n            (- 1.3975 (+ (* y 2.84553) (* x 4.47154))))\n           (- (+ (* y 2.03252) (* x 4.47154)) 1.2575))\n          (fmin\n           (fmax\n            (fmax\n             (- 0.195 (* y 0.813008))\n             (- (+ (* y 2.84553) (* x 4.47154)) 1.3975))\n            (- 1.2575 (+ (* y 2.03252) (* x 4.47154))))\n           (fmax\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 1.675) 2)\n               (pow (- (* x 8.13008) 0.224999) 2))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 1.675) 2)\n               (pow (- (* x 8.13008) 0.224999) 2)))\n             0.275)))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (- 1.4 (* y 8.13008))\n              (-\n               (fmin\n                (fmin\n                 (fmin\n                  (fmax\n                   (fmax (- (* y 4.06504) 1.2) (- (* x 4.06504) 2.104))\n                   (- 3.054 (* (+ x y) 4.06504)))\n                  (fmax\n                   (fmax (- (* (+ x y) 4.06504) 3.054) (- 2.104 (* x 4.06504)))\n                   (- 1.2 (* y 4.06504))))\n                 (fmin\n                  (fmax\n                   (fmax\n                    (- (* x 8.13008) (+ (* y 0.813008) 3.968))\n                    (- 1.8858 (+ (* y 2.60163) (* x 2.84553))))\n                   (- (+ 1.7272 (* y 3.41463)) (* x 5.28455)))\n                  (fmax\n                   (fmax\n                    (- (* x 5.28455) (+ 1.7272 (* y 3.41463)))\n                    (- (+ (* y 2.60163) (* x 2.84553)) 1.8858))\n                   (- (+ (* y 0.813008) 3.968) (* x 8.13008)))))\n                (fmin\n                 (fmin\n                  (fmax\n                   (fmax (- 0.351 (* y 2.19512)) (- 1.2978 (* x 2.84553)))\n                   (- (+ (* y 2.19512) (* x 2.84553)) 1.7433))\n                  (fmax\n                   (fmax\n                    (- 1.7433 (+ (* y 2.19512) (* x 2.84553)))\n                    (- (* x 2.84553) 1.2978))\n                   (- (* y 2.19512) 0.351)))\n                 (fmin\n                  (fmax\n                   (fmax\n                    (- (* y 3.25203) 0.96)\n                    (- (* x 4.47154) (+ 1.2994 (* y 3.25203))))\n                   (- 2.0394 (* x 4.47154)))\n                  (fmax\n                   (fmax\n                    (- (* x 4.47154) 2.0394)\n                    (- (+ 1.2994 (* y 3.25203)) (* x 4.47154)))\n                   (- 0.96 (* y 3.25203))))))))\n             (- (* y 8.13008) 2.4))\n            (- (* x 8.13008) 4.108))\n           (- 3.608 (* x 8.13008)))\n          (fmax\n           (fmax\n            (fmax (- 1.4 (* y 8.13008)) (- (* y 8.13008) 1.95))\n            (- (* x 8.13008) 3.25))\n           (- 3.15 (* x 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- 1.4 (* y 8.13008)) (- (* y 8.13008) 1.95))\n              (- (* x 11.6144) 5.05))\n             (- 4.5 (* x 11.6144)))\n            (-\n             0.45\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 1.4) 2)\n               (pow (- (* x 14.518) 6.3125) 2)))))\n           (-\n            (sqrt\n             (+ (pow (- (* y 8.13008) 1.4) 2) (pow (- (* x 11.6144) 5.05) 2)))\n            0.55))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (* y 8.13008) 1.95) (- (+ 2.55 (* x 8.13008))))\n             (+ 2.375 (* x 8.13008)))\n            (- 1.85 (* y 8.13008)))\n           (fmax\n            (fmax\n             (fmax (- 1.4 (* y 8.13008)) (- (+ 2.55 (* x 8.13008))))\n             (- (* y 8.13008) 1.5))\n            (+ 2.375 (* x 8.13008)))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- 1.4 (* y 8.13008)) (- (* y 8.13008) 2.4))\n              (+ 2.55 (* x 8.13008)))\n             (- (+ 3.275 (* x 8.13008))))\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 1.675) 2)\n               (pow (- (+ 2.55 (* x 8.13008))) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 1.675) 2)\n              (pow (- (+ 2.55 (* x 8.13008))) 2)))\n            0.275))\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 2.4) (- 2.3 (* y 8.13008)))\n            (+ 3.6 (* x 8.13008)))\n           (- (+ 4.1 (* x 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 1.4 (* y 8.13008)) (- (* y 8.13008) 1.5))\n            (+ 3.6 (* x 8.13008)))\n           (- (+ 4.1 (* x 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (+ 3.8 (* x 8.13008)) (- 1.4 (* y 8.13008)))\n             (- (* y 8.13008) 2.4))\n            (- (+ 3.9 (* x 8.13008))))\n           (fmax\n            (fmax\n             (- 0.14 (* y 0.813008))\n             (- (+ 3.1825 (* x 4.47154)) (* y 2.03252)))\n            (- (* y 2.84553) (+ 3.3775 (* x 4.47154)))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (* y 0.813008) 0.14)\n            (- (+ 3.3775 (* x 4.47154)) (* y 2.84553)))\n           (- (* y 2.03252) (+ 3.1825 (* x 4.47154))))\n          (fmin\n           (fmax\n            (fmax\n             (- (* y 0.813008) 0.195)\n             (- (+ 3.3775 (* x 4.47154)) (* y 2.84553)))\n            (- (* y 2.03252) (+ 3.2375 (* x 4.47154))))\n           (fmax\n            (fmax\n             (- 0.195 (* y 0.813008))\n             (- (* y 2.84553) (+ 3.3775 (* x 4.47154))))\n            (- (+ 3.2375 (* x 4.47154)) (* y 2.03252)))))\n         (fmin\n          (fmax\n           (fmax\n            (- 0.14 (* y 0.813008))\n            (- (+ (+ (* y 2.03252) 2.5375) (* x 4.47154))))\n           (+ (+ 2.3425 (* y 2.84553)) (* x 4.47154)))\n          (fmin\n           (fmax\n            (fmax\n             (- (* y 0.813008) 0.14)\n             (+ (+ (* y 2.03252) 2.5375) (* x 4.47154)))\n            (- (+ (+ 2.3425 (* y 2.84553)) (* x 4.47154))))\n           (fmax\n            (fmax\n             (- (* y 0.813008) 0.195)\n             (- (+ (+ 2.3425 (* y 2.84553)) (* x 4.47154))))\n            (+ (+ (* y 2.03252) 2.4825) (* x 4.47154)))))))))))\n   (fmin\n    (fmin\n     (fmin\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- 0.195 (* y 0.813008))\n            (+ (+ 2.3425 (* y 2.84553)) (* x 4.47154)))\n           (- (+ (+ (* y 2.03252) 2.4825) (* x 4.47154))))\n          (fmax\n           (fmax\n            (- 0.14 (* y 0.813008))\n            (- (+ 3.4575 (* x 4.47154)) (* y 2.03252)))\n           (- (* y 2.84553) (+ 3.6525 (* x 4.47154)))))\n         (fmin\n          (fmax\n           (fmax\n            (- (* y 0.813008) 0.14)\n            (- (+ 3.6525 (* x 4.47154)) (* y 2.84553)))\n           (- (* y 2.03252) (+ 3.4575 (* x 4.47154))))\n          (fmin\n           (fmax\n            (fmax\n             (- (* y 0.813008) 0.195)\n             (- (+ 3.6525 (* x 4.47154)) (* y 2.84553)))\n            (- (* y 2.03252) (+ 3.5125 (* x 4.47154))))\n           (fmax\n            (fmax\n             (- 0.195 (* y 0.813008))\n             (- (* y 2.84553) (+ 3.6525 (* x 4.47154))))\n            (- (+ 3.5125 (* x 4.47154)) (* y 2.03252))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 1.65 (* y 8.13008)) (+ 0.300001 (* x 8.13008)))\n            (- (* y 8.13008) 2.4))\n           (- (+ 0.400001 (* x 8.13008))))\n          (fmax\n           (fmax\n            (fmax (+ 0.150001 (* x 8.13008)) (- (* y 8.13008) 2.05))\n            (- 1.95 (* y 8.13008)))\n           (- (+ 0.550001 (* x 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (+ 0.150001 (* x 8.13008)) (- 1.4 (* y 8.13008)))\n              (- (+ 0.550001 (* x 8.13008))))\n             (- (* y 8.13008) 1.65))\n            (-\n             0.15\n             (sqrt\n              (+\n               (pow (+ 0.150001 (* x 8.13008)) 2)\n               (pow (- (* y 8.13008) 1.65) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 0.150001 (* x 8.13008)) 2)\n              (pow (- (* y 8.13008) 1.65) 2)))\n            0.25))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax\n                (-\n                 (fmin\n                  (fmax\n                   (fmax\n                    (- (+ 0.65875 (* x 2.84553)) (* y 0.813008))\n                    (- 0.281875 (+ (* x 1.82927) (* y 4.06504))))\n                   (- (* y 4.87805) (+ (* x 1.01626) 1.13813)))\n                  (fmax\n                   (fmax\n                    (- (+ (* x 1.01626) 1.13813) (* y 4.87805))\n                    (- (+ (* x 1.82927) (* y 4.06504)) 0.281875))\n                   (- (* y 0.813008) (+ 0.65875 (* x 2.84553))))))\n                (- (* y 8.13008) 1.475))\n               (- 1.25 (* y 8.13008)))\n              (+ 1.375 (* x 8.13008)))\n             (- (+ 1.525 (* x 8.13008))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 2.71003) 0.491667) 2)\n               (pow (+ 1.45 (* x 8.13008)) 2)))\n             0.075))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 1.475) 2)\n              (pow (+ 1.425 (* x 8.13008)) 2)))\n            0.075)))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (-\n            0.175\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 1.675) 2)\n              (pow (+ 1.9 (* x 8.13008)) 2))))\n           (-\n            (sqrt\n             (+ (pow (- (* y 8.13008) 1.675) 2) (pow (+ 1.9 (* x 8.13008)) 2)))\n            0.275))\n          (fmax\n           (fmax\n            (fmax (- 1.4 (* y 8.13008)) (- (* y 8.13008) 2.4))\n            (- (+ 2.375 (* x 8.13008))))\n           (+ 2.275 (* x 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (-\n                (sqrt\n                 (+\n                  (pow (- (* x 8.13008) 1.951) 2)\n                  (pow (- (* y 8.13008) 4.975) 2)))\n                0.275)\n               (- (* x 8.13008) 2.226))\n              (- 1.676 (* x 8.13008)))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (- (* x 8.13008) 1.951) 2)\n                (pow (- (* y 8.13008) 4.975) 2)))))\n            (- (* y 8.13008) 5.25))\n           (- 5.025 (* y 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (* y 8.13008) 5.05) (- (* x 8.13008) 1.556))\n             (- 1.456 (* x 8.13008)))\n            (- 4.7 (* y 8.13008)))\n           (fmax\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (- (+ 0.146856 (* x 8.13008)) (* y 2.32288)) 2)\n               (pow (- (* y 8.13008) 4.975) 2))))\n            (-\n             (sqrt\n              (+\n               (pow (- (+ 0.146856 (* x 8.13008)) (* y 2.32288)) 2)\n               (pow (- (* y 8.13008) 4.975) 2)))\n             0.275)))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (-\n                (fmin\n                 (fmax\n                  (fmax\n                   (- (+ 0.44765 (* x 2.84553)) (* y 0.813008))\n                   (- 2.27973 (+ (* x 1.82927) (* y 4.06504))))\n                  (- (* y 4.87805) (+ (* x 1.01626) 2.92488)))\n                 (fmax\n                  (fmax\n                   (- (+ (* x 1.01626) 2.92488) (* y 4.87805))\n                   (- (+ (* x 1.82927) (* y 4.06504)) 2.27973))\n                  (- (* y 0.813008) (+ 0.44765 (* x 2.84553))))))\n               (- (* y 8.13008) 4.775))\n              (- 4.55 (* y 8.13008)))\n             (- (* x 8.13008) 0.171))\n            (- 0.0209999 (* x 8.13008)))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 2.71003) 1.59167) 2)\n              (pow (- (* x 8.13008) 0.0959997) 2)))\n            0.075))\n          (-\n           (sqrt\n            (+\n             (pow (- (* y 8.13008) 4.775) 2)\n             (pow (- (* x 8.13008) 0.121) 2)))\n           0.075))\n         (fmin\n          (fmax\n           (fmax\n            (- 0.525 (* y 0.813008))\n            (- (+ (* y 2.84553) (* x 4.47154)) 4.12055))\n           (- 3.65055 (+ (* y 2.03252) (* x 4.47154))))\n          (fmin\n           (fmax\n            (fmax\n             (- (* x 4.47154) (+ 1.02555 (* y 2.03252)))\n             (- (+ 0.500551 (* y 2.84553)) (* x 4.47154)))\n            (- 0.47 (* y 0.813008)))\n           (fmax\n            (fmax\n             (- (* x 4.47154) (+ 0.500551 (* y 2.84553)))\n             (- (+ 1.02555 (* y 2.03252)) (* x 4.47154)))\n            (- (* y 0.813008) 0.47)))))))\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (* x 4.47154) (+ 0.500551 (* y 2.84553)))\n            (- (+ 0.970551 (* y 2.03252)) (* x 4.47154)))\n           (- (* y 0.813008) 0.525))\n          (fmax\n           (fmax\n            (- (+ 0.500551 (* y 2.84553)) (* x 4.47154))\n            (- (* x 4.47154) (+ 0.970552 (* y 2.03252))))\n           (- 0.525 (* y 0.813008))))\n         (fmin\n          (fmax\n           (fmax\n            (- 3.32055 (+ (* y 2.03252) (* x 4.47154)))\n            (- (+ (* y 2.84553) (* x 4.47154)) 3.84555))\n           (- 0.47 (* y 0.813008)))\n          (fmin\n           (fmax\n            (fmax\n             (- 3.84555 (+ (* y 2.84553) (* x 4.47154)))\n             (- (+ (* y 2.03252) (* x 4.47154)) 3.32055))\n            (- (* y 0.813008) 0.47))\n           (fmax\n            (fmax\n             (- 3.84555 (+ (* y 2.84553) (* x 4.47154)))\n             (- (+ (* y 2.03252) (* x 4.47154)) 3.37555))\n            (- (* y 0.813008) 0.525)))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (+ (* y 2.84553) (* x 4.47154)) 3.84555)\n            (- 3.37555 (+ (* y 2.03252) (* x 4.47154))))\n           (- 0.525 (* y 0.813008)))\n          (fmax\n           (fmax\n            (fmax (- 2.751 (* x 8.13008)) (- (* x 8.13008) 2.851))\n            (- (* y 8.13008) 5.7))\n           (- 4.7 (* y 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 5.15 (* y 8.13008)) (- 2.576 (* x 8.13008)))\n            (- (* x 8.13008) 2.751))\n           (- (* y 8.13008) 5.25))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- 2.576 (* x 8.13008)) (- (* x 8.13008) 2.751))\n             (- (* y 8.13008) 4.8))\n            (- 4.7 (* y 8.13008)))\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- 1.851 (* x 8.13008)) (- (* x 8.13008) 2.576))\n               (-\n                0.175\n                (sqrt\n                 (+\n                  (pow (- 2.576 (* x 8.13008)) 2)\n                  (pow (- (* y 8.13008) 4.975) 2)))))\n              (-\n               (sqrt\n                (+\n                 (pow (- 2.576 (* x 8.13008)) 2)\n                 (pow (- (* y 8.13008) 4.975) 2)))\n               0.275))\n             (- (* y 8.13008) 5.7))\n            (- 4.7 (* y 8.13008)))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* x 8.13008) 2.226) (- 2.126 (* x 8.13008)))\n            (- (* y 8.13008) 5.025))\n           (- 4.7 (* y 8.13008)))\n          (fmax\n           (fmax\n            (fmax (- (* x 8.13008) 1.776) (- 1.676 (* x 8.13008)))\n            (- 4.7 (* y 8.13008)))\n           (- (* y 8.13008) 5.25)))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 4.6 (* y 8.13008)) (+ 1.862 (* x 8.13008)))\n            (- (+ 1.962 (* x 8.13008))))\n           (- (* y 8.13008) 5.25))\n          (fmin\n           (-\n            (sqrt\n             (+ (pow (- (* y 8.13008) 5.4) 2) (pow (+ 1.912 (* x 8.13008)) 2)))\n            0.075)\n           (fmax\n            (fmax\n             (fmax (+ 2.662 (* x 8.13008)) (- (+ 2.762 (* x 8.13008))))\n             (- (* y 8.13008) 5.7))\n            (- 4.7 (* y 8.13008))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 5.15 (* y 8.13008)) (+ 2.487 (* x 8.13008)))\n            (- (+ 2.662 (* x 8.13008))))\n           (- (* y 8.13008) 5.25))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (* y 8.13008) 4.8) (+ 2.487 (* x 8.13008)))\n             (- (+ 2.662 (* x 8.13008))))\n            (- 4.7 (* y 8.13008)))\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (+ 1.762 (* x 8.13008)) (- (+ 2.487 (* x 8.13008))))\n               (-\n                0.175\n                (sqrt\n                 (+\n                  (pow (+ 2.487 (* x 8.13008)) 2)\n                  (pow (- (* y 8.13008) 4.975) 2)))))\n              (-\n               (sqrt\n                (+\n                 (pow (+ 2.487 (* x 8.13008)) 2)\n                 (pow (- (* y 8.13008) 4.975) 2)))\n               0.275))\n             (- (* y 8.13008) 5.7))\n            (- 4.7 (* y 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 5.05) (+ 2.882 (* x 8.13008)))\n            (- (+ 2.982 (* x 8.13008))))\n           (- 4.7 (* y 8.13008)))\n          (fmin\n           (fmax\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (- (+ 4.58486 (* x 8.13008)) (* y 2.32288)) 2)\n               (pow (- (* y 8.13008) 4.975) 2))))\n            (-\n             (sqrt\n              (+\n               (pow (- (+ 4.58486 (* x 8.13008)) (* y 2.32288)) 2)\n               (pow (- (* y 8.13008) 4.975) 2)))\n             0.275))\n           (fmax\n            (-\n             (sqrt\n              (+\n               (pow (+ 0.354001 (* x 8.13008)) 2)\n               (pow (- (* y 8.13008) 4.975) 2)))\n             0.275)\n            (fmin\n             (fmax\n              (fmax\n               (fmax\n                (+ 0.0790005 (* x 8.13008))\n                (- (+ 0.579001 (* x 8.13008))))\n               (- (* y 8.13008) 5.015))\n              (- 4.925 (* y 8.13008)))\n             (fmax\n              (fmax\n               (-\n                (sqrt\n                 (+\n                  (pow (+ 0.354001 (* x 8.13008)) 2)\n                  (pow (- (* y 8.13008) 4.975) 2)))\n                0.275)\n               (-\n                (fmin\n                 (fmax\n                  (fmax\n                   (- (+ 0.712975 (* x 2.23577)) (* y 1.21951))\n                   (- 2.34202 (+ (* x 2.23577) (* y 4.06504))))\n                  (- (* y 5.28455) 3.23375))\n                 (fmax\n                  (fmax\n                   (- (+ (* x 2.23577) (* y 4.06504)) 2.34202)\n                   (- (* y 1.21951) (+ 0.712975 (* x 2.23577))))\n                  (- 3.23375 (* y 5.28455))))))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (+ 0.354001 (* x 8.13008)) 2)\n                 (pow (- (* y 8.13008) 4.975) 2)))))))))))))\n     (fmin\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 0.987 (* x 8.13008)) (- (+ 1.087 (* x 8.13008))))\n            (- 4.7 (* y 8.13008)))\n           (- (* y 8.13008) 5.25))\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (+ 1.00286 (* x 11.6144)) (- (+ 1.55286 (* x 11.6144))))\n              (-\n               0.45\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 4.7) 2)\n                 (pow (+ 1.25357 (* x 14.518)) 2)))))\n             (-\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 4.7) 2)\n                (pow (+ 1.00286 (* x 11.6144)) 2)))\n              0.55))\n            (- 4.7 (* y 8.13008)))\n           (- (* y 8.13008) 5.25)))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 1.187 (* x 8.13008)) (- (+ 1.287 (* x 8.13008))))\n            (- 4.7 (* y 8.13008)))\n           (- (* y 8.13008) 5.25))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (+ 1.637 (* x 8.13008)) (- (+ 1.737 (* x 8.13008))))\n             (- 4.975 (* y 8.13008)))\n            (- (* y 8.13008) 5.25))\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (+ 1.187 (* x 8.13008)) (- (+ 1.737 (* x 8.13008))))\n               (-\n                0.175\n                (sqrt\n                 (+\n                  (pow (+ 1.462 (* x 8.13008)) 2)\n                  (pow (- (* y 8.13008) 4.975) 2)))))\n              (-\n               (sqrt\n                (+\n                 (pow (+ 1.462 (* x 8.13008)) 2)\n                 (pow (- (* y 8.13008) 4.975) 2)))\n               0.275))\n             (- 4.7 (* y 8.13008)))\n            (- (* y 8.13008) 4.975)))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- 4.325 (* y 8.13008)) (+ 1.587 (* x 8.13008)))\n              (- (+ 2.137 (* x 8.13008))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 4.6) 2)\n                (pow (+ 2.137 (* x 8.13008)) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 4.6) 2)\n               (pow (+ 2.137 (* x 8.13008)) 2)))\n             0.275))\n           (- (* y 8.13008) 4.6))\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 5.9) (- 5.8 (* y 8.13008)))\n            (- (* x 8.13008) 6.5305))\n           (- 6.0305 (* x 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 5.8 (* y 8.13008)) (- (* x 8.13008) 6.3305))\n            (- 6.2305 (* x 8.13008)))\n           (- (* y 8.13008) 6.8))\n          (fmin\n           (fmax\n            (fmax\n             (-\n              (fmin\n               (fmax\n                (fmax\n                 (- (* y 2.23577) (+ 0.263484 (* x 2.27642)))\n                 (- (* x 4.5122) 2.94178))\n                (- 3.05264 (* (+ x y) 2.23577)))\n               (fmax\n                (fmax (- (* (+ x y) 2.23577) 3.05264) (- 2.94178 (* x 4.5122)))\n                (- (+ 0.263484 (* x 2.27642)) (* y 2.23577)))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 6.075) 2)\n                (pow (- (* x 8.13008) 5.0255) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 6.075) 2)\n               (pow (- (* x 8.13008) 5.0255) 2)))\n             0.275))\n           (fmax\n            (fmax\n             (fmax (- 5.8 (* y 8.13008)) (- (* y 8.13008) 6.35))\n             (- (* x 8.13008) 4.6255))\n            (- 4.5255 (* x 8.13008)))))))\n       (fmin\n        (fmin\n         (fmin\n          (-\n           (sqrt\n            (+ (pow (- (* y 8.13008) 6.5) 2) (pow (- (* x 8.13008) 4.5755) 2)))\n           0.075)\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 6.35) (- 5.7 (* y 8.13008)))\n            (- (* x 8.13008) 4.4005))\n           (- 4.3005 (* x 8.13008))))\n         (fmin\n          (fmax\n           (-\n            0.175\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 6.075) 2)\n              (pow (- (* x 8.13008) 4.1255) 2))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 6.075) 2)\n              (pow (- (* x 8.13008) 4.1255) 2)))\n            0.275))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- (* x 8.13008) 4.4005) (- 5.425 (* y 8.13008)))\n               (- 3.8505 (* x 8.13008)))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (- (* x 8.13008) 4.1255) 2)\n                 (pow (- (* y 8.13008) 5.7) 2)))))\n             (-\n              (sqrt\n               (+\n                (pow (- (* x 8.13008) 4.1255) 2)\n                (pow (- (* y 8.13008) 5.7) 2)))\n              0.275))\n            (- (* y 8.13008) 5.7))\n           (fmax\n            (-\n             (sqrt\n              (+\n               (pow (+ 4.517 (* x 8.13008)) 2)\n               (pow (- (* y 8.13008) 4.975) 2)))\n             0.275)\n            (fmin\n             (fmax\n              (fmax\n               (fmax (+ 4.242 (* x 8.13008)) (- (+ 4.742 (* x 8.13008))))\n               (- (* y 8.13008) 5.015))\n              (- 4.925 (* y 8.13008)))\n             (fmax\n              (fmax\n               (-\n                (sqrt\n                 (+\n                  (pow (+ 4.517 (* x 8.13008)) 2)\n                  (pow (- (* y 8.13008) 4.975) 2)))\n                0.275)\n               (-\n                (fmin\n                 (fmax\n                  (fmax\n                   (- (+ 1.8578 (* x 2.23577)) (* y 1.21951))\n                   (- 1.1972 (+ (* x 2.23577) (* y 4.06504))))\n                  (- (* y 5.28455) 3.23375))\n                 (fmax\n                  (fmax\n                   (- (+ (* x 2.23577) (* y 4.06504)) 1.1972)\n                   (- (* y 1.21951) (+ 1.8578 (* x 2.23577))))\n                  (- 3.23375 (* y 5.28455))))))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (+ 4.517 (* x 8.13008)) 2)\n                 (pow (- (* y 8.13008) 4.975) 2))))))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 5.15 (* x 8.13008)) (- (+ 5.25 (* x 8.13008))))\n            (- 4.7 (* y 8.13008)))\n           (- (* y 8.13008) 5.25))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (+ 6.95 (* x 11.6144)) (- (+ 7.5 (* x 11.6144))))\n               (-\n                0.45\n                (sqrt\n                 (+\n                  (pow (- (* y 8.13008) 4.7) 2)\n                  (pow (+ 8.6875 (* x 14.518)) 2)))))\n              (-\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 4.7) 2)\n                 (pow (+ 6.95 (* x 11.6144)) 2)))\n               0.55))\n             (- 4.7 (* y 8.13008)))\n            (- (* y 8.13008) 5.25))\n           (fmax\n            (-\n             (sqrt\n              (+\n               (pow (+ 5.625 (* x 8.13008)) 2)\n               (pow (- (* y 8.13008) 4.975) 2)))\n             0.275)\n            (fmin\n             (fmax\n              (fmax\n               (fmax (+ 5.35 (* x 8.13008)) (- (+ 5.85 (* x 8.13008))))\n               (- (* y 8.13008) 5.015))\n              (- 4.925 (* y 8.13008)))\n             (fmax\n              (fmax\n               (-\n                (sqrt\n                 (+\n                  (pow (+ 5.625 (* x 8.13008)) 2)\n                  (pow (- (* y 8.13008) 4.975) 2)))\n                0.275)\n               (-\n                (fmin\n                 (fmax\n                  (fmax\n                   (- (+ 2.1625 (* x 2.23577)) (* y 1.21951))\n                   (- 0.8925 (+ (* x 2.23577) (* y 4.06504))))\n                  (- (* y 5.28455) 3.23375))\n                 (fmax\n                  (fmax\n                   (- (+ (* x 2.23577) (* y 4.06504)) 0.8925)\n                   (- (* y 1.21951) (+ 2.1625 (* x 2.23577))))\n                  (- 3.23375 (* y 5.28455))))))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (+ 5.625 (* x 8.13008)) 2)\n                 (pow (- (* y 8.13008) 4.975) 2)))))))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 6.05 (* x 8.13008)) (- (+ 6.15 (* x 8.13008))))\n            (- 4.7 (* y 8.13008)))\n           (- (* y 8.13008) 4.975))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (+ 6.5 (* x 8.13008)) (- (+ 6.6 (* x 8.13008))))\n             (- (* y 8.13008) 5.7))\n            (- 4.7 (* y 8.13008)))\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- (+ 6.6 (* x 8.13008))) (+ 6.05 (* x 8.13008)))\n               (-\n                0.175\n                (sqrt\n                 (+\n                  (pow (+ 6.325 (* x 8.13008)) 2)\n                  (pow (- (* y 8.13008) 4.975) 2)))))\n              (-\n               (sqrt\n                (+\n                 (pow (+ 6.325 (* x 8.13008)) 2)\n                 (pow (- (* y 8.13008) 4.975) 2)))\n               0.275))\n             (- 4.975 (* y 8.13008)))\n            (- (* y 8.13008) 5.25)))))))\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 6.8) (- 6.7 (* y 8.13008)))\n            (- (* x 8.13008) 6.5305))\n           (- 6.0305 (* x 8.13008)))\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 6.35) (- 5.7 (* y 8.13008)))\n            (- (* x 8.13008) 0.9705))\n           (- 0.8705 (* x 8.13008))))\n         (fmin\n          (fmax\n           (-\n            0.175\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 6.075) 2)\n              (pow (- (* x 8.13008) 0.695499) 2))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 6.075) 2)\n              (pow (- (* x 8.13008) 0.695499) 2)))\n            0.275))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- 5.425 (* y 8.13008)) (- (* x 8.13008) 0.9705))\n               (- 0.4205 (* x 8.13008)))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 5.7) 2)\n                 (pow (- (* x 8.13008) 0.695499) 2)))))\n             (-\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 5.7) 2)\n                (pow (- (* x 8.13008) 0.695499) 2)))\n              0.275))\n            (- (* y 8.13008) 5.7))\n           (fmax\n            (fmax\n             (fmax (- 5.8 (* y 8.13008)) (- (* y 8.13008) 6.35))\n             (- (* x 8.13008) 0.320499))\n            (- 0.220499 (* x 8.13008))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 6.35) (+ 0.129501 (* x 8.13008)))\n            (- (+ 0.229501 (* x 8.13008))))\n           (- 6.075 (* y 8.13008)))\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- 5.8 (* y 8.13008)) (- (* y 8.13008) 6.075))\n              (- (* x 8.13008) 0.320499))\n             (- (+ 0.229501 (* x 8.13008))))\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 6.075) 2)\n               (pow (- (* x 8.13008) 0.0454988) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 6.075) 2)\n              (pow (- (* x 8.13008) 0.0454988) 2)))\n            0.275)))\n         (fmin\n          (fmax\n           (-\n            0.175\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 6.075) 2)\n              (pow (+ 0.604501 (* x 8.13008)) 2))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 6.075) 2)\n              (pow (+ 0.604501 (* x 8.13008)) 2)))\n            0.275))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- 5.8 (* y 8.13008)) (- (* y 8.13008) 6.35))\n             (+ 1.2375 (* x 8.13008)))\n            (- (+ 1.3375 (* x 8.13008))))\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- 5.8 (* y 8.13008)) (- (* y 8.13008) 6.35))\n               (+ 1.36071 (* x 11.6144)))\n              (- (+ 1.91072 (* x 11.6144))))\n             (-\n              0.45\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 5.8) 2)\n                (pow (+ 1.70089 (* x 14.518)) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 5.8) 2)\n               (pow (+ 1.36071 (* x 11.6144)) 2)))\n             0.55))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 5.8 (* y 8.13008)) (- (* y 8.13008) 6.15))\n            (- (* x 8.13008) 3.7305))\n           (- 3.6305 (* x 8.13008)))\n          (fmax\n           (-\n            0.175\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 6.075) 2)\n              (pow (- (* x 8.13008) (+ 1.71336 (* y 2.32288))) 2))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 6.075) 2)\n              (pow (- (* x 8.13008) (+ 1.71336 (* y 2.32288))) 2)))\n            0.275)))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 5.8 (* y 8.13008)) (- (* y 8.13008) 6.15))\n            (- (* x 8.13008) 3.0705))\n           (- 2.9705 (* x 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- 5.8 (* y 8.13008)) (- (* y 8.13008) 6.15))\n             (- (* x 8.13008) 2.8205))\n            (- 2.7205 (* x 8.13008)))\n           (fmax\n            (fmax\n             (fmax (- 5.8 (* y 8.13008)) (- (* y 8.13008) 6.325))\n             (- (* x 8.13008) 2.5705))\n            (- 2.4705 (* x 8.13008))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax (- 2.4705 (* x 8.13008)) (- (* y 8.13008) 6.45))\n             (- 6.15 (* y 8.13008)))\n            (- (* x 8.13008) 3.1205))\n           (fmin\n            (fmax\n             (-\n              0.075\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 6.15) 2)\n                (pow (- (* x 8.13008) 2.8955) 2))))\n             (-\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 6.15) 2)\n                (pow (- (* x 8.13008) 2.8955) 2)))\n              0.175))\n            (fmax\n             (-\n              0.075\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 6.15) 2)\n                (pow (- (* x 8.13008) 2.6455) 2))))\n             (-\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 6.15) 2)\n                (pow (- (* x 8.13008) 2.6455) 2)))\n              0.175))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- 5.8 (* y 8.13008)) (- (* y 8.13008) 6.075))\n             (- (* x 8.13008) 1.6205))\n            (- 1.5205 (* x 8.13008)))\n           (fmax\n            (fmax\n             (fmax (- 5.8 (* y 8.13008)) (- (* y 8.13008) 6.8))\n             (- (* x 8.13008) 1.1705))\n            (- 1.0705 (* x 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (* y 8.13008) 6.35) (- (* x 8.13008) 1.6205))\n              (- 1.0705 (* x 8.13008)))\n             (- 6.075 (* y 8.13008)))\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 6.075) 2)\n               (pow (- (* x 8.13008) 1.3455) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 6.075) 2)\n              (pow (- (* x 8.13008) 1.3455) 2)))\n            0.275))\n          (fmin\n           (fmax\n            (fmin\n             (fmax\n              (fmax\n               (fmax (- 3.825 (* y 8.13008)) (- (* x 8.13008) 6.4085))\n               (- 5.9085 (* x 8.13008)))\n              (- (* y 8.13008) 3.915))\n             (fmax\n              (fmax\n               (-\n                (fmin\n                 (fmax\n                  (fmax\n                   (- (* y 5.28455) 2.51875)\n                   (- (* x 2.23577) (+ (* y 1.21951) 1.23609)))\n                  (- 3.57609 (+ (* x 2.23577) (* y 4.06504))))\n                 (fmax\n                  (fmax\n                   (- (+ (* x 2.23577) (* y 4.06504)) 3.57609)\n                   (- (+ (* y 1.21951) 1.23609) (* x 2.23577)))\n                  (- 2.51875 (* y 5.28455)))))\n               (-\n                0.175\n                (sqrt\n                 (+\n                  (pow (- (* y 8.13008) 3.875) 2)\n                  (pow (- (* x 8.13008) 6.1335) 2)))))\n              (-\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 3.875) 2)\n                 (pow (- (* x 8.13008) 6.1335) 2)))\n               0.275)))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 3.875) 2)\n               (pow (- (* x 8.13008) 6.1335) 2)))\n             0.275))\n           (fmax\n            (fmax\n             (fmax (- (* y 8.13008) 3.95) (- 3.6 (* y 8.13008)))\n             (- (* x 8.13008) 5.7585))\n            (- 5.6585 (* x 8.13008))))))))))\n    (fmin\n     (fmin\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 3.95) (- 3.6 (* y 8.13008)))\n            (- (* x 8.13008) 5.5085))\n           (- 5.4085 (* x 8.13008)))\n          (fmax\n           (fmax\n            (fmax (- 3.6 (* y 8.13008)) (- (* y 8.13008) 4.125))\n            (- (* x 8.13008) 5.2585))\n           (- 5.1585 (* x 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax (- 5.1585 (* x 8.13008)) (- (* y 8.13008) 4.25))\n             (- 3.95 (* y 8.13008)))\n            (- (* x 8.13008) 5.8085))\n           (fmin\n            (fmax\n             (-\n              0.075\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 3.95) 2)\n                (pow (- (* x 8.13008) 5.5835) 2))))\n             (-\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 3.95) 2)\n                (pow (- (* x 8.13008) 5.5835) 2)))\n              0.175))\n            (fmax\n             (-\n              0.075\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 3.95) 2)\n                (pow (- (* x 8.13008) 5.3335) 2))))\n             (-\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 3.95) 2)\n                (pow (- (* x 8.13008) 5.3335) 2)))\n              0.175))))\n          (fmin\n           (fmax\n            (fmax\n             (- (* y 0.813008) 0.25)\n             (+ (+ (* y 2.03252) 2.521) (* x 4.47154)))\n            (- (+ (+ 2.216 (* y 2.84553)) (* x 4.47154))))\n           (fmax\n            (fmax\n             (- (* y 0.813008) 0.305)\n             (- (+ (+ 2.216 (* y 2.84553)) (* x 4.47154))))\n            (+ (+ (* y 2.03252) 2.466) (* x 4.47154))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- 0.305 (* y 0.813008))\n            (+ (+ 2.216 (* y 2.84553)) (* x 4.47154)))\n           (- (+ (+ (* y 2.03252) 2.466) (* x 4.47154))))\n          (fmax\n           (fmax\n            (fmax (- 2.5 (* y 8.13008)) (- (* y 8.13008) 2.85))\n            (+ 6.09 (* x 8.13008)))\n           (- (+ 6.19 (* x 8.13008)))))\n         (fmin\n          (fmax\n           (-\n            0.175\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 2.775) 2)\n              (pow (- (+ 7.16429 (* x 8.13008)) (* y 2.32288)) 2))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 2.775) 2)\n              (pow (- (+ 7.16429 (* x 8.13008)) (* y 2.32288)) 2)))\n            0.275))\n          (fmin\n           (fmax\n            (-\n             (sqrt\n              (+\n               (pow (+ 7.025 (* x 8.13008)) 2)\n               (pow (- (* y 8.13008) 2.775) 2)))\n             0.275)\n            (fmin\n             (fmax\n              (fmax\n               (fmax (- (* y 8.13008) 2.815) (- 2.725 (* y 8.13008)))\n               (+ 6.75 (* x 8.13008)))\n              (- (+ 7.25 (* x 8.13008))))\n             (fmax\n              (fmax\n               (-\n                (sqrt\n                 (+\n                  (pow (+ 7.025 (* x 8.13008)) 2)\n                  (pow (- (* y 8.13008) 2.775) 2)))\n                0.275)\n               (-\n                (fmin\n                 (fmax\n                  (fmax\n                   (- (* y 5.28455) 1.80375)\n                   (- (+ 2.2175 (* x 2.23577)) (* y 1.21951)))\n                  (- (+ (+ 0.5925 (* x 2.23577)) (* y 4.06504))))\n                 (fmax\n                  (fmax\n                   (- 1.80375 (* y 5.28455))\n                   (+ (+ 0.5925 (* x 2.23577)) (* y 4.06504)))\n                  (- (* y 1.21951) (+ 2.2175 (* x 2.23577)))))))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (+ 7.025 (* x 8.13008)) 2)\n                 (pow (- (* y 8.13008) 2.775) 2)))))))\n           (fmax\n            (fmax\n             (fmax (+ 7.45 (* x 8.13008)) (- 2.5 (* y 8.13008)))\n             (- (* y 8.13008) 2.775))\n            (- (+ 7.55 (* x 8.13008))))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 2.5 (* y 8.13008)) (- (* y 8.13008) 3.5))\n            (+ 7.9 (* x 8.13008)))\n           (- (+ 8 (* x 8.13008))))\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (+ 7.45 (* x 8.13008)) (- (* y 8.13008) 3.05))\n              (- 2.775 (* y 8.13008)))\n             (- (+ 8 (* x 8.13008))))\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (+ 7.725 (* x 8.13008)) 2)\n               (pow (- (* y 8.13008) 2.775) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (+ 7.725 (* x 8.13008)) 2)\n              (pow (- (* y 8.13008) 2.775) 2)))\n            0.275)))\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- 3.6 (* y 8.13008)) (- (* y 8.13008) 4.6))\n              (- 2.121 (* x 8.13008)))\n             (- (* x 8.13008) 2.846))\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 3.875) 2)\n               (pow (- 2.846 (* x 8.13008)) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 3.875) 2)\n              (pow (- 2.846 (* x 8.13008)) 2)))\n            0.275))\n          (fmin\n           (fmax\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 3.875) 2)\n               (pow (- (* x 8.13008) 2.221) 2)))\n             0.275)\n            (fmin\n             (fmax\n              (fmax\n               (fmax (- 3.825 (* y 8.13008)) (- (* y 8.13008) 3.915))\n               (- (* x 8.13008) 2.496))\n              (- 1.996 (* x 8.13008)))\n             (fmax\n              (fmax\n               (-\n                (sqrt\n                 (+\n                  (pow (- (* y 8.13008) 3.875) 2)\n                  (pow (- (* x 8.13008) 2.221) 2)))\n                0.275)\n               (-\n                (fmin\n                 (fmax\n                  (fmax\n                   (- (* y 5.28455) 2.51875)\n                   (- (* x 2.23577) (+ 0.16015 (* y 1.21951))))\n                  (- 2.50015 (+ (* x 2.23577) (* y 4.06504))))\n                 (fmax\n                  (fmax\n                   (- 2.51875 (* y 5.28455))\n                   (- (+ (* x 2.23577) (* y 4.06504)) 2.50015))\n                  (- (+ 0.16015 (* y 1.21951)) (* x 2.23577))))))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 3.875) 2)\n                 (pow (- (* x 8.13008) 2.221) 2)))))))\n           (fmax\n            (fmax\n             (fmax (- 3.6 (* y 8.13008)) (- (* x 8.13008) 1.588))\n             (- 1.488 (* x 8.13008)))\n            (- (* y 8.13008) 4.15)))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- 3.6 (* y 8.13008)) (- (* x 11.6144) 2.67571))\n              (- 2.12571 (* x 11.6144)))\n             (-\n              0.45\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 3.6) 2)\n                (pow (- (* x 14.518) 3.34464) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 3.6) 2)\n               (pow (- (* x 11.6144) 2.67571) 2)))\n             0.55))\n           (- (* y 8.13008) 4.15))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- 3.6 (* y 8.13008)) (- (* x 8.13008) 1.363))\n             (- 1.263 (* x 8.13008)))\n            (- (* y 8.13008) 4.15))\n           (-\n            (sqrt\n             (+ (pow (- (* y 8.13008) 4.3) 2) (pow (- (* x 8.13008) 1.313) 2)))\n            0.075)))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 3.6 (* y 8.13008)) (- (* x 8.13008) 1.138))\n            (- 1.038 (* x 8.13008)))\n           (- (* y 8.13008) 4.15))\n          (fmin\n           (fmax\n            (-\n             (sqrt\n              (+\n               (pow (- (* x 8.13008) 4.7835) 2)\n               (pow (- (* y 8.13008) 3.875) 2)))\n             0.275)\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (- (* x 8.13008) 4.7835) 2)\n               (pow (- (* y 8.13008) 3.875) 2)))))\n           (fmax\n            (-\n             (fmin\n              (fmax\n               (fmax\n                (fmax (- 3.825 (* y 8.13008)) (- (* y 8.13008) 3.9875))\n                (- 2.7765 (* x 5.42005)))\n               (- (* x 5.42005) 2.939))\n              (-\n               (sqrt\n                (+\n                 (pow (- 3.985 (* y 8.13008)) 2)\n                 (pow (- 1.84933 (* x 3.61337)) 2)))\n               0.0625)))\n            (-\n             (sqrt\n              (+\n               (pow (- 3.9875 (* y 8.13008)) 2)\n               (pow (- 2.7765 (* x 5.42005)) 2)))\n             0.1625)))))))\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (-\n            (fmin\n             (fmax\n              (fmax\n               (fmax (- (* y 8.13008) 3.925) (- 3.7625 (* y 8.13008)))\n               (- (* x 5.42005) 2.7765))\n              (- 2.614 (* x 5.42005)))\n             (-\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 3.765) 2)\n                (pow (- (* x 3.61337) 1.85267) 2)))\n              0.0625)))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 3.7625) 2)\n              (pow (- (* x 5.42005) 2.7765) 2)))\n            0.1625))\n          (fmax\n           (fmax\n            (fmax (- 3.6 (* y 8.13008)) (- (* y 8.13008) 4.6))\n            (- 3.021 (* x 8.13008)))\n           (- (* x 8.13008) 3.121)))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 4.15) (- 4.05 (* y 8.13008)))\n            (- 2.846 (* x 8.13008)))\n           (- (* x 8.13008) 3.021))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- 3.6 (* y 8.13008)) (- 2.846 (* x 8.13008)))\n             (- (* x 8.13008) 3.021))\n            (- (* y 8.13008) 3.7))\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- 3.6 (* y 8.13008)) (- (* y 8.13008) 4.15))\n               (+ 1.12143 (* x 11.6144)))\n              (- (+ 1.67143 (* x 11.6144))))\n             (-\n              0.45\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 3.6) 2)\n                (pow (+ 1.40179 (* x 14.518)) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 3.6) 2)\n               (pow (+ 1.12143 (* x 11.6144)) 2)))\n             0.55)))))\n        (fmin\n         (fmin\n          (fmax\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 3.875) 2)\n              (pow (+ 2.245 (* x 8.13008)) 2)))\n            0.275)\n           (fmin\n            (fmax\n             (fmax\n              (fmax (- 3.825 (* y 8.13008)) (- (* y 8.13008) 3.915))\n              (+ 1.97 (* x 8.13008)))\n             (- (+ 2.47 (* x 8.13008))))\n            (fmax\n             (fmax\n              (-\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 3.875) 2)\n                 (pow (+ 2.245 (* x 8.13008)) 2)))\n               0.275)\n              (-\n               (fmin\n                (fmax\n                 (fmax\n                  (- (* y 5.28455) 2.51875)\n                  (- (+ 1.068 (* x 2.23577)) (* y 1.21951)))\n                 (- 1.272 (+ (* x 2.23577) (* y 4.06504))))\n                (fmax\n                 (fmax\n                  (- 2.51875 (* y 5.28455))\n                  (- (+ (* x 2.23577) (* y 4.06504)) 1.272))\n                 (- (* y 1.21951) (+ 1.068 (* x 2.23577)))))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 3.875) 2)\n                (pow (+ 2.245 (* x 8.13008)) 2)))))))\n          (fmax\n           (fmax\n            (- 0.36 (* y 0.813008))\n            (- (+ 2.4785 (* x 4.47154)) (* y 2.03252)))\n           (- (* y 2.84553) (+ 2.8935 (* x 4.47154)))))\n         (fmin\n          (fmax\n           (fmax\n            (- (+ 2.8935 (* x 4.47154)) (* y 2.84553))\n            (- (* y 2.03252) (+ 2.4785 (* x 4.47154))))\n           (- (* y 0.813008) 0.36))\n          (fmin\n           (fmax\n            (fmax\n             (- (+ 2.8935 (* x 4.47154)) (* y 2.84553))\n             (- (* y 0.813008) 0.415))\n            (- (* y 2.03252) (+ 2.5335 (* x 4.47154))))\n           (fmax\n            (fmax\n             (- (* y 2.84553) (+ 2.8935 (* x 4.47154)))\n             (- (+ 2.5335 (* x 4.47154)) (* y 2.03252)))\n            (- 0.415 (* y 0.813008)))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- 0.36 (* y 0.813008))\n            (- (+ (+ 0.7335 (* y 2.03252)) (* x 4.47154))))\n           (+ (+ 0.318501 (* y 2.84553)) (* x 4.47154)))\n          (fmax\n           (fmax\n            (- (* y 0.813008) 0.36)\n            (+ (+ 0.7335 (* y 2.03252)) (* x 4.47154)))\n           (- (+ (+ 0.318501 (* y 2.84553)) (* x 4.47154)))))\n         (fmin\n          (fmax\n           (fmax\n            (- (* y 0.813008) 0.415)\n            (- (+ (+ 0.318501 (* y 2.84553)) (* x 4.47154))))\n           (+ (+ 0.6785 (* y 2.03252)) (* x 4.47154)))\n          (fmin\n           (fmax\n            (fmax\n             (- 0.415 (* y 0.813008))\n             (+ (+ 0.318501 (* y 2.84553)) (* x 4.47154)))\n            (- (+ (+ 0.6785 (* y 2.03252)) (* x 4.47154))))\n           (fmax\n            (fmax\n             (fmax (- (* y 8.13008) 3.95) (- 3.6 (* y 8.13008)))\n             (+ 3.34 (* x 8.13008)))\n            (- (+ 3.44 (* x 8.13008)))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 3.875 (* y 8.13008)) (- (* x 8.13008) 0.688))\n            (- 0.587999 (* x 8.13008)))\n           (- (* y 8.13008) 4.15))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- 3.6 (* y 8.13008)) (- (* y 8.13008) 3.875))\n               (- (* x 8.13008) 1.138))\n              (- 0.587999 (* x 8.13008)))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 3.875) 2)\n                (pow (- (* x 8.13008) 0.862999) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 3.875) 2)\n               (pow (- (* x 8.13008) 0.862999) 2)))\n             0.275))\n           (fmax\n            (fmax\n             (fmax (- (* y 8.13008) 4.15) (- 3.225 (* y 8.13008)))\n             (- (* x 8.13008) 0.487999))\n            (- 0.387999 (* x 8.13008)))))\n         (fmin\n          (fmax\n           (-\n            0.175\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 3.875) 2)\n              (pow (- (* x 8.13008) 0.212998) 2))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 3.875) 2)\n              (pow (- (* x 8.13008) 0.212998) 2)))\n            0.275))\n          (fmin\n           (fmax\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 3.875) 2)\n               (pow (+ 0.437001 (* x 8.13008)) 2)))\n             0.275)\n            (fmin\n             (fmax\n              (fmax\n               (fmax (- 3.825 (* y 8.13008)) (- (* y 8.13008) 3.915))\n               (+ 0.162001 (* x 8.13008)))\n              (- (+ 0.662001 (* x 8.13008))))\n             (fmax\n              (fmax\n               (-\n                (sqrt\n                 (+\n                  (pow (- (* y 8.13008) 3.875) 2)\n                  (pow (+ 0.437001 (* x 8.13008)) 2)))\n                0.275)\n               (-\n                (fmin\n                 (fmax\n                  (fmax\n                   (- (* y 5.28455) 2.51875)\n                   (- (+ 0.5708 (* x 2.23577)) (* y 1.21951)))\n                  (- 1.7692 (+ (* x 2.23577) (* y 4.06504))))\n                 (fmax\n                  (fmax\n                   (- 2.51875 (* y 5.28455))\n                   (- (+ (* x 2.23577) (* y 4.06504)) 1.7692))\n                  (- (* y 1.21951) (+ 0.5708 (* x 2.23577)))))))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 3.875) 2)\n                 (pow (+ 0.437001 (* x 8.13008)) 2)))))))\n           (fmax\n            (fmax\n             (fmax (- 3.6 (* y 8.13008)) (- (* y 8.13008) 4.15))\n             (+ 1.07 (* x 8.13008)))\n            (- (+ 1.17 (* x 8.13008))))))))))\n     (fmin\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmin\n            (fmax\n             (fmax\n              (-\n               (fmin\n                (fmax\n                 (fmax\n                  (- (* y 5.28455) 3.23375)\n                  (- (* x 2.23577) (+ 0.986526 (* y 1.21951))))\n                 (- 4.04153 (+ (* x 2.23577) (* y 4.06504))))\n                (fmax\n                 (fmax\n                  (- (+ (* x 2.23577) (* y 4.06504)) 4.04153)\n                  (- (+ 0.986526 (* y 1.21951)) (* x 2.23577)))\n                 (- 3.23375 (* y 5.28455)))))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 4.975) 2)\n                 (pow (- (* x 8.13008) 5.826) 2)))))\n             (-\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 4.975) 2)\n                (pow (- (* x 8.13008) 5.826) 2)))\n              0.275))\n            (fmax\n             (fmax\n              (fmax (- (* y 8.13008) 5.015) (- 4.925 (* y 8.13008)))\n              (- (* x 8.13008) 6.101))\n             (- 5.601 (* x 8.13008))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 4.975) 2)\n              (pow (- (* x 8.13008) 5.826) 2)))\n            0.275))\n          (fmax\n           (fmax\n            (fmax (- (* x 8.13008) 5.401) (- 5.301 (* x 8.13008)))\n            (- 4.7 (* y 8.13008)))\n           (- (* y 8.13008) 4.975)))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 5.7) (- (* x 8.13008) 4.951))\n            (- 4.851 (* x 8.13008)))\n           (- 4.7 (* y 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- (* x 8.13008) 5.401) (- 4.851 (* x 8.13008)))\n               (- 4.975 (* y 8.13008)))\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (- (* x 8.13008) 5.126) 2)\n                 (pow (- (* y 8.13008) 4.975) 2)))))\n             (-\n              (sqrt\n               (+\n                (pow (- (* x 8.13008) 5.126) 2)\n                (pow (- (* y 8.13008) 4.975) 2)))\n              0.275))\n            (- (* y 8.13008) 5.25))\n           (fmax\n            (fmax\n             (- 0.47 (* y 0.813008))\n             (- (* x 4.47154) (+ 1.30055 (* y 2.03252))))\n            (- (+ 0.775551 (* y 2.84553)) (* x 4.47154))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (* x 4.47154) (+ 0.775551 (* y 2.84553)))\n            (- (+ 1.30055 (* y 2.03252)) (* x 4.47154)))\n           (- (* y 0.813008) 0.47))\n          (fmax\n           (fmax\n            (- (* x 4.47154) (+ 0.775551 (* y 2.84553)))\n            (- (* y 0.813008) 0.525))\n           (- (+ 1.24555 (* y 2.03252)) (* x 4.47154))))\n         (fmin\n          (fmax\n           (fmax\n            (- (+ 0.775551 (* y 2.84553)) (* x 4.47154))\n            (- (* x 4.47154) (+ 1.24555 (* y 2.03252))))\n           (- 0.525 (* y 0.813008)))\n          (fmin\n           (fmax\n            (fmax\n             (- 0.47 (* y 0.813008))\n             (- 3.59555 (+ (* y 2.03252) (* x 4.47154))))\n            (- (+ (* y 2.84553) (* x 4.47154)) 4.12055))\n           (fmax\n            (fmax\n             (- (* y 0.813008) 0.47)\n             (- 4.12055 (+ (* y 2.84553) (* x 4.47154))))\n            (- (+ (* y 2.03252) (* x 4.47154)) 3.59555))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (- (* y 0.813008) 0.525)\n            (- 4.12055 (+ (* y 2.84553) (* x 4.47154))))\n           (- (+ (* y 2.03252) (* x 4.47154)) 3.65055))\n          (fmax\n           (-\n            0.175\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 3.875) 2)\n              (pow (- (+ 4.72857 (* x 8.13008)) (* y 2.32288)) 2))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 3.875) 2)\n              (pow (- (+ 4.72857 (* x 8.13008)) (* y 2.32288)) 2)))\n            0.275)))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 3.6 (* y 8.13008)) (- (* y 8.13008) 3.875))\n            (+ 4.05 (* x 8.13008)))\n           (- (+ 4.15 (* x 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (+ 4.5 (* x 8.13008)) (- (+ 4.6 (* x 8.13008))))\n             (- 3.6 (* y 8.13008)))\n            (- (* y 8.13008) 4.6))\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- (+ 4.6 (* x 8.13008))) (- 3.875 (* y 8.13008)))\n               (- (* y 8.13008) 4.15))\n              (+ 4.05 (* x 8.13008)))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 3.875) 2)\n                (pow (+ 4.325 (* x 8.13008)) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 3.875) 2)\n               (pow (+ 4.325 (* x 8.13008)) 2)))\n             0.275)))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 4.6) (- 4.5 (* y 8.13008)))\n            (+ 5.4 (* x 8.13008)))\n           (- (+ 5.9 (* x 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- 3.6 (* y 8.13008)) (- (* y 8.13008) 3.7))\n             (+ 5.4 (* x 8.13008)))\n            (- (+ 5.9 (* x 8.13008))))\n           (fmax\n            (fmax\n             (fmax (- 3.6 (* y 8.13008)) (- (* y 8.13008) 4.6))\n             (+ 5.6 (* x 8.13008)))\n            (- (+ 5.7 (* x 8.13008))))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 5.025) (- 4.7 (* y 8.13008)))\n            (- (* x 8.13008) 6.75101))\n           (- 6.651 (* x 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- 4.7 (* y 8.13008)) (- (* y 8.13008) 5.25))\n             (- (* x 8.13008) 6.30101))\n            (- 6.201 (* x 8.13008)))\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- (* x 8.13008) 6.75101) (- (* y 8.13008) 5.25))\n               (- 6.201 (* x 8.13008)))\n              (- 5.025 (* y 8.13008)))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 4.975) 2)\n                (pow (- (* x 8.13008) 6.476) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 4.975) 2)\n               (pow (- (* x 8.13008) 6.476) 2)))\n             0.275)))))))\n      (fmin\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- (* y 8.13008) 6.35) (- 6.075 (* y 8.13008)))\n              (+ 3.025 (* x 8.13008)))\n             (- (+ 3.575 (* x 8.13008))))\n            (-\n             0.175\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 6.075) 2)\n               (pow (+ 3.3 (* x 8.13008)) 2)))))\n           (-\n            (sqrt\n             (+ (pow (- (* y 8.13008) 6.075) 2) (pow (+ 3.3 (* x 8.13008)) 2)))\n            0.275))\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 6.8) (- 6.05 (* y 8.13008)))\n            (+ 3.825 (* x 8.13008)))\n           (- (+ 3.925 (* x 8.13008)))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 6.45) (- 6.35 (* y 8.13008)))\n            (+ 3.675 (* x 8.13008)))\n           (- (+ 4.075 (* x 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (- 5.8 (* y 8.13008)) (+ 3.675 (* x 8.13008)))\n               (- (+ 4.075 (* x 8.13008))))\n              (- (* y 8.13008) 6.05))\n             (-\n              0.15\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 6.05) 2)\n                (pow (+ 3.675 (* x 8.13008)) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 6.05) 2)\n               (pow (+ 3.675 (* x 8.13008)) 2)))\n             0.25))\n           (fmax\n            (fmax\n             (fmax (- (* y 8.13008) 6.8) (- 6.05 (* y 8.13008)))\n             (+ 5.025 (* x 8.13008)))\n            (- (+ 5.125 (* x 8.13008)))))))\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (* y 8.13008) 6.45) (- 6.35 (* y 8.13008)))\n            (+ 4.875 (* x 8.13008)))\n           (- (+ 5.275 (* x 8.13008))))\n          (fmax\n           (fmax\n            (fmax\n             (fmax\n              (fmax (- 5.8 (* y 8.13008)) (- (* y 8.13008) 6.05))\n              (+ 4.875 (* x 8.13008)))\n             (- (+ 5.275 (* x 8.13008))))\n            (-\n             0.15\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 6.05) 2)\n               (pow (+ 4.875 (* x 8.13008)) 2)))))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 6.05) 2)\n              (pow (+ 4.875 (* x 8.13008)) 2)))\n            0.25)))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 5.375 (* x 8.13008)) (- 5.8 (* y 8.13008)))\n            (- (* y 8.13008) 6.35))\n           (- (+ 5.475 (* x 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (* y 8.13008) 6.35) (- 6.075 (* y 8.13008)))\n             (+ 5.825 (* x 8.13008)))\n            (- (+ 5.925 (* x 8.13008))))\n           (fmax\n            (fmax\n             (fmax\n              (fmax\n               (fmax (+ 5.375 (* x 8.13008)) (- 5.8 (* y 8.13008)))\n               (- (* y 8.13008) 6.075))\n              (- (+ 5.925 (* x 8.13008))))\n             (-\n              0.175\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 6.075) 2)\n                (pow (+ 5.65 (* x 8.13008)) 2)))))\n            (-\n             (sqrt\n              (+\n               (pow (- (* y 8.13008) 6.075) 2)\n               (pow (+ 5.65 (* x 8.13008)) 2)))\n             0.275))))))\n       (fmin\n        (fmin\n         (fmin\n          (fmax\n           (fmax\n            (fmax (+ 6.5 (* x 8.13008)) (- (+ 6.6 (* x 8.13008))))\n            (- 5.8 (* y 8.13008)))\n           (- (* y 8.13008) 6.8))\n          (fmax\n           (fmax\n            (fmax (- (+ 6.5 (* x 8.13008))) (- (* y 8.13008) 6.8))\n            (- 6.7 (* y 8.13008)))\n           (+ 6.3 (* x 8.13008))))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- (+ 6.5 (* x 8.13008))) (- (* y 8.13008) 6.35))\n            (+ 6.3 (* x 8.13008)))\n           (- 6.25 (* y 8.13008)))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- (+ 6.5 (* x 8.13008))) (- (* y 8.13008) 5.9))\n             (- 5.8 (* y 8.13008)))\n            (+ 6.3 (* x 8.13008)))\n           (fmax\n            (-\n             (fmin\n              (fmax\n               (fmax\n                (fmax (- 6.025 (* y 8.13008)) (- (* y 8.13008) 6.1875))\n                (- (+ 1.5875 (* x 5.42005))))\n               (+ 1.425 (* x 5.42005)))\n              (-\n               (sqrt\n                (+\n                 (pow (- 6.185 (* y 8.13008)) 2)\n                 (pow (- (+ 1.06 (* x 3.61337))) 2)))\n               0.0625)))\n            (-\n             (sqrt\n              (+\n               (pow (- 6.1875 (* y 8.13008)) 2)\n               (pow (- (+ 1.5875 (* x 5.42005))) 2)))\n             0.1625)))))\n        (fmin\n         (fmin\n          (fmax\n           (-\n            (fmin\n             (fmax\n              (fmax\n               (fmax (- (* y 8.13008) 6.125) (- 5.9625 (* y 8.13008)))\n               (+ 1.5875 (* x 5.42005)))\n              (- (+ 1.75 (* x 5.42005))))\n             (-\n              (sqrt\n               (+\n                (pow (- (* y 8.13008) 5.965) 2)\n                (pow (+ 1.05667 (* x 3.61337)) 2)))\n              0.0625)))\n           (-\n            (sqrt\n             (+\n              (pow (- (* y 8.13008) 5.9625) 2)\n              (pow (+ 1.5875 (* x 5.42005)) 2)))\n            0.1625))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- 5.8 (* y 8.13008)) (- (* y 8.13008) 6.35))\n             (+ 2.75 (* x 8.13008)))\n            (- (+ 2.85 (* x 8.13008))))\n           (-\n            (sqrt\n             (+ (pow (- (* y 8.13008) 6.5) 2) (pow (+ 2.8 (* x 8.13008)) 2)))\n            0.075)))\n         (fmin\n          (fmax\n           (fmax\n            (fmax (- 5.8 (* y 8.13008)) (- (* y 8.13008) 6.075))\n            (+ 3.025 (* x 8.13008)))\n           (- (+ 3.125 (* x 8.13008))))\n          (fmin\n           (fmax\n            (fmax\n             (fmax (- 5.8 (* y 8.13008)) (- (* y 8.13008) 6.8))\n             (+ 3.475 (* x 8.13008)))\n            (- (+ 3.575 (* x 8.13008))))\n           (fmax\n            (fmax\n             (fmax\n              (fmax (+ 5.6 (* x 8.13008)) (- 5.8 (* y 8.13008)))\n              (- (* y 8.13008) 6.8))\n             (- (+ 6.3 (* x 8.13008))))\n            (fmin\n             (fmax\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 6.075) 2)\n                 (pow (+ 6.3 (* x 8.13008)) 2))))\n              (-\n               (sqrt\n                (+\n                 (pow (- (* y 8.13008) 6.075) 2)\n                 (pow (+ 6.3 (* x 8.13008)) 2)))\n               0.275))\n             (fmax\n              (-\n               0.175\n               (sqrt\n                (+\n                 (pow (+ 6.3 (* x 8.13008)) 2)\n                 (pow (- (* y 8.13008) 6.525) 2))))\n              (-\n               (sqrt\n                (+\n                 (pow (+ 6.3 (* x 8.13008)) 2)\n                 (pow (- (* y 8.13008) 6.525) 2)))\n               0.275)))))))))))))))\n"
  },
  {
    "path": "bench/graphics/fidget/quarter.fpcore",
    "content": "(FPCore (x y)\n  :name \"A quarter-circle in the lower-left quadrant\"\n  :precision binary64\n  (fmax (- (+ (pow y 2) (pow x 2)) 0.5) (fmax x y))\n)\n"
  },
  {
    "path": "bench/graphics/lod.fpcore",
    "content": "; -*- mode: scheme -*-\n\n;\n; Level-of-Detail computation\n; Direct3D 11.3\n; Section 7.8.11\n;\n; Texture limits from Section 21:\n; Textures sizes are integer values between [1, 2^14].\n; Maximum ratio of anisotropy will be fixed at 16 since the algorithm\n; is only interesting when clamping is kept minimal.\n;\n; While the section mentions \"reasonable\" limits for derivatives,\n; unreasonable is still allowable, so any good algorithm should\n; be able to handle inputs in this space. The limits on derivatives\n; are conservative and handle inputs far outside the \"reasonable\" space\n; \n;\n\n;\n;   Anisotropic\n;\n\n(FPCore (w h dX.u dX.v dY.u dY.v maxAniso)\n  :name \"Anisotropic x16 LOD (LOD)\"\n  :precision binary32\n  :pre (and (<= 1 w 16384)\n            (<= 1 h 16384)\n            (<= 1e-20 (fabs dX.u) 1e+20)\n            (<= 1e-20 (fabs dX.v) 1e+20)\n            (<= 1e-20 (fabs dY.u) 1e+20)\n            (<= 1e-20 (fabs dY.v) 1e+20)\n            (== maxAniso 16))\n  \n  (let* ([w         (floor w)]\n         [h         (floor h)]\n         [maxAniso  (floor maxAniso)]\n\n         [dX.u (* w dX.u)]\n         [dX.v (* h dX.v)]\n         [dY.u (* w dY.u)]\n         [dY.v (* h dY.v)]\n    \n         [dX2  (+ (* dX.u dX.u) (* dX.v dX.v))]\n         [dY2  (+ (* dY.u dY.u) (* dY.v dY.v))]\n         [det  (fabs (- (* dX.u dY.v) (* dX.v dY.u)))]\n\n         [major2        (fmax dX2 dY2)]\n         [major         (sqrt major2)]\n         [normMajor     (/ 1 major)]\n         [ratioAniso0   (/ major2 det)]\n\n         ; first round of clamping\n         [minor         (if (> ratioAniso0 maxAniso)\n                            (/ major maxAniso)\n                            (/ det major))]\n         [ratioAniso1   (if (> ratioAniso0 maxAniso)\n                            maxAniso\n                            ratioAniso0)]\n\n         ; second round of clamping\n         [ratioAniso    (if (< minor 1.0)\n                            (fmax 1.0 (* ratioAniso1 minor))\n                            ratioAniso1)])\n\n    (log2 minor)))\n\n(FPCore (w h dX.u dX.v dY.u dY.v maxAniso)\n  :name \"Anisotropic x16 LOD (ratio of anisotropy)\"\n  :precision binary32\n  :pre (and (<= 1 w 16384)\n            (<= 1 h 16384)\n            (<= 1e-20 (fabs dX.u) 1e+20)\n            (<= 1e-20 (fabs dX.v) 1e+20)\n            (<= 1e-20 (fabs dY.u) 1e+20)\n            (<= 1e-20 (fabs dY.v) 1e+20)\n            (== maxAniso 16))\n  \n  (let* ([w         (floor w)]\n         [h         (floor h)]\n         [maxAniso  (floor maxAniso)]\n\n         [dX.u (* w dX.u)]\n         [dX.v (* h dX.v)]\n         [dY.u (* w dY.u)]\n         [dY.v (* h dY.v)]\n    \n         [dX2  (+ (* dX.u dX.u) (* dX.v dX.v))]\n         [dY2  (+ (* dY.u dY.u) (* dY.v dY.v))]\n         [det  (fabs (- (* dX.u dY.v) (* dX.v dY.u)))]\n\n         [major2        (fmax dX2 dY2)]\n         [major         (sqrt major2)]\n         [normMajor     (/ 1 major)]\n         [ratioAniso0   (/ major2 det)]\n\n         ; first round of clamping\n         [minor         (if (> ratioAniso0 maxAniso)\n                            (/ major maxAniso)\n                            (/ det major))]\n         [ratioAniso1   (if (> ratioAniso0 maxAniso)\n                            maxAniso\n                            ratioAniso0)]\n\n         ; second round of clamping\n         [ratioAniso    (if (< minor 1.0)\n                            (fmax 1.0 (* ratioAniso1 minor))\n                            ratioAniso1)])\n\n    ratioAniso))\n\n(FPCore (w h dX.u dX.v dY.u dY.v maxAniso)\n  :name \"Anisotropic x16 LOD (line direction, u)\"\n  :precision binary32\n  :pre (and (<= 1 w 16384)\n            (<= 1 h 16384)\n            (<= 1e-20 (fabs dX.u) 1e+20)\n            (<= 1e-20 (fabs dX.v) 1e+20)\n            (<= 1e-20 (fabs dY.u) 1e+20)\n            (<= 1e-20 (fabs dY.v) 1e+20)\n            (== maxAniso 16))\n  \n  (let* ([w         (floor w)]\n         [h         (floor h)]\n         [maxAniso  (floor maxAniso)]\n\n         [dX.u (* w dX.u)]\n         [dX.v (* h dX.v)]\n         [dY.u (* w dY.u)]\n         [dY.v (* h dY.v)]\n    \n         [dX2  (+ (* dX.u dX.u) (* dX.v dX.v))]\n         [dY2  (+ (* dY.u dY.u) (* dY.v dY.v))]\n         [det  (fabs (- (* dX.u dY.v) (* dX.v dY.u)))]\n\n         [major2        (fmax dX2 dY2)]\n         [major         (sqrt major2)]\n         [normMajor     (/ 1 major)]\n         [ratioAniso0   (/ major2 det)]\n\n         ; first round of clamping\n         [minor         (if (> ratioAniso0 maxAniso)\n                            (/ major maxAniso)\n                            (/ det major))]\n         [ratioAniso1   (if (> ratioAniso0 maxAniso)\n                            maxAniso\n                            ratioAniso0)]\n\n         ; second round of clamping\n         [ratioAniso    (if (< minor 1.0)\n                            (fmax 1.0 (* ratioAniso1 minor))\n                            ratioAniso1)])\n\n    (if (>= dX2 dY2)\n        (* normMajor dX.u)\n        (* normMajor dY.u))))\n\n(FPCore (w h dX.u dX.v dY.u dY.v maxAniso)\n  :name \"Anisotropic x16 LOD (line direction, v)\"\n  :precision binary32\n  :pre (and (<= 1 w 16384)\n            (<= 1 h 16384)\n            (<= 1e-20 (fabs dX.u) 1e+20)\n            (<= 1e-20 (fabs dX.v) 1e+20)\n            (<= 1e-20 (fabs dY.u) 1e+20)\n            (<= 1e-20 (fabs dY.v) 1e+20)\n            (== maxAniso 16))\n  \n  (let* ([w         (floor w)]\n         [h         (floor h)]\n         [maxAniso  (floor maxAniso)]\n\n         [dX.u (* w dX.u)]\n         [dX.v (* h dX.v)]\n         [dY.u (* w dY.u)]\n         [dY.v (* h dY.v)]\n    \n         [dX2  (+ (* dX.u dX.u) (* dX.v dX.v))]\n         [dY2  (+ (* dY.u dY.u) (* dY.v dY.v))]\n         [det  (fabs (- (* dX.u dY.v) (* dX.v dY.u)))]\n\n         [major2        (fmax dX2 dY2)]\n         [major         (sqrt major2)]\n         [normMajor     (/ 1 major)]\n         [ratioAniso0   (/ major2 det)]\n\n         ; first round of clamping\n         [minor         (if (> ratioAniso0 maxAniso)\n                            (/ major maxAniso)\n                            (/ det major))]\n         [ratioAniso1   (if (> ratioAniso0 maxAniso)\n                            maxAniso\n                            ratioAniso0)]\n\n         ; second round of clamping\n         [ratioAniso    (if (< minor 1.0)\n                            (fmax 1.0 (* ratioAniso1 minor))\n                            ratioAniso1)])\n\n    (if (>= dX2 dY2)\n        (* normMajor dX.v)\n        (* normMajor dY.v))))\n\n;\n;   Isotropic (supports 3D as well)\n;\n\n(FPCore (w h d dX.u dX.v dX.w dY.u dY.v dY.w)\n  :name \"Isotropic LOD (LOD)\"\n  :precision binary32\n  :pre (and (<= 1 w 16384)\n            (<= 1 h 16384)\n            (<= 1 d 4096)\n            (<= 1e-20 (fabs dX.u) 1e+20)\n            (<= 1e-20 (fabs dX.v) 1e+20)\n            (<= 1e-20 (fabs dX.w) 1e+20)\n            (<= 1e-20 (fabs dY.u) 1e+20)\n            (<= 1e-20 (fabs dY.v) 1e+20)\n            (<= 1e-20 (fabs dY.w) 1e+20))\n  \n  (let* ([w         (floor w)]\n         [h         (floor h)]\n         [d         (floor d)]\n\n         [dX.u (* w dX.u)]\n         [dX.v (* h dX.v)]\n         [dX.w (* d dX.w)]\n         [dY.u (* w dY.u)]\n         [dY.v (* h dY.v)]\n         [dY.w (* d dY.w)]\n    \n         [dX2  (+ (+ (* dX.u dX.u) (* dX.v dX.v)) (* dX.w dX.w))]\n         [dY2  (+ (+ (* dY.u dY.u) (* dY.v dY.v)) (* dY.w dY.w))]\n\n         [major2        (fmax dX2 dY2)]\n         [major         (sqrt major2)])\n  \n    (log2 major)))\n\n\n; The following two benchmarks are thanks to Ben Wang and Bill Zorn.\n(FPCore (p r q)\n  :name \"1/2(abs(p)+abs(r) - sqrt((p-r)^2 + 4q^2))\"\n  (* (/ 1.0 2.0) (- (+ (fabs p) (fabs r)) (sqrt (+ (pow (- p r) 2.0) (* 4.0 (pow q 2.0)))))))\n\n(FPCore (p r q)\n  :name \"1/2(abs(p)+abs(r) + sqrt((p-r)^2 + 4q^2))\"\n  (* (/ 1.0 2.0) (+ (+ (fabs p) (fabs r)) (sqrt (+ (pow (- p r) 2.0) (* 4.0 (pow q 2.0)))))))"
  },
  {
    "path": "bench/graphics/log-transform.fpcore",
    "content": "; This example is taken from the Image Processing domain and referred to \n; as \"Logarithmic Transform\". This in its basic form is used to bring out\n; details in dark parts of an image. This instantiation of the idea is for 1D\n; as opposed to 2D images.\n\n(FPCore (c x y)\n  :name \"Logarithmic Transform\"\n  :alt\n    (* c (log1p (* (expm1 x) y)))\n\n  (* c (log (+ 1.0 (* (- (pow E x) 1.0) y)))))"
  },
  {
    "path": "bench/graphics/pbrt.fpcore",
    "content": "(FPCore (cosTheta_i cosTheta_O sinTheta_i sinTheta_O v)\n :name \"HairBSDF, Mp, upper\"\n :precision binary32\n :pre (and (<= -1 cosTheta_i 1) (<= -1 cosTheta_O 1)\n           (<= -1 sinTheta_i 1) (<= -1 sinTheta_O 1)\n           (< 0.1 v) (<= v 1.5707964))\n (let ([a (/ (* cosTheta_i cosTheta_O) v)]\n       [b (/ (* sinTheta_i sinTheta_O) v)])\n  (/ (* (exp (- b)) a) (* (* (sinh (/ 1 v)) 2) v))))\n\n(FPCore (cosTheta_i cosTheta_O sinTheta_i sinTheta_O v)\n :name \"HairBSDF, Mp, lower\"\n :precision binary32\n :pre (and (<= -1 cosTheta_i 1) (<= -1 cosTheta_O 1)\n           (<= -1 sinTheta_i 1) (<= -1 sinTheta_O 1)\n           (<= -1.5707964 v 0.1))\n (let ([a (/ (* cosTheta_i cosTheta_O) v)]\n       [b (/ (* sinTheta_i sinTheta_O) v)])\n  (exp (+ (+ (- (- a b) (/ 1 v)) 0.6931f0) (log (/ 1 (* 2 v)))))))\n\n(FPCore (u v)\n :name \"HairBSDF, sample_f, cosTheta\"\n :precision binary32\n :pre (and (<= 1e-5 u 1) (<= 0 v 109.746574))\n (+ 1 (* v (log (+ u (* (- 1 u) (exp (/ -2 v))))))))\n\n(FPCore (sinTheta_O h eta)\n :name \"HairBSDF, gamma for a refracted ray\"\n :precision binary32\n :pre (and (<= -1 sinTheta_O 1)\n           (<= -1 h 1)\n           (<= 0 eta 10))\n (let* ([sqr_sinTheta_O (* sinTheta_O sinTheta_O)]\n        [cosThetaO (sqrt (- 1 sqr_sinTheta_O))])\n  (asin (/ h (sqrt (- (* eta eta) (/ sqr_sinTheta_O cosThetaO)))))))\n\n;; Light sampling functions\n\n(FPCore (ux uy maxCos)\n :name \"UniformSampleCone, x\"\n :precision binary32\n :pre (and (<= 2.328306437e-10 ux 1)\n           (<= 2.328306437e-10 uy 1)\n           (<= 0 maxCos 1))\n (let* ([cosTheta (+ (- 1 ux) (* ux maxCos))]\n        [sinTheta (sqrt (- 1 (* cosTheta cosTheta)))]\n        [phi (* (* uy 2) PI)])\n  (* (cos phi) sinTheta)))\n\n(FPCore (ux uy maxCos)\n :name \"UniformSampleCone, y\"\n :precision binary32\n :pre (and (<= 2.328306437e-10 ux 1)\n           (<= 2.328306437e-10 uy 1)\n           (<= 0 maxCos 1))\n (let* ([cosTheta (+ (- 1 ux) (* ux maxCos))]\n        [sinTheta (sqrt (- 1 (* cosTheta cosTheta)))]\n        [phi (* (* uy 2) PI)])\n  (* (sin phi) sinTheta)))\n\n(FPCore (ux uy maxCos)\n :name \"UniformSampleCone, z\"\n :precision binary32\n :pre (and (<= 2.328306437e-10 ux 1)\n           (<= 2.328306437e-10 uy 1)\n           (<= 0 maxCos 1))\n (let* ([cosTheta (+ (- 1 ux) (* ux maxCos))]\n        [sinTheta (sqrt (- 1 (* cosTheta cosTheta)))]\n        [phi (* (* uy 2) PI)])\n  cosTheta))\n\n;; Unsure on reasonable bounds for xi, yi, zi\n(FPCore (xi yi zi ux uy maxCos)\n :name \"UniformSampleCone 2\"\n :precision binary32\n :pre (and (<= -1e4 xi 1e4) (<= -1e4 yi 1e4) (<= -1e4 zi 1e4)\n           (<= 2.328306437e-10 ux 1) (<= 2.328306437e-10 uy 1)\n           (<= 0 maxCos 1))\n (let* ([cosTheta (* (* (- 1 ux) maxCos) ux)] ; (lerp ux maxCos 1)\n        [sinTheta (sqrt (- 1 (* cosTheta cosTheta)))]\n        [phi (* (* uy 2) PI)])\n  (+ (+ (* (* (cos phi) sinTheta) xi)\n     (* (* (sin phi) sinTheta) yi))\n     (* cosTheta zi))))\n\n(FPCore (normAngle u n0_i n1_i)\n :name \"Curve intersection, scale width based on ribbon orientation\"\n :precision binary32\n :pre (and (<= 0 normAngle (/ PI 2))\n           (<= -1 n0_i 1) (<= -1 n1_i 1)\n           (<= 2.328306437e-10 u 1))\n (let* ([invSinNormAngle (/ 1 (sin normAngle))]\n        [sin0 (* (sin (* (- 1 u) normAngle)) invSinNormAngle)]\n        [sin1 (* (sin (* u normAngle)) invSinNormAngle)])\n  (+ (* sin0 n0_i) (* sin1 n1_i))))\n\n(FPCore (x tau)\n :name \"Lanczos kernel\"\n :precision binary32\n :pre (and (<= 1e-5 x 1) (<= 1 tau 5))\n (let ([xp (* x PI)])\n  (* (/ (sin (* xp tau)) (* xp tau))\n     (/ (sin xp) xp))))\n\n(FPCore (cosTheta_i u1 u2)\n :name \"Beckmann Sample, near normal, slope_x\"\n :precision binary32\n :pre (and (> cosTheta_i 0.9999) (<= cosTheta_i 1)\n           (<= 2.328306437e-10 u1 1) (<= 2.328306437e-10 u2 1))\n (let ([r (sqrt (- (log (- 1 u1))))]\n       [sinPhi (sin (* (* 2 PI) u2))]\n       [cosPhi (cos (* (* 2 PI) u2))])\n  (* r cosPhi)))\n\n(FPCore (cosTheta_i u1 u2)\n :name \"Beckmann Sample, near normal, slope_y\"\n :precision binary32\n :pre (and (> cosTheta_i 0.9999) (<= cosTheta_i 1)\n           (<= 2.328306437e-10 u1 1) (<= 2.328306437e-10 u2 1))\n (let ([r (sqrt (- (log (- 1 u1))))]\n       [sinPhi (sin (* (* 2 PI) u2))]\n       [cosPhi (cos (* (* 2 PI) u2))])\n  (* r sinPhi)))\n\n(FPCore (cosTheta_i u1 u2)\n :name \"Trowbridge-Reitz Sample, near normal, slope_x\"\n :precision binary32\n :pre (and (> cosTheta_i 0.9999) (<= cosTheta_i 1)\n           (<= 2.328306437e-10 u1 1) (<= 2.328306437e-10 u2 1))\n (let ([r (sqrt (/ u1 (- 1 u1)))]\n       [phi (* 6.28318530718 u2)])\n  (* r (cos phi))))\n\n(FPCore (cosTheta_i u1 u2)\n :name \"Trowbridge-Reitz Sample, near normal, slope_y\"\n :precision binary32\n :pre (and (> cosTheta_i 0.9999) (<= cosTheta_i 1)\n           (<= 2.328306437e-10 u1 1) (<= 2.328306437e-10 u2 1))\n (let ([r (sqrt (/ u1 (- 1 u1)))]\n       [phi (* 6.28318530718 u2)])\n  (* r (sin phi))))\n\n(FPCore (u0 u1 alphax alphay)\n :name \"Trowbridge-Reitz Sample, sample surface normal, cosTheta\"\n :precision binary32\n :pre (and (<= 2.328306437e-10 u0 1)\n           (<= 2.328306437e-10 u1 0.5)\n           (<= 0.0001 alphax 1)\n           (<= 0.0001 alphay 1))\n (let* ([phi (atan (* (/ alphay alphax) (tan (+ (* (* 2 PI) u1) (* 0.5 PI)))))]\n        [sinPhi (sin phi)]\n        [cosPhi (cos phi)]\n        [alphax2 (* alphax alphax)]\n        [alphay2 (* alphay alphay)]\n        [alpha2 (/ 1 (+ (/ (* cosPhi cosPhi) alphax2) (/ (* sinPhi sinPhi) alphay2)))]\n        [tanTheta2 (/ (* alpha2 u0) (- 1 u0))])\n  (/ 1 (sqrt (+ 1 tanTheta2)))))\n\n(FPCore (x s)\n :name \"Logistic distribution\"\n :precision binary32\n :pre (<= 0 s 1.0651631)\n (let ([e (exp (/ (- (fabs x)) s))])\n  (/ e (* (* s (+ 1 e)) (+ 1 e)))))\n\n(FPCore (x s)\n :name \"Logistic function\"\n :precision binary32\n :pre (<= 0 s 1.0651631)\n (/ 1 (+ 1 (exp (/ (- x) s)))))\n\n(FPCore (u s)\n :name \"Sample trimmed logistic on [-pi, pi]\"\n :precision binary32\n :pre (and (<= 2.328306437e-10 u 1) (<= 0 s 1.0651631))\n (let* ([lcdf_lo (/ 1 (+ 1 (exp (/ PI s))))]\n        [lcdf_hi (/ 1 (+ 1 (exp (/ (- PI) s))))]\n        [k (- lcdf_hi lcdf_lo)])\n  (* (- s) (log (- (/ 1 (+ (* u k) lcdf_lo)) 1)))))\n\n(FPCore (cosTheta c)\n :name \"Beckmann Sample, normalization factor\"\n :precision binary32\n :pre (and (< 0 cosTheta 0.9999) (< -1 c 1))\n (let* ([sinTheta (sqrt (- (- 1 cosTheta) cosTheta))]\n        [tanTheta (/ sinTheta cosTheta)])\n  (/ 1 (+ (+ 1 c) (* (* (/ 1 (sqrt PI)) tanTheta) (exp (* (- cosTheta) cosTheta)))))))\n\n(FPCore (alpha u0)\n :name \"Beckmann Distribution sample, tan2theta, alphax == alphay\"\n :precision binary32\n :pre (and (<= 0.0001 alpha 1) (<= 2.328306437e-10 u0 1))\n (* (* (- alpha) alpha) (log (- 1 u0))))\n    \n(FPCore (alphax alphay u0 cos2phi sin2phi)\n :name \"Beckmann Distribution sample, tan2theta, alphax != alphay, u1 <= 0.5\"\n :precision binary32\n :pre (and (<= 0.0001 alphax 1) (<= 0.0001 alphay 1) (<= 2.328306437e-10 u0 1)\n           (<= 0 cos2phi 1) (<= 0 sin2phi))\n (let ([alphax2 (* alphax alphax)]\n       [alphay2 (* alphay alphay)])\n  (/ (- (log (- 1 u0))) (+ (/ cos2phi alphax2) (/ sin2phi alphay2)))))\n\n; TODO: find better upper bound on 's' for Disney BSSRDF...\n\n(FPCore (s r)\n :name \"Disney BSSRDF, PDF of scattering profile\"\n :precision binary32\n :pre (and (<= 0 s 256) (< 1e-6 r 1e6))\n (+ (/ (* 0.25 (exp (/ (- r) s))) (* (* (* 2 PI) s) r))\n    (/ (* 0.75 (exp (/ (- r) (* 3 s)))) (* (* (* 6 PI) s) r))))\n\n(FPCore (s u)\n :name \"Disney BSSRDF, sample scattering profile, lower\"\n :precision binary32\n :pre (and (<= 0 s 256) (<= 2.328306437e-10 u 0.25))\n (* s (log (/ 1 (- 1 (* 4 u))))))\n\n(FPCore (s u)\n :name \"Disney BSSRDF, sample scattering profile, upper\"\n :precision binary32\n :pre (and (<= 0 s 256) (<= 0.25 u 1))\n (* (* 3 s) (log (/ 1 (- 1 (/ (- u 0.25) 0.75))))))\n\n(FPCore (cosTheta alpha)\n :name \"GTR1 distribution\"\n :precision binary32\n :pre (and (<= 0 cosTheta 1) (<= 0.0001 alpha 1))\n (let ([alpha2 (* alpha alpha)])\n  (/ (- alpha2 1) (* (* PI (log alpha2)) (+ 1 (* (* (- alpha2 1) cosTheta) cosTheta))))))\n"
  },
  {
    "path": "bench/hamming/machine-decide.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (a x)\n :name \"expax (section 3.5)\"\n ;:herbie-expected 14\n :pre (> 710 (* a x))\n ; Hamming suggests using Taylor expansion for ax small\n ; We use expm1 as it specifically avoids cancellation for ax small\n :alt \n (! :herbie-platform c (expm1 (* a x)))\n\n (- (exp (* a x)) 1))\n"
  },
  {
    "path": "bench/hamming/overflow-underflow.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (x)\n :name \"expq2 (section 3.11)\"\n :pre (> 710 x)\n ; Hamming version (1/1 - e^-x) was not accurate. Dealt with overflow/underflow but not cancellation.\n ; Used expm1 from libm to deal with cancellation.\n :alt \n (! :herbie-platform c\n  (/ (- 1) (expm1 (- x))))\n\n (/ (exp x) (- (exp x) 1)))\n"
  },
  {
    "path": "bench/hamming/quadratic.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (a b c)\n :name \"quadp (p42, positive)\"\n :herbie-expected 10\n ; From Racket Math Lib implementation\n :alt \n (! :herbie-platform c\n  (let ([sqtD\n   (let ([x (* (sqrt (fabs a)) (sqrt (fabs c)))])\n    (if (== (copysign a c) a)\n      (* (sqrt (- (fabs (/ b 2)) x)) (sqrt (+ (fabs (/ b 2)) x)))\n      (hypot (/ b 2) x)))])\n    (if (< b 0) (/ (- sqtD (/ b 2)) a)\n      (/ (- c) (+ (/ b 2) sqtD)))))\n\n (let ([d (sqrt (- (* b b) (* 4 (* a c))))])\n   (/ (+ (- b) d) (* 2 a))))\n\n(FPCore (a b c)\n :name \"quadm (p42, negative)\"\n :herbie-expected 10\n ; From Racket Math Lib implementation\n :alt \n (! :herbie-platform c\n  (let ([sqtD\n   (let ([x (* (sqrt (fabs a)) (sqrt (fabs c)))])\n    (if (== (copysign a c) a)\n      (* (sqrt (- (fabs (/ b 2)) x)) (sqrt (+ (fabs (/ b 2)) x)))\n      (hypot (/ b 2) x)))])\n    (if (< b 0) (/ c (- sqtD (/ b 2)))\n      (/ (+ (/ b 2) sqtD) (- a)))))\n\n (let ([d (sqrt (- (* b b) (* 4 (* a c))))])\n   (/ (- (- b) d) (* 2 a))))\n\n(FPCore (a b_2 c)\n :name \"quad2m (problem 3.2.1, negative)\"\n :herbie-expected 10\n ; From Racket Math Lib implementation\n :alt \n (! :herbie-platform c\n  (let ([sqtD\n   (let ([x (* (sqrt (fabs a)) (sqrt (fabs c)))])\n    (if (== (copysign a c) a)\n      (* (sqrt (- (fabs b_2) x)) (sqrt (+ (fabs b_2) x)))\n      (hypot b_2 x)))])\n    (if (< b_2 0) (/ c (- sqtD b_2))\n      (/ (+ b_2 sqtD) (- a)))))\n\n (let ([d (sqrt (- (* b_2 b_2) (* a c)))])\n   (/ (- (- b_2) d) a)))\n\n(FPCore (a b_2 c)\n :name \"quad2p (problem 3.2.1, positive)\"\n :herbie-expected 10\n ; From Racket Math Lib implementation\n :alt \n (! :herbie-platform c \n  (let ([sqtD\n   (let ([x (* (sqrt (fabs a)) (sqrt (fabs c)))])\n    (if (== (copysign a c) a)\n      (* (sqrt (- (fabs b_2) x)) (sqrt (+ (fabs b_2) x)))\n      (hypot b_2 x)))])\n    (if (< b_2 0) (/ (- sqtD b_2) a)\n      (/ (- c) (+ b_2 sqtD)))))\n\n (let ([d (sqrt (- (* b_2 b_2) (* a c)))])\n   (/ (+ (- b_2) d) a)))\n"
  },
  {
    "path": "bench/hamming/rearrangement.fpcore",
    "content": "; -*- mode: scheme -*-\n\n; The precondition for this expression is labelled as for large x hence we choose this\n; range that contains all the relevant values that are sampled. The proof that they\n; are equivalent is by rationalizing the denominator by multiplying both the\n; numerator and denominator by the conjugate of the denominator and simplifying using \n; the identity a^2-b^2 = (a+b)(a-b) and cancellation.\n(FPCore (x)\n :name \"2sqrt (example 3.1)\"\n :pre (and (> x 1) (< x 1e+308))\n :alt \n (! :herbie-platform c\n  (/ 1 (+ (sqrt (+ x 1)) (sqrt x))))\n\n :alt\n (! :herbie-platform c \n  (* 0.5 (pow x -0.5)))\n\n (- (sqrt (+ x 1)) (sqrt x)))\n\n; The precondition for this expression is labelled as for large x hence we choose this\n; range that contains all the relevant values that are sampled. The proof that they\n; are equivalent is by rationalizing the denominator by multiplying both the\n; numerator and denominator by the conjugate of the denominator and simplifying using \n; the identity a^2-b^2 = (a+b)(a-b) and cancellation.\n(FPCore (x)\n :name \"2isqrt (example 3.6)\"\n :pre (and (> x 1) (< x 1e+308))\n :alt \n (! :herbie-platform c\n  (/ 1 (+ (* (+ x 1) (sqrt x)) (* x (sqrt (+ x 1))))))\n\n :alt\n (! :herbie-platform c\n  (- (pow x -0.5) (pow (+ x 1) -0.5)))\n\n (- (/ 1 (sqrt x)) (/ 1 (sqrt (+ x 1)))))\n\n(FPCore (x)\n :name \"2frac (problem 3.3.1)\"\n\n :alt\n (! :herbie-platform c\n  (/ (/ -1 x) (+ x 1)))\n\n :alt\n (! :herbie-platform c\n  (/ 1 (* x (- -1 x))))\n\n (- (/ 1 (+ x 1)) (/ 1 x)))\n\n(FPCore (x)\n :name \"3frac (problem 3.3.3)\"\n ; Rewrite comes from Hammings textbook on page 46. Hamming says to sample large x\n ; Half of floating point numbers are > 1 so this will sample large enough x.\n :pre (> (fabs x) 1)\n :alt \n (! :herbie-platform c\n  (/ 2 (* x (- (* x x) 1))))\n\n (+ (- (/ 1 (+ x 1)) (/ 2 x)) (/ 1 (- x 1))))\n\n; The precondition for this expression is labelled as for large x hence we choose this\n; range that contains all the relevant values that are sampled. The proof that they\n; are equivalent is by rewriting the two terms as a = (cbrt (+ x 1)) and b = (cbrt x)\n; and then using the trigonometric identity for a^3-b^3 where (a-b) is the term we\n; equate to (/ (- (pow a 3) (pow b 3)) (+ (pow a 2) (* a b) (pow b 2))), and then cancel values.\n(FPCore (x)\n :name \"2cbrt (problem 3.3.4)\"\n :pre (and (> x 1) (< x 1e+308))\n :herbie-expected 2.5\n :alt \n (! :herbie-platform c\n  (/ 1 (+ (* (cbrt (+ x 1)) (cbrt (+ x 1))) (* (cbrt x) (cbrt (+ x 1))) (* (cbrt x) (cbrt x)))))\n \n (- (cbrt (+ x 1)) (cbrt x)))\n\n; This is a slightly unique rewrite because it involves the use of the c function log1p \n; as Hamming gave this as an exercise with no real hint on how to approach this.\n; For the precondition we want large values of N as described by Hamming. Hence, we chose the range for reasonable\n; values for which this could be queried and have relevant sampling and still being described as a large enough N.\n; log1p(x) simply returns log(1+x) but computed in a way that is accurate even when the value of number is close to zero.\n; Hence, after rearranging the expression using log-rewrite to get us (log (/ (+ N 1) N)) = (log (+ 1 (/ 1 N))), we can\n; find the term to be used in place of x to call log1p\n(FPCore (N)\n :name \"2log (problem 3.3.6)\"\n :pre (and (> N 1) (< N 1e+40))\n :alt \n (! :herbie-platform c\n  (log1p (/ 1 N)))\n\n :alt \n (! :herbie-platform c\n  (log (+ 1 (/ 1 N))))\n\n :alt \n (! :herbie-platform c\n  (+ (/ 1 N) (/ -1 (* 2 (pow N 2))) (/ 1 (* 3 (pow N 3))) (/ -1 (* 4 (pow N 4)))))\n\n (- (log (+ N 1)) (log N)))\n\n; Commented out explanation for platforms\n; Talking about the else case first, this is simply a log-rewrite which is (log(/ a b)) = (- (log a) (log b))\n; with N being cancelled in the numerator and denominator.\n; Now for the reason for the if-case and the 1e+3 value is because while on sampling in Herbie reports and Odyssey,\n; the sampled values for this equation is extremely inaccurate after this range. There could be a possible overflow or \n; another reason but we have consistently noted that this exists. Hence, we chose the next best case\n; which is a Taylor series until the 4-th power, preventing too much of computation power while giving\n; the best answer for that range.\n\n\n(FPCore (x)\n :name \"exp2 (problem 3.3.7)\"\n :pre (<= (fabs x) 710)\n ; Bounded x on the extremes  by +/- 710 to avoid sampling infinite outputs\n ; Target comes from Hamming's textbook, page 46\n :alt \n (! :herbie-platform c\n  (* 4 (* (sinh (/ x 2)) (sinh (/ x 2)))))\n\n (+ (- (exp x) 2) (exp (- x))))\n"
  },
  {
    "path": "bench/hamming/series.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (x)\n :name \"expm1 (example 3.7)\"\n ; We want to sample around 0 according to Hamming. We can sample more inputs closer to zero by shrinking the range to +/- 1\n :pre (<= (fabs x) 1)\n ; Hamming suggests taylor series expansion but we have libm functions in FPCore for the c platform\n :alt \n (! :herbie-platform c (expm1 x))\n\n (- (exp x) 1))\n\n(FPCore (n)\n :name \"logs (example 3.8)\"\n :pre (> n 6.8e+15)\n :alt \n (! :herbie-platform c\n  (- (log (+ n 1)) (- (/ 1 (* 2 n)) (- (/ 1 (* 3 (* n n))) (/ 4 (pow n 3))))))\n\n (- (- (* (+ n 1) (log (+ n 1))) (* n (log n))) 1))\n\n(FPCore (x)\n :name \"invcot (example 3.9)\"\n :pre (and (< -0.026 x) (< x 0.026))\n :alt \n (! :herbie-platform c\n  (if (< (fabs x) 0.026)\n     (* (/ x 3) (+ 1 (/ (* x x) 15)))\n     (- (/ 1 x) (/ 1 (tan x)))))\n\n (- (/ 1 x) (/ 1 (tan x))))\n\n(FPCore (x)\n :name \"qlog (example 3.10)\"\n ; We want to sample small x according to Hamming. We can sample more inputs closer to zero by shrinking the range to +/- 1\n :pre (<= (fabs x) 1)\n ; Hamming suggests using Taylor expansion but until we have platforms, we will use FPCore's access to c functions.\n :alt \n (! :herbie-platform c\n  (/ (log1p (- x)) (log1p x)))\n\n (/ (log (- 1 x)) (log (+ 1 x))))\n\n(FPCore (x)\n :name \"cos2 (problem 3.4.1)\"\n (/ (- 1 (cos x)) (* x x)))\n\n(FPCore (a b eps)\n :name \"expq3 (problem 3.4.2)\"\n :pre (and (<= (fabs a) 710) (<= (fabs b) 710) (<= (* 1e-27 (fmin (fabs a) (fabs b))) eps (fmin (fabs a) (fabs b))))\n ; We want epsilon small compared to a and b according to Hamming. In the precondition we force eps to be smaller in magnitude\n ; than the smaller between a and b but don't force one to be smaller than the other in order to test to see if Herbie can figure it out. \n ; Bound by 710 to avoid sampling infinite values since we have an exponential.\n ; Chose a multiplicative factor of 1e-27 compared to a in order to not sample epsilon to close to 0 which eliminates the exponent.\n \n ; Hammings' rewrite, page 48\n :alt \n (! :herbie-platform c\n  (+ (/ 1 a) (/ 1 b)))\n\n (/\n  (* eps (- (exp (* (+ a b) eps)) 1))\n  (* (- (exp (* a eps)) 1) (- (exp (* b eps)) 1))))\n\n(FPCore (eps)\n :name \"logq (problem 3.4.3)\"\n ; Using previous notions of small epsilon, simply < +/- 1\n :pre (< (fabs eps) 1)\n ; Hamming suggests using Taylor expansion but FPCore has libm which is contained on the \"c\" platform.\n :alt \n (! :herbie-platform c\n  (- (log1p (- eps)) (log1p eps)))\n\n (log (/ (- 1 eps) (+ 1 eps))))\n\n(FPCore (x)\n :name \"sqrtexp (problem 3.4.4)\"\n (sqrt (/ (- (exp (* 2 x)) 1) (- (exp x) 1))))\n\n(FPCore (x n)\n :name \"2nthrt (problem 3.4.6)\"\n (- (pow (+ x 1) (/ 1 n)) (pow x (/ 1 n))))\n"
  },
  {
    "path": "bench/hamming/trigonometry.fpcore",
    "content": "; -*- mode: scheme -*-\n\n; Most of the below functions (except sintan) are subsets of the rearrangement functions. However, these\n; are specific to trigonometric functions as it deals with a subtraction of two trig functions that at\n; a very large value cause cancellation and need to be rewritten to ensure floating point accuracy based on\n; their nature of expression (more in specific detail below).\n\n; Almost all expressions follow this precondition : -1e4 <= x <= 1e4 and 1e-16 * (abs x) < eps < (abs x)\n; Our reasoning for this stems from Hamming's explanation that eps is small with respect to x, hence for \n; getting the highest accuracy we are bounding it's lowest value to be 1e-16 times (abs x). We don't\n; query anything below because we don't want (x+eps) ~ x. And we also want values of x that would be usable\n; and relevant for most trigonometric queries as well as those that are the most sampled in Herbie\n\n\n; 2sin involves the difference of two sine functions. According to the sum-to-product trigonometric identity,\n; the target for this benchmark can apply the identity (- (sin x) (sin y)) = (* 2 (cos (/ (+ x y) 2)) (sin (/ (- x y) 2)))\n(FPCore (x eps)\n  :name \"2sin (example 3.3)\"\n  :pre (and (<= -1e4 x) (<= x 1e4) (< (* 1e-16 (fabs x)) eps) (< eps (* (fabs x))))\n  :alt \n  (! :herbie-platform c\n   (* 2 (cos (+ x (/ eps 2))) (sin (/ eps 2))))\n\n  :alt \n  (! :herbie-platform c\n    (+ (* (sin x) (- (cos eps) 1)) (* (cos x) (sin eps))))\n\n  :alt \n  (! :herbie-platform c\n    (* (cos (* 0.5 (- eps (* -2 x)))) (sin (* 0.5 eps)) 2))\n \n  (- (sin (+ x eps)) (sin x)))\n\n\n; 2cos involves the difference of two cos functions. According to the sum-to-product trigonometric identity,\n; the target for this benchmark can apply the identity (- (cos x) (cos y)) = (* 2 (sin (/ (+ x y) 2)) (sin (/ (- x y) 2)))\n(FPCore (x eps)\n :name \"2cos (problem 3.3.5)\"\n :pre (and (<= -1e4 x) (<= x 1e4) (< (* 1e-16 (fabs x)) eps) (< eps (* (fabs x))))\n :alt \n (! :herbie-platform c\n  (* -2 (sin (+ x (/ eps 2))) (sin (/ eps 2))))\n\n :alt \n (! :herbie-platform c\n  (pow (cbrt (* -2 (sin (* 0.5 (fma 2.0 x eps))) (sin (* 0.5 eps)) )) 3))\n\n (- (cos (+ x eps)) (cos x)))\n\n\n; 2tan involves the difference of two tan functions. A slightly more intuitive proof, this involves\n; converting the two tan into (- (/ (sin (+ x eps) (cos (+ x eps)))) (/ (sin x) (cos x))). After cross\n; multiplying we get the massive formula (/ (- (* (sin (+ x eps)) (cos x)) (* (sin x) (cos (+ x eps)))) (* (cos (+ x eps)) (cos x)))\n; Fortunately, the numerator is just an expansion of the identity sin(a-b) where a = x+eps and b = x.\n; Hence, we can simply use that identity to craft the numerator and leaving the denominator as is.\n(FPCore (x eps)\n :name \"2tan (problem 3.3.2)\"\n :pre (and (<= -1e4 x) (<= x 1e4) (< (* 1e-16 (fabs x)) eps) (< eps (* (fabs x))))\n :alt \n (! :herbie-platform c\n  (/ (sin eps) (* (cos x) (cos (+ x eps)))))\n\n :alt \n (! :herbie-platform c\n  (- (/ (+ (tan x) (tan eps)) (- 1 (* (tan x) (tan eps)))) (tan x)))\n\n :alt \n (! :herbie-platform c\n  (+ eps (* eps (tan x) (tan x))))\n\n (- (tan (+ x eps)) (tan x)))\n\n\n; This is directly taken from the Hamming textbook but this is a direct identity of the trig half identity\n; for tan, and we completely remove any trace of a subtraction using this, fulfilling our goal.\n; As a result, we can query any value of x from -infinity to +infinity as we eliminated any cause\n; of the error using this rewrite.\n(FPCore (x)\n :name \"tanhf (example 3.4)\"\n :alt \n (! :herbie-platform c\n  (tan (/ x 2)))\n\n (/ (- 1 (cos x)) (sin x)))\n\n\n; Noting the difference in the variable name, N is actually a large N. Hence, we are changing our precondition\n; definition by including all values of N till 1e+100. \n; For the rewrite, we use the trigonometric identity, (- (atan x) (atan y)) = (atan (/ (- x y) (+ 1 (* x y))))\n(FPCore (N)\n :name \"2atan (example 3.5)\"\n :pre (and (> N 1) (< N 1e+100))\n :alt \n (! :herbie-platform c\n  (atan (/ 1 (+ 1 (* N (+ N 1))))))\n \n :alt \n (! :herbie-platform c\n  (atan2 1 (fma N (+ 1 N) 1)))\n\n (- (atan (+ N 1)) (atan N)))\n\n\n; This is a slightly unique rewrite because it involves two different trigonometric functions that don't have\n; a direct rewrite. Moreover, Hamming gave this as an exercise with no real hint on how to approach this.\n; Hence, we resort to the Taylor series of this identity where the rewrite for all values for (<= (fabs x) 1)\n; rewrites to a Taylor series otherwise the general identity works great enough.\n; The reason for this is because when x is in the vicinity of 0, both the numerator and denominator have A\n; a lot of error according to the sampling, either possibly because of underflow and/or because x ~ (sin x) ~ (tan x).\n; Hence, the Taylor series until the 6-th power is chosen to not prevent too much of computation power while giving\n; the best answer for that range.\n(FPCore (eps)\n :name \"sintan (problem 3.4.5)\"\n :pre (and (<= -0.4 eps) (<= eps 0.4))\n :alt \n (! :herbie-platform c\n  (+ -0.5 (/ (* 9 (* eps eps)) 40) (/ (* -27 (* eps eps eps eps)) 2800) (/ (* 27 (* eps eps eps eps eps eps)) 112000)))\n\n :alt\n (! :herbie-platform c\n  (- (* 0.225 eps eps) 0.5))\n\n (/ (- eps (sin eps)) (- eps (tan eps))))\n"
  },
  {
    "path": "bench/haskell.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (x y)\n :name \"Optimisation.CirclePacking:place from circle-packing-0.1.0.4, A\"\n (sqrt (+ x y)))\n\n(FPCore (x y z t)\n :name \"Optimisation.CirclePacking:place from circle-packing-0.1.0.4, B\"\n (/ (- (+ x y) z) (* t 2.0)))\n\n(FPCore (x y)\n :name \"Optimisation.CirclePacking:place from circle-packing-0.1.0.4, C\"\n (sqrt (fabs (- x y))))\n\n\n(FPCore (x y z t)\n :name \"Optimisation.CirclePacking:place from circle-packing-0.1.0.4, D\"\n :alt \n (! :herbie-platform default (- x (+ (* x (/ y t)) (* (- z) (/ y t)))))\n\n (+ x (/ (* y (- z x)) t)))\n\n(FPCore  (x y z t a)\n :name \"Optimisation.CirclePacking:place from circle-packing-0.1.0.4, E\"\n :alt \n (! :herbie-platform default \n  (if (< y -1.0761266216389975e-10)\n   (+ x (/ 1 (/ (/ a (- z t)) y)))\n    (if (< y 2.894426862792089e-49)\n     (+ x (/ (* y (- z t)) a))\n     (+ x (/ y (/ a (- z t)))))))\n \n (+ x (/ (* y (- z t)) a)))\n\n(FPCore  (x y z t a)\n :name \"Optimisation.CirclePacking:place from circle-packing-0.1.0.4, F\"\n :alt \n (! :herbie-platform default\n  (if (< y -1.0761266216389975e-10)\n    (- x (/ 1 (/ (/ a (- z t)) y)))\n    (if (< y 2.894426862792089e-49)\n      (- x (/ (* y (- z t)) a))\n      (- x (/ y (/ a (- z t)))))))\n\n (- x (/ (* y (- z t)) a)))\n\n(FPCore  (x y z)\n :name \"Optimisation.CirclePacking:place from circle-packing-0.1.0.4, G\"\n (* (+ x y) (+ z 1.0)))\n\n(FPCore  (x y z)\n :name \"Optimisation.CirclePacking:place from circle-packing-0.1.0.4, H\"\n (* (+ x y) (- 1.0 z)))\n\n(FPCore  (x y z)\n :name \"Optimisation.CirclePacking:place from circle-packing-0.1.0.4, I\"\n (+ (+ x y) z))\n\n(FPCore  (x y z t a b c i j)\n :name \"Data.Colour.Matrix:determinant from colour-2.3.3, A\"\n :alt \n (! :herbie-platform default\n  (if (< x -1.469694296777705e-64)\n   (+\n    (-\n     (* x (- (* y z) (* t a)))\n     (/ (* b (- (pow (* c z) 2) (pow (* t i) 2))) (+ (* c z) (* t i))))\n    (* j (- (* c a) (* y i))))\n   (if (< x 3.2113527362226803e-147)\n     (- (* (- (* b i) (* x a)) t) (- (* z (* c b)) (* j (- (* c a) (* y i)))))\n     (+\n      (-\n       (* x (- (* y z) (* t a)))\n       (/ (* b (- (pow (* c z) 2) (pow (* t i) 2))) (+ (* c z) (* t i))))\n      (* j (- (* c a) (* y i)))))))\n (+\n  (- (* x (- (* y z) (* t a))) (* b (- (* c z) (* t i))))\n  (* j (- (* c a) (* y i)))))\n\n(FPCore  (x y z t a)\n :name \"Data.Colour.Matrix:inverse from colour-2.3.3, B\"\n :alt \n (! :herbie-platform default\n  (if (< z -2.468684968699548e+170)\n   (- (* (/ y a) x) (* (/ t a) z))\n   (if (< z 6.309831121978371e-71)\n     (/ (- (* x y) (* z t)) a)\n     (- (* (/ y a) x) (* (/ t a) z)))))\n (/ (- (* x y) (* z t)) a))\n\n(FPCore  (x y)\n :name \"Data.Colour.CIE.Chromaticity:chromaCoords from colour-2.3.3\"\n (- (- 1.0 x) y))\n\n(FPCore  (x y)\n :name \"Data.Colour.RGB:hslsv from colour-2.3.3, A\"\n (/ (+ x y) 2.0))\n\n(FPCore  (x y z t a)\n :name \"Data.Colour.RGB:hslsv from colour-2.3.3, B\"\n :alt \n (! :herbie-platform default (+ (/ 60.0 (/ (- z t) (- x y))) (* a 120.0)))\n\n (+ (/ (* 60.0 (- x y)) (- z t)) (* a 120.0)))\n\n(FPCore  (x y)\n :name \"Data.Colour.RGB:hslsv from colour-2.3.3, C\"\n :alt \n (! :herbie-platform default (- (/ x (- 2.0 (+ x y))) (/ y (- 2.0 (+ x y)))))\n\n (/ (- x y) (- 2.0 (+ x y))))\n\n(FPCore  (x y)\n :name \"Data.Colour.RGB:hslsv from colour-2.3.3, D\"\n :alt \n (! :herbie-platform default (- (/ x (+ x y)) (/ y (+ x y))))\n\n (/ (- x y) (+ x y)))\n\n(FPCore  (x y)\n :name \"Data.Colour.RGB:hslsv from colour-2.3.3, E\"\n :alt \n (! :herbie-platform default (- 1 (/ y x)))\n\n (/ (- x y) x))\n\n(FPCore  (x y)\n :name \"Data.Colour.RGBSpace.HSL:hsl from colour-2.3.3, A\"\n (- (+ x y) (* x y)))\n\n(FPCore  (x y)\n :name \"Data.Colour.RGBSpace.HSL:hsl from colour-2.3.3, B\"\n :alt \n (! :herbie-platform default (+ x (* x y)))\n\n (* x (+ y 1.0)))\n\n(FPCore  (x y)\n :name \"Data.Colour.RGBSpace.HSL:hsl from colour-2.3.3, C\"\n (- (* x 2.0) y))\n\n(FPCore  (x y z)\n :name \"Data.Colour.RGBSpace.HSL:hsl from colour-2.3.3, D\"\n (+ x (* (* (- y x) 6.0) (- (/ 2.0 3.0) z))))\n\n(FPCore  (x y z)\n :name \"Data.Colour.RGBSpace.HSL:hsl from colour-2.3.3, E\"\n :alt \n (! :herbie-platform default (- x (* (* 6.0 z) (- x y))))\n\n (+ x (* (* (- y x) 6.0) z)))\n\n(FPCore  (x)\n :name \"Data.Colour.RGBSpace.HSL:hsl from colour-2.3.3, F\"\n (+ x (/ 1.0 3.0)))\n\n(FPCore  (x)\n :name \"Data.Colour.RGBSpace.HSL:hsl from colour-2.3.3, G\"\n (- x (/ 1.0 3.0)))\n\n(FPCore  (x y)\n :name \"Data.Colour.RGBSpace.HSV:hsv from colour-2.3.3, H\"\n (* x (- 1.0 y)))\n\n(FPCore  (x y z)\n :name \"Data.Colour.RGBSpace.HSV:hsv from colour-2.3.3, I\"\n (* x (- 1.0 (* y z))))\n\n(FPCore  (x y z)\n :name \"Data.Colour.RGBSpace.HSV:hsv from colour-2.3.3, J\"\n :alt \n (! :herbie-platform default\n  (if (< (* x (- 1.0 (* (- 1.0 y) z))) -1.618195973607049e+50)\n   (+ x (* (- 1.0 y) (* (- z) x)))\n   (if (< (* x (- 1.0 (* (- 1.0 y) z))) 3.892237649663903e+134)\n     (- (* (* x y) z) (- (* x z) x))\n     (+ x (* (- 1.0 y) (* (- z) x))))))\n\n (* x (- 1.0 (* (- 1.0 y) z))))\n\n(FPCore  (x y)\n :name \"Data.Colour.SRGB:invTransferFunction from colour-2.3.3\"\n (/ (+ x y) (+ y 1.0)))\n\n(FPCore  (x y)\n :name \"Data.Colour.SRGB:transferFunction from colour-2.3.3\"\n (- (* (+ x 1.0) y) x))\n\n(FPCore  (x)\n :name \"Data.Colour.CIE:lightness from colour-2.3.3\"\n (- (* x 116.0) 16.0))\n\n(FPCore  (x)\n :name \"Data.Colour.CIE:cieLABView from colour-2.3.3, A\"\n (+ (* (/ 841.0 108.0) x) (/ 4.0 29.0)))\n\n(FPCore  (x y)\n :name \"Data.Colour.CIE:cieLABView from colour-2.3.3, B\"\n (* 500.0 (- x y)))\n\n(FPCore  (x y)\n :name \"Data.Colour.CIE:cieLABView from colour-2.3.3, C\"\n (* 200.0 (- x y)))\n\n(FPCore  (x y)\n :name \"Data.Colour.CIE:cieLAB from colour-2.3.3, A\"\n :alt \n (! :herbie-platform default (* y (- (* x 3.0) 0.41379310344827586)))\n\n (* (* (- x (/ 16.0 116.0)) 3.0) y))\n\n(FPCore  (x)\n :name \"Data.Colour.CIE:cieLAB from colour-2.3.3, B\"\n (/ (+ x 16.0) 116.0))\n\n(FPCore  (x y)\n :name \"Data.Colour.CIE:cieLAB from colour-2.3.3, C\"\n (+ x (/ y 500.0)))\n\n(FPCore  (x y)\n :name \"Data.Colour.CIE:cieLAB from colour-2.3.3, D\"\n (- x (/ y 200.0)))\n\n(FPCore  (x y z t a)\n :name \"Diagrams.Solve.Tridiagonal:solveTriDiagonal from diagrams-solve-0.1, A\"\n :alt \n (! :herbie-platform default\n  (if (< z -32113435955957344.0)\n   (- (/ x (- t (* a z))) (/ y (- (/ t z) a)))\n   (if (< z 3.5139522372978296e-86)\n     (* (- x (* y z)) (/ 1 (- t (* a z))))\n     (- (/ x (- t (* a z))) (/ y (- (/ t z) a))))))\n\n (/ (- x (* y z)) (- t (* a z))))\n\n(FPCore  (x y z t)\n :name \"Diagrams.Solve.Tridiagonal:solveTriDiagonal from diagrams-solve-0.1, B\"\n :alt \n (! :herbie-platform default\n  (if (< x -1.618195973607049e+50)\n   (/ 1 (- (/ y x) (* (/ z x) t)))\n   (if (< x 2.1378306434876444e+131)\n     (/ x (- y (* z t)))\n     (/ 1 (- (/ y x) (* (/ z x) t))))))\n\n (/ x (- y (* z t))))\n\n(FPCore  (x y z)\n :name \"Diagrams.Solve.Tridiagonal:solveTriDiagonal from diagrams-solve-0.1, C\"\n :alt \n (! :herbie-platform default \n  (/ (+ x (* y z)) (/ (+ x (* y z)) (- x (* y z)))))\n\n (- x (* y z)))\n\n(FPCore  (x y z)\n :name \"Diagrams.Solve.Tridiagonal:solveCyclicTriDiagonal from diagrams-solve-0.1, A\"\n :alt \n (! :herbie-platform default\n  (if (< z -4.262230790519429e-138)\n   (/ (* x y) z)\n   (if (< z 1.7042130660650472e-164) (/ x (/ z y)) (* (/ x z) y))))\n\n (/ (* x y) z))\n\n(FPCore  (x y z t a b)\n :name \"Diagrams.Solve.Tridiagonal:solveCyclicTriDiagonal from diagrams-solve-0.1, B\"\n :alt \n (! :herbie-platform default\n  (if (< t -1.3659085366310088e-271)\n   (* 1 (* (+ x (* (/ y t) z)) (/ 1 (+ (+ a 1.0) (* (/ y t) b)))))\n   (if (< t 3.036967103737246e-130)\n     (/ z b)\n     (* 1 (* (+ x (* (/ y t) z)) (/ 1 (+ (+ a 1.0) (* (/ y t) b))))))))\n\n (/ (+ x (/ (* y z) t)) (+ (+ a 1.0) (/ (* y b) t))))\n\n(FPCore  (x y z)\n :name \"Diagrams.Solve.Polynomial:quadForm from diagrams-solve-0.1, A\"\n (- x (* (* y 4.0) z)))\n\n(FPCore  (x y z)\n :name \"Diagrams.Solve.Polynomial:quadForm from diagrams-solve-0.1, B\"\n (* (/ 1.0 2.0) (+ x (* y (sqrt z)))))\n\n(FPCore  (x y)\n :name \"Diagrams.Solve.Polynomial:quadForm from diagrams-solve-0.1, C\"\n (/ x (* y 2.0)))\n\n(FPCore  (x y z t a b)\n :name \"Diagrams.Solve.Polynomial:cubForm  from diagrams-solve-0.1, A\"\n :alt \n (! :herbie-platform default\n  (if (< y 7.590524218811189e-161)\n   (+ (- (* x 2.0) (* (* (* y 9.0) z) t)) (* a (* 27.0 b)))\n   (+ (- (* x 2.0) (* 9.0 (* y (* t z)))) (* (* a 27.0) b))))\n\n (+ (- (* x 2.0) (* (* (* y 9.0) z) t)) (* (* a 27.0) b)))\n\n(FPCore  (x y z)\n :name \"Diagrams.Solve.Polynomial:cubForm  from diagrams-solve-0.1, B\"\n :alt \n (! :herbie-platform default (- (* x (* 3.0 y)) z))\n\n (- (* (* x 3.0) y) z))\n\n(FPCore  (x y)\n :name \"Diagrams.Solve.Polynomial:cubForm  from diagrams-solve-0.1, C\"\n :alt \n (! :herbie-platform default (/ (/ x y) 3.0))\n\n (/ x (* y 3.0)))\n\n(FPCore  (x y z t)\n :name \"Diagrams.Solve.Polynomial:cubForm  from diagrams-solve-0.1, D\"\n :alt \n (! :herbie-platform default\n  (/ (acos (* (/ (/ x 27.0) (* y z)) (/ (sqrt t) (/ 2.0 3.0)))) 3.0))\n\n (* (/ 1.0 3.0) (acos (* (/ (* 3.0 (/ x (* y 27.0))) (* z 2.0)) (sqrt t)))))\n\n(FPCore  (x y z t a b c i j k)\n :name \"Diagrams.Solve.Polynomial:cubForm  from diagrams-solve-0.1, E\"\n :alt \n (! :herbie-platform default\n  (if (< t -1.6210815397541398e-69)\n   (-\n    (- (* (* 18.0 t) (* (* x y) z)) (* (+ (* a t) (* i x)) 4.0))\n    (- (* (* k j) 27.0) (* c b)))\n   (if (< t 165.68027943805222)\n     (+\n      (- (* (* 18.0 y) (* x (* z t))) (* (+ (* a t) (* i x)) 4.0))\n      (- (* c b) (* 27.0 (* k j))))\n     (-\n      (- (* (* 18.0 t) (* (* x y) z)) (* (+ (* a t) (* i x)) 4.0))\n      (- (* (* k j) 27.0) (* c b))))))\n (-\n  (-\n   (+ (- (* (* (* (* x 18.0) y) z) t) (* (* a 4.0) t)) (* b c))\n   (* (* x 4.0) i))\n  (* (* j 27.0) k)))\n\n(FPCore  (x y)\n :name \"Diagrams.Solve.Polynomial:cubForm  from diagrams-solve-0.1, F\"\n (* (* x 27.0) y))\n\n(FPCore  (x y)\n :name \"Diagrams.Solve.Polynomial:cubForm  from diagrams-solve-0.1, G\"\n :alt \n (! :herbie-platform default (/ (+ x y) 2.0))\n\n (* (/ 1.0 2.0) (+ x y)))\n\n(FPCore  (x y z t)\n :name \"Diagrams.Solve.Polynomial:cubForm  from diagrams-solve-0.1, H\"\n :alt \n (! :herbie-platform default\n  (+ (- x (/ y (* z 3.0))) (/ (/ t (* z 3.0)) y)))\n\n (+ (- x (/ y (* z 3.0))) (/ t (* (* z 3.0) y))))\n\n(FPCore  (x y z t a)\n :name \"Diagrams.Solve.Polynomial:cubForm  from diagrams-solve-0.1, I\"\n :alt \n (! :herbie-platform default\n  (if (< a -2.090464557976709e+86)\n   (- (* 0.5 (/ (* y x) a)) (* 4.5 (/ t (/ a z))))\n   (if (< a 2.144030707833976e+99)\n     (/ (- (* x y) (* z (* 9.0 t))) (* a 2.0))\n     (- (* (/ y a) (* x 0.5)) (* (/ t a) (* z 4.5))))))\n\n (/ (- (* x y) (* (* z 9.0) t)) (* a 2.0)))\n\n(FPCore  (x y z t a b c)\n :name \"Diagrams.Solve.Polynomial:cubForm  from diagrams-solve-0.1, J\"\n :alt \n (! :herbie-platform default\n  (if (<\n      (/ (+ (- (* (* x 9.0) y) (* (* (* z 4.0) t) a)) b) (* z c))\n      -1.100156740804105e-171)\n   (/ (+ (- (* (* x 9.0) y) (* (* z 4.0) (* t a))) b) (* z c))\n   (if (< (/ (+ (- (* (* x 9.0) y) (* (* (* z 4.0) t) a)) b) (* z c)) -0.0)\n     (/ (/ (+ (- (* (* x 9.0) y) (* (* (* z 4.0) t) a)) b) z) c)\n     (if (<\n          (/ (+ (- (* (* x 9.0) y) (* (* (* z 4.0) t) a)) b) (* z c))\n          1.1708877911747488e-53)\n       (/ (+ (- (* (* x 9.0) y) (* (* z 4.0) (* t a))) b) (* z c))\n       (if (<\n            (/ (+ (- (* (* x 9.0) y) (* (* (* z 4.0) t) a)) b) (* z c))\n            2.876823679546137e+130)\n         (-\n          (+ (* (* 9.0 (/ y c)) (/ x z)) (/ b (* c z)))\n          (* 4.0 (/ (* a t) c)))\n         (if (<\n              (/ (+ (- (* (* x 9.0) y) (* (* (* z 4.0) t) a)) b) (* z c))\n              1.3838515042456319e+158)\n           (/ (+ (- (* (* x 9.0) y) (* (* z 4.0) (* t a))) b) (* z c))\n           (-\n            (+ (* 9.0 (* (/ y (* c z)) x)) (/ b (* c z)))\n            (* 4.0 (/ (* a t) c)))))))))\n\n (/ (+ (- (* (* x 9.0) y) (* (* (* z 4.0) t) a)) b) (* z c)))\n\n(FPCore  (x y z t a b)\n :name \"Diagrams.Solve.Polynomial:cubForm  from diagrams-solve-0.1, K\"\n :alt \n (! :herbie-platform default\n  (if (< z -1.3793337487235141e+129)\n   (-\n    (* (* 2.0 (sqrt x)) (cos (- (/ 1 y) (/ (/ 0.3333333333333333 z) t))))\n    (/ (/ a 3.0) b))\n   (if (< z 3.516290613555987e+106)\n     (- (* (* (sqrt x) 2.0) (cos (- y (* (/ t 3.0) z)))) (/ (/ a 3.0) b))\n     (-\n      (* (cos (- y (/ (/ 0.3333333333333333 z) t))) (* 2.0 (sqrt x)))\n      (/ (/ a b) 3.0)))))\n\n (- (* (* 2.0 (sqrt x)) (cos (- y (/ (* z t) 3.0)))) (/ a (* b 3.0))))\n\n(FPCore  (x y)\n :name \"Diagrams.Solve.Polynomial:quartForm  from diagrams-solve-0.1, A\"\n (- x (* (/ 3.0 8.0) y)))\n\n(FPCore  (x y z t)\n :name \"Diagrams.Solve.Polynomial:quartForm  from diagrams-solve-0.1, B\"\n :alt \n (! :herbie-platform default\n  (- (+ (/ x 8.0) t) (* (/ z 2.0) y)))\n\n (+ (- (* (/ 1.0 8.0) x) (/ (* y z) 2.0)) t))\n\n(FPCore  (x y z t a b c)\n :name \"Diagrams.Solve.Polynomial:quartForm  from diagrams-solve-0.1, C\"\n (+ (- (+ (* x y) (/ (* z t) 16.0)) (/ (* a b) 4.0)) c))\n\n(FPCore  (x y z)\n :name \"Diagrams.Solve.Polynomial:quartForm  from diagrams-solve-0.1, D\"\n (- (/ (* x y) 2.0) (/ z 8.0)))\n\n(FPCore  (x y)\n :name \"Diagrams.Solve.Polynomial:quartForm  from diagrams-solve-0.1, E\"\n (- x (/ y 4.0)))\n\n(FPCore  (x y)\n :name \"Text.Parsec.Token:makeTokenParser from parsec-3.1.9, A\"\n (/ (+ x y) 10.0))\n\n(FPCore  (x y z)\n :name \"Text.Parsec.Token:makeTokenParser from parsec-3.1.9, B\"\n (* (+ x y) z))\n\n(FPCore  (x y)\n :name \"Numeric.Interval.Internal:bisect from intervals-0.7.1, A\"\n :alt \n (! :herbie-platform default (* 0.5 (+ x y)))\n\n (+ x (/ (- y x) 2.0)))\n\n(FPCore  (x y)\n :name \"Numeric.Interval.Internal:scale from intervals-0.7.1, B\"\n (/ (* x y) 2.0))\n\n(FPCore  (x y z t)\n :name \"Linear.V2:$cdot from linear-1.19.1.3, A\"\n (+ (* x y) (* z t)))\n\n(FPCore  (x y z t)\n :name \"Linear.V3:cross from linear-1.19.1.3\"\n (- (* x y) (* z t)))\n\n(FPCore  (x y z t a b)\n :name \"Linear.V3:$cdot from linear-1.19.1.3, B\"\n (+ (+ (* x y) (* z t)) (* a b)))\n\n(FPCore  (x y z t a b c i)\n :name \"Linear.V4:$cdot from linear-1.19.1.3, C\"\n (+ (+ (+ (* x y) (* z t)) (* a b)) (* c i)))\n\n(FPCore  (x y z)\n :name \"Main:bigenough2 from A\"\n (+ x (* y (+ z x))))\n\n(FPCore (x) :name \"Main:bigenough1 from B\" (+ x (* x x)))\n\n(FPCore  (x)\n :name \"Main:bigenough3 from C\"\n :alt \n (! :herbie-platform default\n  (/ 1.0 (+ (sqrt (+ x 1.0)) (sqrt x))))\n\n (- (sqrt (+ x 1.0)) (sqrt x)))\n\n(FPCore  (x y z)\n :name \"Linear.Quaternion:$c/ from linear-1.19.1.3, A\"\n :alt \n (! :herbie-platform default\n  (+ (* (* 3 z) z) (* y x)))\n\n (+ (+ (+ (* x y) (* z z)) (* z z)) (* z z)))\n\n(FPCore  (x y z)\n :name \"Linear.Quaternion:$c/ from linear-1.19.1.3, B\"\n :alt \n (! :herbie-platform default (* (- x z) y))\n\n (+ (- (- (* x y) (* y z)) (* y y)) (* y y)))\n\n(FPCore  (x y z)\n :name \"Linear.Quaternion:$c/ from linear-1.19.1.3, C\"\n :alt \n (! :herbie-platform default (* (- x z) y))\n\n (- (- (+ (* x y) (* y y)) (* y z)) (* y y)))\n\n(FPCore  (x y z)\n :name \"Linear.Quaternion:$c/ from linear-1.19.1.3, D\"\n :alt \n (! :herbie-platform default (* (- x z) y))\n\n (- (+ (- (* x y) (* y y)) (* y y)) (* y z)))\n\n(FPCore  (x y)\n :name \"Linear.Quaternion:$c/ from linear-1.19.1.3, E\"\n :alt \n (! :herbie-platform default\n  (+ (* x x) (* y (+ y (+ y y)))))\n\n (+ (+ (+ (* x x) (* y y)) (* y y)) (* y y)))\n\n(FPCore  (x y)\n :name \"Graphics.Rasterific.Linear:$cquadrance from Rasterific-0.6.1\"\n (+ (* x x) (* y y)))\n\n(FPCore  (x y z)\n :name \"Linear.Quaternion:$ctanh from linear-1.19.1.3\"\n :alt \n (! :herbie-platform default\n  (if (< z -4.2173720203427147e-29)\n   (/ (* x (/ 1 (/ y (sin y)))) z)\n   (if (< z 4.446702369113811e+64)\n     (/ x (* z (/ y (sin y))))\n     (/ (* x (/ 1 (/ y (sin y)))) z))))\n\n (/ (* x (/ (sin y) y)) z))\n\n(FPCore  (x y)\n :name \"Linear.Quaternion:$ccosh from linear-1.19.1.3\"\n :alt \n (! :herbie-platform default\n  (* (sin x) (/ (sinh y) x)))\n\n (/ (* (sin x) (sinh y)) x))\n\n(FPCore  (x y)\n :name \"Linear.Quaternion:$csinh from linear-1.19.1.3\"\n :alt \n (! :herbie-platform default\n  (/ (* (cosh x) (sin y)) y))\n\n (* (cosh x) (/ (sin y) y)))\n\n(FPCore  (x y z)\n :name \"Linear.Quaternion:$ctan from linear-1.19.1.3\"\n :alt \n (! :herbie-platform default\n  (if (< y -4.618902267687042e-52)\n   (* (/ (/ y z) x) (cosh x))\n   (if (< y 1.038530535935153e-39)\n     (/ (/ (* (cosh x) y) x) z)\n     (* (/ (/ y z) x) (cosh x)))))\n\n (/ (* (cosh x) (/ y x)) z))\n\n(FPCore  (x y)\n :name \"Linear.Quaternion:$ccos from linear-1.19.1.3\"\n (* (sin x) (/ (sinh y) y)))\n\n(FPCore  (x y)\n :name \"Linear.Quaternion:$csin from linear-1.19.1.3\"\n (* (cos x) (/ (sinh y) y)))\n\n(FPCore  (x y)\n :name \"Linear.Quaternion:$clog from linear-1.19.1.3\"\n :alt \n (! :herbie-platform default\n  (if (< x -1.5097698010472593e+153)\n   (- (+ (* 1/2 (/ y x)) x))\n   (if (< x 5.582399551122541e+57) (sqrt (+ (* x x) y)) (+ (* 1/2 (/ y x)) x))))\n\n (sqrt (+ (* x x) y)))\n\n(FPCore  (x y)\n :name \"Linear.Quaternion:$cexp from linear-1.19.1.3\"\n (* x (/ (sin y) y)))\n\n(FPCore  (x y z t a b c i j k y0 y1 y2 y3 y4 y5)\n :name \"Linear.Matrix:det44 from linear-1.19.1.3\"\n :alt \n (! :herbie-platform default\n  (if (< y4 -7.206256231996481e+60)\n   (-\n    (-\n     (* (- (* b a) (* i c)) (- (* y x) (* t z)))\n     (-\n      (* (- (* j x) (* k z)) (- (* y0 b) (* i y1)))\n      (* (- (* j t) (* k y)) (- (* y4 b) (* y5 i)))))\n    (-\n     (/ (- (* y2 t) (* y3 y)) (/ 1 (- (* y4 c) (* y5 a))))\n     (* (- (* y2 k) (* y3 j)) (- (* y4 y1) (* y5 y0)))))\n   (if (< y4 -3.364603505246317e-66)\n     (+\n      (-\n       (- (- (* (* t c) (* i z)) (* (* a t) (* b z))) (* (* y c) (* i x)))\n       (* (- (* b y0) (* i y1)) (- (* j x) (* k z))))\n      (-\n       (* (- (* y0 c) (* a y1)) (- (* x y2) (* z y3)))\n       (-\n        (* (- (* t y2) (* y y3)) (- (* y4 c) (* a y5)))\n        (* (- (* y1 y4) (* y5 y0)) (- (* k y2) (* j y3))))))\n     (if (< y4 -1.2000065055686116e-105)\n       (+\n        (+\n         (-\n          (* (- (* j t) (* k y)) (- (* y4 b) (* y5 i)))\n          (* (* y3 y) (- (* y5 a) (* y4 c))))\n         (+\n          (* (* y5 a) (* t y2))\n          (* (- (* k y2) (* j y3)) (- (* y4 y1) (* y5 y0)))))\n        (-\n         (* (- (* x y2) (* z y3)) (- (* c y0) (* a y1)))\n         (-\n          (* (- (* b y0) (* i y1)) (- (* j x) (* k z)))\n          (* (- (* y x) (* z t)) (- (* b a) (* i c))))))\n       (if (< y4 6.718963124057495e-279)\n         (+\n          (-\n           (-\n            (- (* (* k y) (* y5 i)) (* (* y b) (* y4 k)))\n            (* (* y5 t) (* i j)))\n           (-\n            (* (- (* y2 t) (* y3 y)) (- (* y4 c) (* y5 a)))\n            (* (- (* y2 k) (* y3 j)) (- (* y4 y1) (* y5 y0)))))\n          (-\n           (* (- (* b a) (* i c)) (- (* y x) (* t z)))\n           (-\n            (* (- (* j x) (* k z)) (- (* y0 b) (* i y1)))\n            (* (- (* y2 x) (* y3 z)) (- (* c y0) (* y1 a))))))\n         (if (< y4 4.77962681403792e-222)\n           (+\n            (+\n             (-\n              (* (- (* j t) (* k y)) (- (* y4 b) (* y5 i)))\n              (* (* y3 y) (- (* y5 a) (* y4 c))))\n             (+\n              (* (* y5 a) (* t y2))\n              (* (- (* k y2) (* j y3)) (- (* y4 y1) (* y5 y0)))))\n            (-\n             (* (- (* x y2) (* z y3)) (- (* c y0) (* a y1)))\n             (-\n              (* (- (* b y0) (* i y1)) (- (* j x) (* k z)))\n              (* (- (* y x) (* z t)) (- (* b a) (* i c))))))\n           (if (< y4 2.2852241541266835e-175)\n             (+\n              (-\n               (-\n                (- (* (* k y) (* y5 i)) (* (* y b) (* y4 k)))\n                (* (* y5 t) (* i j)))\n               (-\n                (* (- (* y2 t) (* y3 y)) (- (* y4 c) (* y5 a)))\n                (* (- (* y2 k) (* y3 j)) (- (* y4 y1) (* y5 y0)))))\n              (-\n               (* (- (* b a) (* i c)) (- (* y x) (* t z)))\n               (-\n                (* (- (* j x) (* k z)) (- (* y0 b) (* i y1)))\n                (* (- (* y2 x) (* y3 z)) (- (* c y0) (* y1 a))))))\n             (+\n              (-\n               (+\n                (+\n                 (-\n                  (* (- (* x y) (* z t)) (- (* a b) (* c i)))\n                  (-\n                   (* k (* i (* z y1)))\n                   (+ (* j (* i (* x y1))) (* y0 (* k (* z b))))))\n                 (-\n                  (* z (* y3 (* a y1)))\n                  (+ (* y2 (* x (* a y1))) (* y0 (* z (* c y3))))))\n                (* (- (* t j) (* y k)) (- (* y4 b) (* y5 i))))\n               (* (- (* t y2) (* y y3)) (- (* y4 c) (* y5 a))))\n              (* (- (* k y2) (* j y3)) (- (* y4 y1) (* y5 y0)))))))))))\n (+\n  (-\n   (+\n    (+\n     (-\n      (* (- (* x y) (* z t)) (- (* a b) (* c i)))\n      (* (- (* x j) (* z k)) (- (* y0 b) (* y1 i))))\n     (* (- (* x y2) (* z y3)) (- (* y0 c) (* y1 a))))\n    (* (- (* t j) (* y k)) (- (* y4 b) (* y5 i))))\n   (* (- (* t y2) (* y y3)) (- (* y4 c) (* y5 a))))\n  (* (- (* k y2) (* j y3)) (- (* y4 y1) (* y5 y0)))))\n\n(FPCore  (x y z t a b c i j)\n :name \"Linear.Matrix:det33 from linear-1.19.1.3\"\n :alt \n (! :herbie-platform default\n  (if (< t -8.120978919195912e-33)\n   (-\n    (* x (- (* z y) (* a t)))\n    (- (* b (- (* z c) (* a i))) (* (- (* c t) (* y i)) j)))\n   (if (< t -4.712553818218485e-169)\n     (+\n      (- (* x (- (* y z) (* t a))) (* b (- (* c z) (* i a))))\n      (/ (* j (- (pow (* c t) 2) (pow (* i y) 2))) (+ (* c t) (* i y))))\n     (if (< t -7.633533346031584e-308)\n       (-\n        (* x (- (* z y) (* a t)))\n        (- (* b (- (* z c) (* a i))) (* (- (* c t) (* y i)) j)))\n       (if (< t 1.0535888557455487e-139)\n         (+\n          (- (* x (- (* y z) (* t a))) (* b (- (* c z) (* i a))))\n          (/ (* j (- (pow (* c t) 2) (pow (* i y) 2))) (+ (* c t) (* i y))))\n         (-\n          (* x (- (* z y) (* a t)))\n          (- (* b (- (* z c) (* a i))) (* (- (* c t) (* y i)) j))))))))\n (+\n  (- (* x (- (* y z) (* t a))) (* b (- (* c z) (* i a))))\n  (* j (- (* c t) (* i y)))))\n\n(FPCore  (x y)\n :name \"Linear.Matrix:fromQuaternion from linear-1.19.1.3, A\"\n :alt \n (! :herbie-platform default\n  (* (* x 2.0) (- x y)))\n\n (* 2.0 (- (* x x) (* x y))))\n\n(FPCore  (x y)\n :name \"Linear.Matrix:fromQuaternion from linear-1.19.1.3, B\"\n :alt \n (! :herbie-platform default\n  (* (* x 2.0) (+ x y)))\n\n (* 2.0 (+ (* x x) (* x y))))\n\n(FPCore  (x y z t)\n :name \"Linear.Projection:inverseInfinitePerspective from linear-1.19.1.3\"\n :alt \n (! :herbie-platform default\n  (if (< t -9.231879582886777e-80)\n   (* (* y t) (- x z))\n   (if (< t 2.543067051564877e+83) (* y (* t (- x z))) (* (* y (- x z)) t))))\n\n (* (- (* x y) (* z y)) t))\n\n(FPCore  (x y z t)\n :name \"Linear.Projection:infinitePerspective from linear-1.19.1.3, A\"\n :alt \n (! :herbie-platform default\n  (if (< (/ (* x 2.0) (- (* y z) (* t z))) -2.559141628295061e-13)\n   (* (/ x (* (- y t) z)) 2.0)\n   (if (< (/ (* x 2.0) (- (* y z) (* t z))) 1.045027827330126e-269)\n     (/ (* (/ x z) 2.0) (- y t))\n     (* (/ x (* (- y t) z)) 2.0))))\n\n (/ (* x 2.0) (- (* y z) (* t z))))\n\n(FPCore  (x y)\n :name \"Linear.Projection:inversePerspective from linear-1.19.1.3, B\"\n :alt \n (! :herbie-platform default\n  (- (/ 0.5 y) (/ 0.5 x)))\n\n (/ (- x y) (* (* x 2.0) y)))\n\n(FPCore  (x y)\n :name \"Linear.Projection:inversePerspective from linear-1.19.1.3, C\"\n :alt \n (! :herbie-platform default\n  (+ (/ 0.5 x) (/ 0.5 y)))\n\n (/ (+ x y) (* (* x 2.0) y)))\n\n(FPCore  (x y)\n :name \"Linear.Projection:perspective from linear-1.19.1.3, A\"\n :alt \n (! :herbie-platform default\n  (/ 1 (- (/ x (+ x y)) (/ y (+ x y)))))\n\n (/ (+ x y) (- x y)))\n\n(FPCore  (x y)\n :name \"Linear.Projection:perspective from linear-1.19.1.3, B\"\n :alt \n (! :herbie-platform default\n  (if (< x -1.7210442634149447e+81)\n   (* (/ (* 2.0 x) (- x y)) y)\n   (if (< x 8.364504563556443e+16)\n     (/ (* x 2.0) (/ (- x y) y))\n     (* (/ (* 2.0 x) (- x y)) y))))\n\n (/ (* (* x 2.0) y) (- x y)))\n\n(FPCore  (x y)\n :name \"Physics.ForceLayout:coulombForce from force-layout-0.4.0.2\"\n :alt \n (! :herbie-platform default (/ (/ x y) y))\n\n (/ x (* y y)))\n\n(FPCore  (x y)\n :name \"Codec.Picture.Types:toneMapping from JuicyPixels-3.2.6.1\"\n :alt \n (! :herbie-platform default\n  (* (/ x 1) (/ (+ (/ x y) 1.0) (+ x 1.0))))\n\n (/ (* x (+ (/ x y) 1.0)) (+ x 1.0)))\n\n(FPCore  (x y z t a b)\n :name \"Codec.Picture.Jpg.FastDct:referenceDct from JuicyPixels-3.2.6.1\"\n :alt \n (! :herbie-platform default\n  (* x (cos (* (/ b 16.0) (/ t (+ (- 1.0 (* a 2.0)) (pow (* a 2.0) 2)))))))\n\n (*\n  (* x (cos (/ (* (* (+ (* y 2.0) 1.0) z) t) 16.0)))\n  (cos (/ (* (* (+ (* a 2.0) 1.0) b) t) 16.0))))\n\n(FPCore  (x)\n :name \"Main:i from \"\n (+ (+ (+ (+ x x) x) x) x))\n\n(FPCore  (x y z t)\n :name \"Main:z from \"\n :alt \n (! :herbie-platform default\n  (+\n   (+\n    (+\n     (/ 1.0 (+ (sqrt (+ x 1.0)) (sqrt x)))\n     (/ 1.0 (+ (sqrt (+ y 1.0)) (sqrt y))))\n    (/ 1.0 (+ (sqrt (+ z 1.0)) (sqrt z))))\n   (- (sqrt (+ t 1.0)) (sqrt t))))\n\n (+\n  (+\n   (+ (- (sqrt (+ x 1.0)) (sqrt x)) (- (sqrt (+ y 1.0)) (sqrt y)))\n   (- (sqrt (+ z 1.0)) (sqrt z)))\n  (- (sqrt (+ t 1.0)) (sqrt t))))\n\n(FPCore  (x y z t a b c i)\n :name \"Diagrams.ThreeD.Shapes:frustum from diagrams-lib-1.3.0.3, A\"\n :alt \n (! :herbie-platform default\n  (* 2.0 (- (+ (* x y) (* z t)) (* (+ a (* b c)) (* c i)))))\n\n (* 2.0 (- (+ (* x y) (* z t)) (* (* (+ a (* b c)) c) i))))\n\n(FPCore  (x y z)\n :name \"Diagrams.ThreeD.Shapes:frustum from diagrams-lib-1.3.0.3, B\"\n (+ x (* (- y x) z)))\n\n(FPCore  (x y z)\n :name \"Diagrams.ThreeD.Transform:aboutY from diagrams-lib-1.3.0.3\"\n (+ (* x (cos y)) (* z (sin y))))\n\n(FPCore  (x y z)\n :name \"Diagrams.ThreeD.Transform:aboutX from diagrams-lib-1.3.0.3, A\"\n (- (* x (cos y)) (* z (sin y))))\n\n(FPCore  (x y z)\n :name \"Diagrams.ThreeD.Transform:aboutX from diagrams-lib-1.3.0.3, B\"\n (+ (* x (sin y)) (* z (cos y))))\n\n(FPCore  (x y z)\n :name \"Diagrams.Color.HSV:lerp  from diagrams-contrib-1.3.0.5\"\n :alt \n (! :herbie-platform default\n  (- y (* x (- y z))))\n (+ (* (- 1.0 x) y) (* x z)))\n\n(FPCore  (x y z)\n :name \"Diagrams.TwoD.Segment.Bernstein:evaluateBernstein from diagrams-lib-1.3.0.3\"\n :alt \n (! :herbie-platform default\n  (if (< x -2.71483106713436e-162)\n   (- (* (+ 1 y) (/ x z)) x)\n   (if (< x 3.874108816439546e-197)\n     (* (* x (+ (- y z) 1.0)) (/ 1 z))\n     (- (* (+ 1 y) (/ x z)) x))))\n\n (/ (* x (+ (- y z) 1.0)) z))\n\n(FPCore  (x y)\n :name \"Diagrams.Segment:$catParam from diagrams-lib-1.3.0.3, A\"\n :alt \n (! :herbie-platform default (* (* x 3.0) (* x y)))\n\n (* (* (* x 3.0) x) y))\n\n(FPCore  (x y)\n :name \"Diagrams.Segment:$catParam from diagrams-lib-1.3.0.3, B\"\n :alt \n (! :herbie-platform default (* (* x (* 3.0 y)) y))\n\n (* (* (* x 3.0) y) y))\n\n(FPCore  (x)\n :name \"Diagrams.Segment:$catParam from diagrams-lib-1.3.0.3, C\"\n (* (* x x) x))\n\n(FPCore  (x)\n :name \"Diagrams.Tangent:$catParam from diagrams-lib-1.3.0.3, D\"\n :alt \n (! :herbie-platform default\n  (+ 3.0 (- (* (* 9.0 x) x) (* 12.0 x))))\n\n (* 3.0 (+ (- (* (* x 3.0) x) (* x 4.0)) 1.0)))\n\n(FPCore  (x)\n :name \"Diagrams.Tangent:$catParam from diagrams-lib-1.3.0.3, E\"\n :alt \n (! :herbie-platform default\n  (- (* 6.0 x) (* 9.0 (* x x))))\n\n (* (* 3.0 (- 2.0 (* x 3.0))) x))\n\n(FPCore  (x)\n :name \"Diagrams.Tangent:$catParam from diagrams-lib-1.3.0.3, F\"\n (* (* x 3.0) x))\n\n(FPCore  (x y z t)\n :name \"Diagrams.Trail:splitAtParam  from diagrams-lib-1.3.0.3, A\"\n :alt \n (! :herbie-platform default\n  (/ (+ x (- (/ y (- t (/ x z))) (/ x (- (* t z) x)))) (+ x 1.0)))\n\n (/ (+ x (/ (- (* y z) x) (- (* t z) x))) (+ x 1.0)))\n\n(FPCore  (x y)\n :name \"Diagrams.Trail:splitAtParam  from diagrams-lib-1.3.0.3, B\"\n :alt \n (! :herbie-platform default\n  (if (< y -3693.8482788297247)\n   (- (/ x (* y y)) (- (/ x y) x))\n   (if (< y 6799310503.41891)\n     (/ (* x y) (+ y 1.0))\n     (- (/ x (* y y)) (- (/ x y) x)))))\n\n (/ (* x y) (+ y 1.0)))\n\n(FPCore  (x y)\n :name \"Diagrams.Trail:splitAtParam  from diagrams-lib-1.3.0.3, C\"\n (/ (- x y) (- 1.0 y)))\n\n(FPCore  (x y)\n :name \"Diagrams.Trail:splitAtParam  from diagrams-lib-1.3.0.3, D\"\n :alt \n (! :herbie-platform default\n  (if (< y -3693.8482788297247)\n   (- (/ 1.0 y) (- (/ x y) x))\n   (if (< y 6799310503.41891)\n     (- 1.0 (/ (* (- 1.0 x) y) (+ y 1.0)))\n     (- (/ 1.0 y) (- (/ x y) x)))))\n\n (- 1.0 (/ (* (- 1.0 x) y) (+ y 1.0))))\n\n(FPCore  (x y)\n :name \"Diagrams.TwoD.Arc:bezierFromSweepQ1 from diagrams-lib-1.3.0.3\"\n :alt \n (! :herbie-platform default\n  (* (/ (- 1.0 x) y) (/ (- 3.0 x) 3.0)))\n\n (/ (* (- 1.0 x) (- 3.0 x)) (* y 3.0)))\n\n(FPCore  (x y)\n :name \"Diagrams.TwoD.Arc:arcBetween from diagrams-lib-1.3.0.3\"\n :alt \n (! :herbie-platform default\n  (if (<\n      (/ (- (* x x) (* (* y 4.0) y)) (+ (* x x) (* (* y 4.0) y)))\n      0.9743233849626781)\n   (-\n    (/ (* x x) (+ (* x x) (* (* y y) 4.0)))\n    (/ (* (* y y) 4.0) (+ (* x x) (* (* y y) 4.0))))\n   (-\n    (pow (/ x (sqrt (+ (* x x) (* (* y y) 4.0)))) 2)\n    (/ (* (* y y) 4.0) (+ (* x x) (* (* y y) 4.0))))))\n\n (/ (- (* x x) (* (* y 4.0) y)) (+ (* x x) (* (* y 4.0) y))))\n\n(FPCore  (x)\n :name \"Diagrams.TwoD.Ellipse:ellipse from diagrams-lib-1.3.0.3\"\n (sqrt (- 1.0 (* x x))))\n\n(FPCore  (x y z t a)\n :name \"Graphics.Rendering.Chart.Axis.Types:invLinMap from Chart-1.5.3\"\n :alt \n (! :herbie-platform default\n  (if (< z -1.2536131056095036e+188)\n   (- t (* (/ y z) (- t x)))\n   (if (< z 4.446702369113811e+64)\n     (+ x (/ (- y z) (/ (- a z) (- t x))))\n     (- t (* (/ y z) (- t x))))))\n (+ x (/ (* (- y z) (- t x)) (- a z))))\n\n(FPCore  (x y z)\n :name \"Diagrams.TwoD.Segment:bezierClip from diagrams-lib-1.3.0.3\"\n :alt \n (! :herbie-platform default\n  (- z (* (- z x) y)))\n\n (+ (* x y) (* z (- 1.0 y))))\n\n(FPCore  (x y)\n :name \"Data.Octree.Internal:octantDistance  from Octree-0.5.4.2\"\n :alt \n (! :herbie-platform default\n  (if (< x -1.1236950826599826e+145)\n   (- x)\n   (if (< x 1.116557621183362e+93) (sqrt (+ (* x x) (* y y))) x)))\n\n (sqrt (+ (* x x) (* y y))))\n\n(FPCore  (x y)\n :name \"Graphics.Rasterific.Shading:$sradialGradientWithFocusShader from Rasterific-0.6.1\"\n (- x (* y y)))\n\n(FPCore  (x y)\n :name \"Diagrams.TwoD.Path.Metafont.Internal:hobbyF from diagrams-contrib-1.3.0.5\"\n (/\n  (+\n   2.0\n   (*\n    (*\n     (* (sqrt 2.0) (- (sin x) (/ (sin y) 16.0)))\n     (- (sin y) (/ (sin x) 16.0)))\n    (- (cos x) (cos y))))\n  (*\n   3.0\n   (+\n    (+ 1.0 (* (/ (- (sqrt 5.0) 1.0) 2.0) (cos x)))\n    (* (/ (- 3.0 (sqrt 5.0)) 2.0) (cos y))))))\n\n(FPCore  (x y)\n :name \"Diagrams.TwoD.Layout.CirclePacking:approxRadius from diagrams-contrib-1.3.0.5\"\n :alt \n (! :herbie-platform default\n  (if (< y -1.2303690911306994e+114)\n   1.0\n   (if (< y -9.102852406811914e-222)\n     (/\n      (sin (/ x (* y 2.0)))\n      (* (sin (/ x (* y 2.0))) (log (exp (cos (/ x (* y 2.0)))))))\n     1.0)))\n\n (/ (tan (/ x (* y 2.0))) (sin (/ x (* y 2.0)))))\n\n(FPCore  (x y z)\n :name \"Diagrams.TwoD.Apollonian:descartes from diagrams-contrib-1.3.0.5\"\n :alt \n (! :herbie-platform default\n  (if (< z 7.636950090573675e+176)\n   (* 2.0 (sqrt (+ (* (+ x y) z) (* x y))))\n   (*\n    (*\n     (+\n      (* 1/4 (* (* (pow y -3/4) (* (pow z -3/4) x)) (+ y z)))\n      (* (pow z 1/4) (pow y 1/4)))\n     (+\n      (* 1/4 (* (* (pow y -3/4) (* (pow z -3/4) x)) (+ y z)))\n      (* (pow z 1/4) (pow y 1/4))))\n    2.0)))\n\n (* 2.0 (sqrt (+ (+ (* x y) (* x z)) (* y z)))))\n\n(FPCore  (x y z)\n :name \"Diagrams.TwoD.Apollonian:initialConfig from diagrams-contrib-1.3.0.5, A\"\n :alt \n (! :herbie-platform default\n  (- (* y 0.5) (* (* (/ 0.5 y) (+ z x)) (- z x))))\n\n (/ (- (+ (* x x) (* y y)) (* z z)) (* y 2.0)))\n\n(FPCore  (x y z)\n :name \"Diagrams.TwoD.Apollonian:initialConfig from diagrams-contrib-1.3.0.5, B\"\n :alt \n (! :herbie-platform default\n  (if (< y 2.5816096488251695e-278)\n   (- (* x y))\n   (* x (* (sqrt (+ y z)) (sqrt (- y z))))))\n\n (* x (sqrt (- (* y y) (* z z)))))\n\n(FPCore  (x y z)\n :name \"Diagrams.Backend.Rasterific:rasterificRadialGradient from diagrams-rasterific-1.3.1.3\"\n :alt \n (! :herbie-platform default\n  (- (+ y (/ x z)) (/ y (/ z x))))\n\n (/ (+ x (* y (- z x))) z))\n\n(FPCore  (x y z t)\n :name \"Data.HashTable.ST.Basic:computeOverhead from hashtables-1.2.0.2\"\n :alt \n (! :herbie-platform default\n  (- (/ (+ (/ 2.0 z) 2.0) t) (- 2.0 (/ x y))))\n\n (+ (/ x y) (/ (+ 2.0 (* (* z 2.0) (- 1.0 t))) (* t z))))\n\n(FPCore  (x y z t)\n :name \"Language.Haskell.HsColour.ColourHighlight:unbase from hscolour-1.23\"\n (+ (* (+ (* x y) z) y) t))\n\n(FPCore  (x)\n :name \"System.Random.MWC.Distributions:blocks from mwc-random-0.13.3.2\"\n (* (* x 0.5) x))\n\n(FPCore  (x y)\n :name \"System.Random.MWC.Distributions:standard from mwc-random-0.13.3.2\"\n (* 0.5 (- (* x x) y)))\n\n(FPCore  (x y z)\n :name \"SynthBasics:oscSampleBasedAux from YampaSynth-0.2\"\n (+ x (* y (- z x))))\n\n(FPCore  (x y z t)\n :name \"System.Random.MWC.Distributions:truncatedExp from mwc-random-0.13.3.2\"\n :alt \n (! :herbie-platform default\n  (if (< z -2.8874623088207947e+119)\n   (-\n    (- x (/ (/ (- 0.5) (* y t)) (* z z)))\n    (* (/ (- 0.5) (* y t)) (/ (/ 2.0 z) (* z z))))\n   (- x (/ (log (+ 1.0 (* z y))) t))))\n\n (- x (/ (log (+ (- 1.0 y) (* y (exp z)))) t)))\n\n(FPCore  (x y z)\n :name \"System.Random.MWC.Distributions:gamma from mwc-random-0.13.3.2\"\n :alt \n (! :herbie-platform default\n  (- (+ y (* 0.5 x)) (* y (- z (log z)))))\n (+ (* x 0.5) (* y (+ (- 1.0 z) (log z)))))\n\n(FPCore  (x y)\n :name \"AI.Clustering.Hierarchical.Internal:average from clustering-0.2.1, A\"\n (/ x (+ x y)))\n\n(FPCore  (x)\n :name \"Numeric.Integration.TanhSinh:nonNegative from integration-0.2.1\"\n (/ x (- 1.0 x)))\n\n(FPCore  (x y z)\n :name \"Graphics.Rasterific.QuadraticFormula:discriminant from Rasterific-0.6.1\"\n (- (* x x) (* (* y 4.0) z)))\n\n(FPCore  (x y z t a b)\n :name \"Graphics.Rasterific.CubicBezier:cachedBezierAt from Rasterific-0.6.1\"\n :alt \n (! :herbie-platform default\n  (if (< z -1.1820553527347888e+19)\n   (+ (* z (+ (* b a) y)) (+ x (* t a)))\n   (if (< z 4.7589743188364287e-122)\n     (+ (* (+ (* b z) t) a) (+ (* z y) x))\n     (+ (* z (+ (* b a) y)) (+ x (* t a))))))\n\n (+ (+ (+ x (* y z)) (* t a)) (* (* a z) b)))\n\n(FPCore  (x)\n :name \"Graphics.Rasterific.CubicBezier:isSufficientlyFlat from Rasterific-0.6.1\"\n (* (* x 16.0) x))\n\n(FPCore  (x y z)\n :name \"Graphics.Rasterific.Shading:$sgradientColorAt from Rasterific-0.6.1\"\n :alt \n (! :herbie-platform default\n  (- (/ x (- z y)) (/ y (- z y))))\n\n (/ (- x y) (- z y)))\n\n(FPCore  (x)\n :name \"Graphics.Rasterific.Shading:$sradialGradientWithFocusShader from Rasterific-0.6.1, A\"\n (+ (* x x) 1.0))\n\n(FPCore  (x y z t)\n :name \"Graphics.Rasterific.Shading:$sradialGradientWithFocusShader from Rasterific-0.6.1, B\"\n :alt \n (! :herbie-platform default\n  (- (* x x) (* 4.0 (* y (- (* z z) t)))))\n\n (- (* x x) (* (* y 4.0) (- (* z z) t))))\n\n(FPCore  (x y)\n :name \"Data.Number.Erf:$dmerfcx from erf-2.0.0.0\"\n :alt \n (! :herbie-platform default\n  (* x (pow (exp y) y)))\n\n (* x (exp (* y y))))\n\n(FPCore  (x y z t)\n :name \"Data.Number.Erf:$cinvnormcdf from erf-2.0.0.0, A\"\n :alt \n (! :herbie-platform default\n  (* (* (- (* x 0.5) y) (sqrt (* z 2.0))) (pow (exp 1) (/ (* t t) 2.0))))\n\n (* (* (- (* x 0.5) y) (sqrt (* z 2.0))) (exp (/ (* t t) 2.0))))\n\n(FPCore  (x y)\n :name \"Data.Number.Erf:$cinvnormcdf from erf-2.0.0.0, B\"\n (- x (/ y (+ 1.0 (/ (* x y) 2.0)))))\n\n(FPCore  (x y z t)\n :name \"Numeric.AD.Rank1.Halley:findZero from ad-4.2.4\"\n :alt \n (! :herbie-platform default\n  (- x (/ 1 (- (/ z y) (/ (/ t 2.0) z)))))\n\n (- x (/ (* (* y 2.0) z) (- (* (* z 2.0) z) (* y t)))))\n\n(FPCore  (x y z)\n :name \"Crypto.Random.Test:calculate from crypto-random-0.0.9\"\n :alt \n (! :herbie-platform default\n  (+ x (* y (/ y z))))\n\n (+ x (/ (* y y) z)))\n\n(FPCore  (x)\n :name \"Numeric.Log:$cexpm1 from log-domain-0.10.2.1, A\"\n :alt \n (! :herbie-platform default\n  (* (* 2.0 x) x))\n\n (* (* x 2.0) x))\n\n(FPCore  (x y)\n :name \"Numeric.Log:$cexpm1 from log-domain-0.10.2.1, B\"\n (+ (+ (* x y) x) y))\n\n(FPCore  (x y)\n :name \"Numeric.Log:$clog1p from log-domain-0.10.2.1, A\"\n :alt \n (! :herbie-platform default\n  (+ (* y y) (+ (* 2.0 x) (* x x))))\n\n (+ (+ (* x 2.0) (* x x)) (* y y)))\n\n(FPCore  (x)\n :name \"Numeric.Log:$clog1p from log-domain-0.10.2.1, B\"\n (/ x (+ 1.0 (sqrt (+ x 1.0)))))\n\n(FPCore  (x)\n :name \"Data.Approximate.Numerics:blog from approximate-0.2.2.1\"\n :alt \n (! :herbie-platform default\n  (/ 6.0 (/ (+ (+ x 1.0) (* 4.0 (sqrt x))) (- x 1.0))))\n\n (/ (* 6.0 (- x 1.0)) (+ (+ x 1.0) (* 4.0 (sqrt x)))))\n\n(FPCore  (x)\n :name \"Graphics.Rasterific.Svg.PathConverter:segmentToBezier from rasterific-svg-0.2.3.1, A\"\n :alt \n (! :herbie-platform default\n  (/ (/ (* 8.0 (sin (* x 0.5))) 3.0) (/ (sin x) (sin (* x 0.5)))))\n\n (/ (* (* (/ 8.0 3.0) (sin (* x 0.5))) (sin (* x 0.5))) (sin x)))\n\n(FPCore  (x y z)\n :name \"Graphics.Rasterific.Svg.PathConverter:segmentToBezier from rasterific-svg-0.2.3.1, B\"\n (- (+ x (cos y)) (* z (sin y))))\n\n(FPCore  (x y z)\n :name \"Graphics.Rasterific.Svg.PathConverter:segmentToBezier from rasterific-svg-0.2.3.1, C\"\n (+ (+ x (sin y)) (* z (cos y))))\n\n(FPCore  (x y z t)\n :name \"Graphics.Rasterific.Svg.PathConverter:arcToSegments from rasterific-svg-0.2.3.1\"\n :alt \n (! :herbie-platform default\n  (+ (pow (/ x y) 2) (pow (/ z t) 2)))\n\n (+ (/ (* x x) (* y y)) (/ (* z z) (* t t))))\n\n(FPCore  (x)\n :name \"Development.Shake.Profile:generateTrace from shake-0.15.5\"\n :alt \n (! :herbie-platform default 0)\n\n (* 1000000.0 (- x x)))\n\n(FPCore  (x y z t a b)\n :name \"Development.Shake.Progress:decay from shake-0.15.5\"\n :alt \n (! :herbie-platform default\n  (- (/ (+ (* z t) (* y x)) (+ y (* z (- b y)))) (/ a (+ (- b y) (/ y z)))))\n\n (/ (+ (* x y) (* z (- t a))) (+ y (* z (- b y)))))\n\n(FPCore  (x y)\n :name \"Development.Shake.Progress:message from shake-0.15.5\"\n :alt \n (! :herbie-platform default\n  (* (/ x 1) (/ 100.0 (+ x y))))\n\n (/ (* x 100.0) (+ x y)))\n\n(FPCore  (x y z)\n :name \"Diagrams.Backend.Rasterific:$crender from diagrams-rasterific-1.3.1.3\"\n (+ (* x y) (* (- 1.0 x) z)))\n\n(FPCore  (x y z t)\n :name \"Numeric.Histogram:binBounds from Chart-1.5.3\"\n :alt \n (! :herbie-platform default\n  (if (< x -9.025511195533005e-135)\n   (- x (* (/ z t) (- x y)))\n   (if (< x 4.275032163700715e-250)\n     (+ x (* (/ (- y x) t) z))\n     (+ x (/ (- y x) (/ t z))))))\n\n (+ x (/ (* (- y x) z) t)))\n\n(FPCore  (x y z)\n :name \"Graphics.Rendering.Chart.Drawing:drawTextsR from Chart-1.5.3\"\n (+ (* x y) (* (- x 1.0) z)))\n\n(FPCore  (x y)\n :name \"Graphics.Rendering.Chart.Axis.Types:hBufferRect from Chart-1.5.3\"\n :alt \n (! :herbie-platform default\n  (- (* 1.5 x) (* 0.5 y)))\n\n (+ x (/ (- x y) 2.0)))\n\n(FPCore  (x y z t a)\n :name \"Graphics.Rendering.Chart.Axis.Types:linMap from Chart-1.5.3\"\n :alt \n (! :herbie-platform default\n  (if (< a -1.6153062845442575e-142)\n   (+ x (* (/ (- y x) 1) (/ (- z t) (- a t))))\n   (if (< a 3.774403170083174e-182)\n     (- y (* (/ z t) (- y x)))\n     (+ x (* (/ (- y x) 1) (/ (- z t) (- a t)))))))\n\n (+ x (/ (* (- y x) (- z t)) (- a t))))\n\n(FPCore  (x y)\n :name \"Graphics.Rendering.Chart.Plot.Vectors:renderPlotVectors from Chart-1.5.3\"\n :alt \n (! :herbie-platform default\n  (- (* y x) (- y 1.0)))\n\n (+ x (* (- 1.0 x) (- 1.0 y))))\n\n(FPCore  (x y)\n :name \"Graphics.Rendering.Chart.Plot.AreaSpots:renderSpotLegend from Chart-1.5.3\"\n (+ x (/ (fabs (- y x)) 2.0)))\n\n(FPCore  (x y z t)\n :name \"Graphics.Rendering.Chart.Plot.AreaSpots:renderAreaSpots4D from Chart-1.5.3\"\n :alt \n (! :herbie-platform default\n  (/ x (/ (- t z) (- y z))))\n\n (/ (* x (- y z)) (- t z)))\n\n(FPCore  (x y)\n :name \"Graphics.Rendering.Chart.Plot.Pie:renderPie from Chart-1.5.3\"\n :alt \n (! :herbie-platform default (- y 0))\n \n (- (+ x y) x))\n\n(FPCore  (x y z t a)\n :name \"Graphics.Rendering.Chart.SparkLine:renderSparkLine from Chart-1.5.3\"\n :alt \n (! :herbie-platform default\n  (- x (* (/ (- y z) (+ (- t z) 1.0)) a)))\n\n (- x (/ (- y z) (/ (+ (- t z) 1.0) a))))\n\n(FPCore  (x y z)\n :name \"Graphics.Rendering.Chart.Backend.Diagrams:calcFontMetrics from Chart-diagrams-1.5.1, A\"\n :alt \n (! :herbie-platform default\n  (if (< y -3.7429310762689856e+171)\n   (* (/ (+ y x) (- y)) z)\n   (if (< y 3.5534662456086734e+168)\n     (/ (+ x y) (- 1.0 (/ y z)))\n     (* (/ (+ y x) (- y)) z))))\n\n (/ (+ x y) (- 1.0 (/ y z))))\n\n(FPCore  (x y z t)\n :name \"Graphics.Rendering.Chart.Backend.Diagrams:calcFontMetrics from Chart-diagrams-1.5.1, B\"\n :alt \n (! :herbie-platform default\n  (if (< (/ (* (/ y z) t) t) -1.20672205123045e+245)\n   (/ y (/ z x))\n   (if (< (/ (* (/ y z) t) t) -5.907522236933906e-275)\n     (* x (/ y z))\n     (if (< (/ (* (/ y z) t) t) 5.658954423153415e-65)\n       (/ y (/ z x))\n       (if (< (/ (* (/ y z) t) t) 2.0087180502407133e+217)\n         (* x (/ y z))\n         (/ (* y x) z))))))\n\n (* x (/ (* (/ y z) t) t)))\n\n(FPCore  (x y)\n :name \"AI.Clustering.Hierarchical.Internal:average from clustering-0.2.1, B\"\n (/ x (+ y x)))\n\n(FPCore  (x y z t a b)\n :name \"AI.Clustering.Hierarchical.Internal:ward from clustering-0.2.1\"\n :alt \n (! :herbie-platform default\n  (if (<\n      (/ (- (+ (* (+ x y) z) (* (+ t y) a)) (* y b)) (+ (+ x t) y))\n      -3.5813117084150564e+153)\n   (- (+ z a) b)\n   (if (<\n        (/ (- (+ (* (+ x y) z) (* (+ t y) a)) (* y b)) (+ (+ x t) y))\n        1.2285964308315609e+82)\n     (/ 1 (/ (+ (+ x t) y) (- (+ (* (+ x y) z) (* (+ t y) a)) (* y b))))\n     (- (+ z a) b))))\n\n (/ (- (+ (* (+ x y) z) (* (+ t y) a)) (* y b)) (+ (+ x t) y)))\n\n(FPCore  (x y z)\n :name \"Numeric.SpecFunctions:invErfc from math-functions-0.1.5.2, A\"\n :alt \n (! :herbie-platform default\n  (+ x (/ 1 (- (* (/ 1.1283791670955126 y) (exp z)) x))))\n\n (+ x (/ y (- (* 1.1283791670955126 (exp z)) (* x y)))))\n\n(FPCore  (x)\n :name \"Numeric.SpecFunctions:invErfc from math-functions-0.1.5.2, B\"\n (*\n  0.70711\n  (- (/ (+ 2.30753 (* x 0.27061)) (+ 1.0 (* x (+ 0.99229 (* x 0.04481))))) x)))\n\n(FPCore  (x y)\n :name \"Numeric.SpecFunctions:logGamma from math-functions-0.1.5.2, A\"\n (+ (- (* x (- y 1.0)) (* y 0.5)) 0.918938533204673))\n\n(FPCore  (x y z)\n :name \"Numeric.SpecFunctions:logGamma from math-functions-0.1.5.2, B\"\n :alt \n (! :herbie-platform default\n  (if (< z -8120153.652456675)\n   (-\n    (* (+ (/ 0.07512208616047561 z) 0.0692910599291889) y)\n    (- (/ (* 0.40462203869992125 y) (* z z)) x))\n   (if (< z 6.576118972787377e+20)\n     (+\n      x\n      (*\n       (*\n        y\n        (+\n         (* (+ (* z 0.0692910599291889) 0.4917317610505968) z)\n         0.279195317918525))\n       (/ 1 (+ (* (+ z 6.012459259764103) z) 3.350343815022304))))\n     (-\n      (* (+ (/ 0.07512208616047561 z) 0.0692910599291889) y)\n      (- (/ (* 0.40462203869992125 y) (* z z)) x)))))\n\n (+\n  x\n  (/\n   (*\n    y\n    (+\n     (* (+ (* z 0.0692910599291889) 0.4917317610505968) z)\n     0.279195317918525))\n   (+ (* (+ z 6.012459259764103) z) 3.350343815022304))))\n\n(FPCore  (x y z)\n :name \"Numeric.SpecFunctions:logGamma from math-functions-0.1.5.2, C\"\n :alt \n (! :herbie-platform default\n  (if (< x -3.326128725870005e+62)\n   (- (+ (/ y (* x x)) (* 4.16438922228 x)) 110.1139242984811)\n   (if (< x 9.429991714554673e+55)\n     (*\n      (/ (- x 2.0) 1)\n      (/\n       (+\n        (*\n         (+\n          (* (+ (* (+ (* x 4.16438922228) 78.6994924154) x) 137.519416416) x)\n          y)\n         x)\n        z)\n       (+\n        (*\n         (+\n          (+ (* 263.505074721 x) (+ (* 43.3400022514 (* x x)) (* x (* x x))))\n          313.399215894)\n         x)\n        47.066876606)))\n     (- (+ (/ y (* x x)) (* 4.16438922228 x)) 110.1139242984811))))\n\n (/\n  (*\n   (- x 2.0)\n   (+\n    (*\n     (+ (* (+ (* (+ (* x 4.16438922228) 78.6994924154) x) 137.519416416) x) y)\n     x)\n    z))\n  (+\n   (* (+ (* (+ (* (+ x 43.3400022514) x) 263.505074721) x) 313.399215894) x)\n   47.066876606)))\n\n(FPCore  (x y z t a b)\n :name \"Numeric.SpecFunctions:logGamma from math-functions-0.1.5.2, D\"\n :alt \n (! :herbie-platform default\n  (if (< z -6.499344996252632e+53)\n   (+\n    x\n    (* (+ (- 3.13060547623 (/ 36.527041698806414 z)) (/ t (* z z))) (/ y 1)))\n   (if (< z 7.066965436914287e+59)\n     (+\n      x\n      (/\n       y\n       (/\n        (+\n         (*\n          (+ (* (+ (* (+ z 15.234687407) z) 31.4690115749) z) 11.9400905721)\n          z)\n         0.607771387771)\n        (+\n         (* (+ (* (+ (* (+ (* z 3.13060547623) 11.1667541262) z) t) z) a) z)\n         b))))\n     (+\n      x\n      (*\n       (+ (- 3.13060547623 (/ 36.527041698806414 z)) (/ t (* z z)))\n       (/ y 1))))))\n\n (+\n  x\n  (/\n   (*\n    y\n    (+ (* (+ (* (+ (* (+ (* z 3.13060547623) 11.1667541262) z) t) z) a) z) b))\n   (+\n    (* (+ (* (+ (* (+ z 15.234687407) z) 31.4690115749) z) 11.9400905721) z)\n    0.607771387771))))\n\n(FPCore  (x)\n :name \"Numeric.SpecFunctions:$slogFactorial from math-functions-0.1.5.2, A\"\n :alt \n (! :herbie-platform default (/ (/ 1.0 x) x))\n\n (/ 1.0 (* x x)))\n\n(FPCore  (x y z)\n :name \"Numeric.SpecFunctions:$slogFactorial from math-functions-0.1.5.2, B\"\n :alt \n (! :herbie-platform default\n  (+\n   (+ (+ (* (- x 0.5) (log x)) (- 0.91893853320467 x)) (/ 0.083333333333333 x))\n   (* (/ z x) (- (* z (+ y 0.0007936500793651)) 0.0027777777777778))))\n\n (+\n  (+ (- (* (- x 0.5) (log x)) x) 0.91893853320467)\n  (/\n   (+\n    (* (- (* (+ y 0.0007936500793651) z) 0.0027777777777778) z)\n    0.083333333333333)\n   x)))\n\n(FPCore  (x y z t a)\n :name \"Numeric.SpecFunctions:logGammaL from math-functions-0.1.5.2\"\n :alt \n (! :herbie-platform default\n  (+ (log (+ x y)) (+ (- (log z) t) (* (- a 0.5) (log t)))))\n (+ (- (+ (log (+ x y)) (log z)) t) (* (- a 0.5) (log t))))\n\n(FPCore  (x)\n :name \"Numeric.SpecFunctions:logGammaCorrection from math-functions-0.1.5.2\"\n (- (* (* x x) 2.0) 1.0))\n\n(FPCore  (x y)\n :name \"Numeric.SpecFunctions:log1p from math-functions-0.1.5.2, A\"\n (* x (- 1.0 (* x y))))\n\n;; TODO: Trello Benchmark Sources - Numeric.SpecFunctions:log1p from math-functions-0.1.5.2, B\n;; (FPCore  (x)\n;;  :name \"Numeric.SpecFunctions:log1p from math-functions-0.1.5.2, B\"\n;;  (* x (- 1.0 (* x 0.5))))\n\n(FPCore  (x y z t a b)\n :name \"Numeric.SpecFunctions:logBeta from math-functions-0.1.5.2, A\"\n :alt \n (! :herbie-platform default\n  (+ (+ (+ x y) (/ (* (- 1 (pow (log t) 2)) z) (+ 1 (log t)))) (* (- a 0.5) b)))\n (+ (- (+ (+ x y) z) (* z (log t))) (* (- a 0.5) b)))\n\n(FPCore  (x y z t a b c i)\n :name \"Numeric.SpecFunctions:logBeta from math-functions-0.1.5.2, B\"\n (+ (+ (+ (+ (+ (* x (log y)) z) t) a) (* (- b 0.5) (log c))) (* y i)))\n\n(FPCore  (x y z)\n :name \"Numeric.SpecFunctions:choose from math-functions-0.1.5.2\"\n :alt \n (! :herbie-platform default (/ x (/ z (+ y z))))\n\n (/ (* x (+ y z)) z))\n\n(FPCore  (x y z)\n :name \"Numeric.SpecFunctions:stirlingError from math-functions-0.1.5.2\"\n :alt \n (! :herbie-platform default\n  (- (- (+ y x) z) (* (+ y 0.5) (log y))))\n\n (- (+ (- x (* (+ y 0.5) (log y))) y) z))\n\n(FPCore  (x y z t)\n :name \"Numeric.SpecFunctions:incompleteGamma from math-functions-0.1.5.2, A\"\n (+ (- (- (* x (log y)) y) z) (log t)))\n\n(FPCore  (x y)\n :name \"Numeric.SpecFunctions:incompleteGamma from math-functions-0.1.5.2, B\"\n :alt \n (! :herbie-platform default\n  (* 3.0 (+ (* y (sqrt x)) (* (- (/ 1.0 (* x 9.0)) 1.0) (sqrt x)))))\n\n (* (* 3.0 (sqrt x)) (- (+ y (/ 1.0 (* x 9.0))) 1.0)))\n\n(FPCore  (x)\n :name \"Numeric.SpecFunctions:invIncompleteGamma from math-functions-0.1.5.2, A\"\n (- 1.0 (* x (+ 0.253 (* x 0.12)))))\n\n(FPCore  (x y)\n :name \"Numeric.SpecFunctions:invIncompleteGamma from math-functions-0.1.5.2, B\"\n :alt \n (! :herbie-platform default\n  (if (< y -81284752.61947241)\n   (- 1.0 (log (- (/ x (* y y)) (- (/ 1.0 y) (/ x y)))))\n   (if (< y 3.0094271212461764e+25)\n     (log (/ (exp 1.0) (- 1.0 (/ (- x y) (- 1.0 y)))))\n     (- 1.0 (log (- (/ x (* y y)) (- (/ 1.0 y) (/ x y))))))))\n\n (- 1.0 (log (- 1.0 (/ (- x y) (- 1.0 y))))))\n\n(FPCore  (x)\n :name \"Numeric.SpecFunctions:invIncompleteGamma from math-functions-0.1.5.2, C\"\n (- (/ (+ 2.30753 (* x 0.27061)) (+ 1.0 (* x (+ 0.99229 (* x 0.04481))))) x))\n\n(FPCore  (x y)\n :name \"Numeric.SpecFunctions:invIncompleteGamma from math-functions-0.1.5.2, D\"\n :alt \n (! :herbie-platform default\n  (- (- 1.0 (/ (/ 1.0 x) 9.0)) (/ y (* 3.0 (sqrt x)))))\n\n (- (- 1.0 (/ 1.0 (* x 9.0))) (/ y (* 3.0 (sqrt x)))))\n\n(FPCore  (x y)\n :name \"Numeric.SpecFunctions:incompleteBetaApprox from math-functions-0.1.5.2, A\"\n :alt \n (! :herbie-platform default\n  (/ (/ (/ x (+ (+ y 1) x)) (+ y x)) (/ 1 (/ y (+ y x)))))\n\n (/ (* x y) (* (* (+ x y) (+ x y)) (+ (+ x y) 1.0))))\n\n(FPCore  (x y z t a b)\n :name \"Numeric.SpecFunctions:incompleteBetaApprox from math-functions-0.1.5.2, B\"\n (* x (exp (+ (* y (- (log z) t)) (* a (- (log (- 1.0 z)) b))))))\n\n(FPCore  (x y z t a b)\n :name \"Numeric.SpecFunctions:incompleteBetaWorker from math-functions-0.1.5.2, A\"\n :alt \n (! :herbie-platform default\n  (if (< t -0.8845848504127471)\n   (/ (* x (/ (pow a (- t 1.0)) y)) (- (+ b 1) (* y (log z))))\n   (if (< t 852031.2288374073)\n     (/ (* (/ x y) (pow a (- t 1.0))) (exp (- b (* (log z) y))))\n     (/ (* x (/ (pow a (- t 1.0)) y)) (- (+ b 1) (* y (log z)))))))\n\n (/ (* x (exp (- (+ (* y (log z)) (* (- t 1.0) (log a))) b))) y))\n\n(FPCore  (x y z t)\n :name \"Numeric.SpecFunctions:invIncompleteBetaWorker from math-functions-0.1.5.2, B\"\n :alt \n (! :herbie-platform default\n  (-\n  (*\n   (- z)\n   (+ (+ (* 0.5 (* y y)) y) (* (/ 1/3 (* 1.0 (* 1.0 1.0))) (* y (* y y)))))\n  (- t (* x (log y)))))\n\n (- (+ (* x (log y)) (* z (log (- 1.0 y)))) t))\n\n(FPCore  (x y z t)\n :name \"Numeric.SpecFunctions:invIncompleteBetaWorker from math-functions-0.1.5.2, C\"\n :alt \n (! :herbie-platform default\n  (if (< (* x (- (/ y z) (/ t (- 1.0 z)))) -7.623226303312042e-196)\n   (* x (- (/ y z) (* t (/ 1 (- 1.0 z)))))\n   (if (< (* x (- (/ y z) (/ t (- 1.0 z)))) 1.4133944927702302e-211)\n     (+ (/ (* y x) z) (- (/ (* t x) (- 1.0 z))))\n     (* x (- (/ y z) (* t (/ 1 (- 1.0 z))))))))\n\n (* x (- (/ y z) (/ t (- 1.0 z)))))\n\n(FPCore  (x)\n :name \"Numeric.SpecFunctions:invIncompleteBetaWorker from math-functions-0.1.5.2, D\"\n (- x (/ (+ 2.30753 (* x 0.27061)) (+ 1.0 (* (+ 0.99229 (* x 0.04481)) x)))))\n\n(FPCore  (x y)\n :name \"Numeric.SpecFunctions:invIncompleteBetaWorker from math-functions-0.1.5.2, E\"\n (+ (- 1.0 x) (* y (sqrt x))))\n\n(FPCore  (x y)\n :name \"Numeric.SpecFunctions:invIncompleteBetaWorker from math-functions-0.1.5.2, F\"\n :alt \n (! :herbie-platform default\n  (if (< y -3.7311844206647956e+94)\n   (/ (exp (/ -1 y)) x)\n   (if (< y 2.817959242728288e+37)\n     (/ (pow (/ x (+ y x)) x) x)\n     (if (< y 2.347387415166998e+178)\n       (log (exp (/ (pow (/ x (+ y x)) x) x)))\n       (/ (exp (/ -1 y)) x)))))\n\n (/ (exp (* x (log (/ x (+ x y))))) x))\n\n(FPCore  (x y z)\n :name \"Numeric.SpecFunctions:invIncompleteBetaWorker from math-functions-0.1.5.2, G\"\n :alt \n (! :herbie-platform default\n  (if (< (/ y (+ z y)) 7.1154157597908e-315)\n   (+ x (/ (exp (/ -1 z)) y))\n   (+ x (/ (exp (log (pow (/ y (+ y z)) y))) y))))\n\n (+ x (/ (exp (* y (log (/ y (+ z y))))) y)))\n\n(FPCore  (x)\n :name \"Numeric.SpecFunctions:invIncompleteBetaWorker from math-functions-0.1.5.2, H\"\n (/ (- (* x x) 3.0) 6.0))\n\n(FPCore  (x y z t a b c)\n :name \"Numeric.SpecFunctions:invIncompleteBetaWorker from math-functions-0.1.5.2, I\"\n :alt \n (! :herbie-platform default\n  (if (< t -2.118326644891581e-50)\n   (/\n    x\n    (+ x (* y (exp (* 2.0 (- (+ (* a c) (* 0.8333333333333334 c)) (* a b)))))))\n   (if (< t 5.196588770651547e-123)\n     (/\n      x\n      (+\n       x\n       (*\n        y\n        (exp\n         (*\n          2.0\n          (/\n           (-\n            (* (* z (sqrt (+ t a))) (* (* 3.0 t) (- a (/ 5.0 6.0))))\n            (*\n             (- (* (+ (/ 5.0 6.0) a) (* 3.0 t)) 2.0)\n             (* (- a (/ 5.0 6.0)) (* (- b c) t))))\n           (* (* (* t t) 3.0) (- a (/ 5.0 6.0)))))))))\n     (/\n      x\n      (+\n       x\n       (*\n        y\n        (exp\n         (*\n          2.0\n          (-\n           (/ (* z (sqrt (+ t a))) t)\n           (* (- b c) (- (+ a (/ 5.0 6.0)) (/ 2.0 (* t 3.0)))))))))))))\n (/\n  x\n  (+\n   x\n   (*\n    y\n    (exp\n     (*\n      2.0\n      (-\n       (/ (* z (sqrt (+ t a))) t)\n       (* (- b c) (- (+ a (/ 5.0 6.0)) (/ 2.0 (* t 3.0)))))))))))\n\n(FPCore  (x y z)\n :name \"Numeric.SpecFunctions.Extra:bd0 from math-functions-0.1.5.2\"\n :alt \n (! :herbie-platform default\n  (if (< y 7.595077799083773e-308)\n   (- (* x (log (/ x y))) z)\n   (- (* x (- (log x) (log y))) z)))\n\n (- (* x (log (/ x y))) z))\n\n(FPCore  (x y z t a b c i)\n :name \"Numeric.SpecFunctions:logGamma from math-functions-0.1.5.2\"\n (/\n  (+ (* (+ (* (+ (* (+ (* x y) z) y) 27464.7644705) y) 230661.510616) y) t)\n  (+ (* (+ (* (+ (* (+ y a) y) b) y) c) y) i)))\n\n(FPCore  (x y z t a)\n :name \"Statistics.Math.RootFinding:ridders from math-functions-0.1.5.2\"\n :alt \n (! :herbie-platform default\n  (if (< z -3.1921305903852764e+46)\n   (- (* y x))\n   (if (< z 5.976268120920894e+90)\n     (/ (* x z) (/ (sqrt (- (* z z) (* a t))) y))\n     (* y x))))\n\n (/ (* (* x y) z) (sqrt (- (* z z) (* t a)))))\n\n(FPCore  (x y z)\n :name \"Statistics.Distribution.Poisson.Internal:probability from math-functions-0.1.5.2\"\n :alt \n (! :herbie-platform default\n  (exp (+ (- x z) (* (log y) y))))\n\n (exp (- (+ x (* y (log y))) z)))\n\n(FPCore  (x)\n :name \"Statistics.Distribution.Binomial:directEntropy from math-functions-0.1.5.2\"\n (* x (log x)))\n\n(FPCore  (x)\n :name \"Statistics.Correlation.Kendall:numOfTiesBy from math-functions-0.1.5.2\"\n :alt \n (! :herbie-platform default (- (* x x) x))\n\n (* x (- x 1.0)))\n\n(FPCore  (x y z)\n :name \"Statistics.Sample:robustSumVarWeighted from math-functions-0.1.5.2\"\n (+ x (* (* y z) z)))\n\n(FPCore  (x y z)\n :name \"Statistics.Sample:$swelfordMean from math-functions-0.1.5.2\"\n (+ x (/ (- y x) z)))\n\n(FPCore  (x y)\n :name \"Statistics.Sample:$skurtosis from math-functions-0.1.5.2\"\n :alt \n (! :herbie-platform default\n  (- (/ (/ x y) y) 3.0))\n\n (- (/ x (* y y)) 3.0))\n\n(FPCore  (x y z t a b)\n :name \"Statistics.Distribution.Beta:$centropy from math-functions-0.1.5.2\"\n (+ (- (- x (* (- y 1.0) z)) (* (- t 1.0) a)) (* (- (+ y t) 2.0) b)))\n\n(FPCore  (x y z)\n :name \"Statistics.Distribution.Beta:$cvariance from math-functions-0.1.5.2\"\n :alt \n (! :herbie-platform default\n  (if (< z 249.6182814532307)\n   (/ (* y (/ x z)) (+ z (* z z)))\n   (/ (* (/ (/ y z) (+ 1 z)) x) z)))\n\n (/ (* x y) (* (* z z) (+ z 1.0))))\n\n(FPCore  (x y z t)\n :name \"Statistics.Distribution.Beta:$cdensity from math-functions-0.1.5.2\"\n (- (+ (* (- x 1.0) (log y)) (* (- z 1.0) (log (- 1.0 y)))) t))\n\n(FPCore  (x y)\n :name \"Statistics.Distribution.Binomial:$cvariance from math-functions-0.1.5.2\"\n (* (* x y) (- 1.0 y)))\n\n(FPCore  (x y z)\n :name \"Statistics.Distribution.Poisson:$clogProbability from math-functions-0.1.5.2\"\n (- (- (* x (log y)) z) y))\n\n(FPCore  (x y z)\n :name \"Statistics.Distribution.CauchyLorentz:$cdensity from math-functions-0.1.5.2\"\n :alt \n (! :herbie-platform default\n  (if (< (* y (+ 1.0 (* z z))) -inf.0)\n   (/ (/ 1.0 y) (* (+ 1.0 (* z z)) x))\n   (if (< (* y (+ 1.0 (* z z))) 8.680743250567252e+305)\n     (/ (/ 1.0 x) (* (+ 1.0 (* z z)) y))\n     (/ (/ 1.0 y) (* (+ 1.0 (* z z)) x)))))\n\n (/ (/ 1.0 x) (* y (+ 1.0 (* z z)))))\n\n(FPCore  (x y)\n :name \"Examples.Basics.BasicTests:f3 from sbv-4.4\"\n :alt \n (! :herbie-platform default\n  (+ (* x x) (+ (* y y) (* 2 (* y x)))))\n\n (* (+ x y) (+ x y)))\n\n(FPCore  (x y)\n :name \"Examples.Basics.BasicTests:f2 from sbv-4.4\"\n (- (* x x) (* y y)))\n\n(FPCore  (x y)\n :name \"Examples.Basics.BasicTests:f1 from sbv-4.4\"\n (* (+ x y) (- x y)))\n\n(FPCore  (x y)\n :name \"Examples.Basics.ProofTests:f4 from sbv-4.4\"\n :alt \n (! :herbie-platform default\n  (+ (* x x) (+ (* y y) (* (* x y) 2.0))))\n\n (+ (+ (* x x) (* (* x 2.0) y)) (* y y)))\n\n(FPCore  (x y)\n :name \"Numeric.LinearAlgebra.Util:formatSparse from hmatrix-0.16.1.5\"\n (/ (fabs (- x y)) (fabs y)))\n\n(FPCore  (x y)\n :name \"Data.Random.Distribution.Normal:normalF from random-fu-0.2.6.2\"\n (exp (* (* x y) y)))\n\n(FPCore  (x y)\n :name \"Data.Random.Distribution.Normal:normalTail from random-fu-0.2.6.2\"\n :alt \n (! :herbie-platform default\n  (+ (+ y y) (* x x)))\n\n (+ (+ (* x x) y) y))\n\n(FPCore  (x)\n :name \"Data.Random.Distribution.Normal:doubleStdNormalZ from random-fu-0.2.6.2\"\n (- (+ x x) 1.0))\n\n(FPCore  (x y)\n :name \"Data.Random.Distribution.T:$ccdf from random-fu-0.2.6.2\"\n :alt \n (! :herbie-platform default\n  (+ (* 1/2 (/ x y)) 1/2))\n\n (/ (+ x y) (+ y y)))\n\n(FPCore  (x y z t)\n :name \"Data.Random.Distribution.Triangular:triangularCDF from random-fu-0.2.6.2, A\"\n (- 1.0 (/ x (* (- y z) (- y t)))))\n\n(FPCore  (x y z t)\n :name \"Data.Random.Distribution.Triangular:triangularCDF from random-fu-0.2.6.2, B\"\n :alt \n (! :herbie-platform default\n  (if (< (/ x (* (- y z) (- t z))) 0.0)\n   (/ (/ x (- y z)) (- t z))\n   (* x (/ 1 (* (- y z) (- t z))))))\n\n (/ x (* (- y z) (- t z))))\n\n(FPCore  (x)\n :name \"Data.Random.Dice:roll from dice-0.1\"\n (- (* x x) 1.0))\n\n(FPCore  (x)\n :name \"Prelude:atanh from fay-base-0.20.0.1\"\n (/ (+ x 1.0) (- 1.0 x)))\n\n(FPCore  (x)\n :name \"ReportTypes:explainFloat from gipeda-0.1.2.1\"\n :alt \n (! :herbie-platform default 0)\n\n (* 100.0 (/ (- x x) x)))\n\n(FPCore  (x y z t a)\n :name \"Hakyll.Web.Tags:renderTagCloud from hakyll-4.7.2.3\"\n (+ x (* (/ (- y z) (- (+ t 1.0) z)) (- a x))))\n\n(FPCore  (x y z)\n :name \"Data.Histogram.Bin.BinF:$cfromIndex from histogram-fill-0.8.4.1\"\n (+ (+ (/ x 2.0) (* y x)) z))\n\n(FPCore  (x y)\n :name \"Data.Histogram.Bin.LogBinD:$cbinSizeN from histogram-fill-0.8.4.1\"\n (- (* x y) x))\n\n(FPCore  (x y z t a)\n :name \"Numeric.Signal:interpolate   from hsignal-0.2.7.1\"\n (+ x (* (- y z) (/ (- t x) (- a z)))))\n\n(FPCore  (x y z t)\n :name \"Numeric.Signal.Multichannel:$cget from hsignal-0.2.7.1\"\n :alt \n (! :herbie-platform default\n  (if (< z 2.759456554562692e-282)\n   (+ (* (/ x y) (- z t)) t)\n   (if (< z 2.326994450874436e-110)\n     (+ (* x (/ (- z t) y)) t)\n     (+ (* (/ x y) (- z t)) t))))\n\n (+ (* (/ x y) (- z t)) t))\n\n(FPCore  (x y z t)\n :name \"Numeric.Signal.Multichannel:$cput from hsignal-0.2.7.1\"\n :alt \n (! :herbie-platform default\n  (/ t (/ (- z y) (- x y))))\n\n (* (/ (- x y) (- z y)) t))\n\n(FPCore  (x y)\n :name \"Data.HyperLogLog.Config:hll from hyperloglog-0.3.4\"\n (* (* x y) y))\n\n(FPCore  (x y)\n :name \"Data.HyperLogLog.Type:size from hyperloglog-0.3.4, A\"\n :alt \n (! :herbie-platform default\n  (* x (log (- 1.0 (/ y x)))))\n\n (* (* x 1.0) (log (- 1.0 (/ y x)))))\n\n(FPCore  (x y)\n :name \"Data.HyperLogLog.Type:size from hyperloglog-0.3.4, B\"\n :alt \n (! :herbie-platform default\n  (if (< y 1.2973149052617803e-303)\n   (* x (log (/ x y)))\n   (/ x (/ 1 (- (log x) (log y))))))\n\n (* x (log (/ x y))))\n\n(FPCore  (x y z)\n :name \"Diagrams.Backend.Cairo.Internal:setTexture from diagrams-cairo-1.3.0.3\"\n :alt \n (! :herbie-platform default\n  (if (< z -2.060202331921739e+104)\n   (- x (/ (* z x) y))\n   (if (< z 1.6939766013828526e+213) (/ x (/ y (- y z))) (* (- y z) (/ x y)))))\n\n (/ (* x (- y z)) y))\n\n(FPCore  (x y)\n :name \"Numeric.Integration.TanhSinh:simpson  from integration-0.2.1\"\n (* x (+ y y)))\n\n(FPCore  (x y)\n :name \"Numeric.Integration.TanhSinh:everywhere from integration-0.2.1\"\n :alt \n (! :herbie-platform default\n  (+ x (* (* x y) y)))\n\n (* x (+ 1.0 (* y y))))\n\n(FPCore  (x y z t)\n :name \"Data.Metrics.Snapshot:quantile from metrics-0.3.0.2\"\n :alt \n (! :herbie-platform default\n  (+ x (+ (* t (- y z)) (* (- x) (- y z)))))\n\n (+ x (* (- y z) (- t x))))\n\n(FPCore  (x y)\n :name \"Graphics.Rendering.Plot.Render.Plot.Legend:renderLegendOutside from plot-0.2.3.4, A\"\n :alt \n (! :herbie-platform default\n  (+ y (* 2 x)))\n\n (+ (+ x y) x))\n\n(FPCore  (x y z t)\n :name \"Graphics.Rendering.Plot.Render.Plot.Legend:renderLegendOutside from plot-0.2.3.4, B\"\n (+ (* x (+ (+ (+ (+ y z) z) y) t)) (* y 5.0)))\n\n(FPCore  (x y z)\n :name \"Graphics.Rendering.Plot.Render.Plot.Legend:renderLegendInside from plot-0.2.3.4\"\n (+ (+ (+ (+ (+ x y) y) x) z) x))\n\n(FPCore  (x y z)\n :name \"Graphics.Rendering.Plot.Render.Plot.Legend:renderLegendOutside from plot-0.2.3.4, C\"\n :alt \n (! :herbie-platform default\n  (+ (* (+ x 5.0) z) (* x y)))\n\n (+ (* x (+ y z)) (* z 5.0)))\n\n(FPCore  (x y z t)\n :name \"Graphics.Rendering.Plot.Render.Plot.Axis:tickPosition from plot-0.2.3.4\"\n :alt \n (! :herbie-platform default\n  (if (< (* (- y x) (/ z t)) -1013646692435.8867)\n   (+ x (/ (- y x) (/ t z)))\n   (if (< (* (- y x) (/ z t)) -0.0)\n     (+ x (/ (* (- y x) z) t))\n     (+ x (/ (- y x) (/ t z))))))\n\n (+ x (* (- y x) (/ z t))))\n\n(FPCore  (x y z t a)\n :name \"Graphics.Rendering.Plot.Render.Plot.Axis:renderAxisLine from plot-0.2.3.4, A\"\n :alt \n (! :herbie-platform default\n  (+ x (/ y (/ (- z a) (- z t)))))\n\n (+ x (* y (/ (- z t) (- z a)))))\n\n(FPCore  (x y z t a)\n :name \"Graphics.Rendering.Plot.Render.Plot.Axis:renderAxisLine from plot-0.2.3.4, B\"\n :alt \n (! :herbie-platform default\n  (if (< y -8.508084860551241e-17)\n   (+ x (* y (/ (- z t) (- a t))))\n   (if (< y 2.894426862792089e-49)\n     (+ x (* (* y (- z t)) (/ 1 (- a t))))\n     (+ x (* y (/ (- z t) (- a t)))))))\n\n (+ x (* y (/ (- z t) (- a t)))))\n\n(FPCore  (x y z t a)\n :name \"Graphics.Rendering.Plot.Render.Plot.Axis:renderAxisTick from plot-0.2.3.4, A\"\n :alt \n (! :herbie-platform default\n  (if (< t -1.0682974490174067e-39)\n   (+ x (* (/ (- y z) (- a z)) t))\n   (if (< t 3.9110949887586375e-141)\n     (+ x (/ (* (- y z) t) (- a z)))\n     (+ x (* (/ (- y z) (- a z)) t)))))\n\n (+ x (/ (* (- y z) t) (- a z))))\n\n(FPCore  (x y z t a)\n :name \"Graphics.Rendering.Plot.Render.Plot.Axis:renderAxisTick from plot-0.2.3.4, B\"\n :alt \n (! :herbie-platform default\n  (if (< (- (+ x y) (/ (* (- z t) y) (- a t))) -1.3664970889390727e-07)\n   (- (+ y x) (* (* (- z t) (/ 1 (- a t))) y))\n   (if (< (- (+ x y) (/ (* (- z t) y) (- a t))) 1.4754293444577233e-239)\n     (/ (- (* y (- a z)) (* x t)) (- a t))\n     (- (+ y x) (* (* (- z t) (/ 1 (- a t))) y)))))\n\n (- (+ x y) (/ (* (- z t) y) (- a t))))\n\n(FPCore  (x y z t a)\n :name \"Graphics.Rendering.Plot.Render.Plot.Axis:renderAxisTicks from plot-0.2.3.4, A\"\n :alt \n (! :herbie-platform default\n  (+ x (/ y (/ (- z a) (- z t)))))\n\n (+ x (/ (* y (- z t)) (- z a))))\n\n(FPCore  (x y z t a)\n :name \"Graphics.Rendering.Plot.Render.Plot.Axis:renderAxisTicks from plot-0.2.3.4, B\"\n :alt \n (! :herbie-platform default\n  (+ x (/ y (/ (- a t) (- z t)))))\n\n (+ x (/ (* y (- z t)) (- a t))))\n\n(FPCore  (x y z)\n :name \"Data.Array.Repa.Algorithms.Pixel:doubleRmsOfRGB8 from repa-algorithms-3.4.0.1\"\n :alt \n (! :herbie-platform default\n  (if (< z -6.396479394109776e+136)\n   (/ (- z) (sqrt 3.0))\n   (if (< z 7.320293694404182e+117)\n     (/ (sqrt (+ (+ (* z z) (* x x)) (* y y))) (sqrt 3.0))\n     (* (sqrt 0.3333333333333333) z))))\n\n (sqrt (/ (+ (+ (* x x) (* y y)) (* z z)) 3.0)))\n\n(FPCore  (x y z)\n :name \"Data.Array.Repa.Algorithms.ColorRamp:rampColorHotToCold from repa-algorithms-3.4.0.1, A\"\n (+ 1.0 (/ (* 4.0 (- (+ x (* y 0.75)) z)) y)))\n\n(FPCore  (x y z)\n :name \"Data.Array.Repa.Algorithms.ColorRamp:rampColorHotToCold from repa-algorithms-3.4.0.1, B\"\n :alt \n (! :herbie-platform default\n  (- (* 4.0 (/ x z)) (+ 2.0 (* 4.0 (/ y z)))))\n\n (/ (* 4.0 (- (- x y) (* z 0.5))) z))\n\n(FPCore  (x y z)\n :name \"Data.Array.Repa.Algorithms.ColorRamp:rampColorHotToCold from repa-algorithms-3.4.0.1, C\"\n (+ 1.0 (/ (* 4.0 (- (+ x (* y 0.25)) z)) y)))\n\n(FPCore  (x)\n :name \"Data.Spline.Key:interpolateKeys from smoothie-0.4.0.2\"\n :alt \n (! :herbie-platform default\n  (* x (* x (- 3.0 (* x 2.0)))))\n\n (* (* x x) (- 3.0 (* x 2.0))))\n\n(FPCore  (x y z)\n :name \"FRP.Yampa.Vector3:vector3Rho from Yampa-0.10.2\"\n :alt \n (! :herbie-platform default\n  (if (< z -6.396479394109776e+136)\n   (- z)\n   (if (< z 7.320293694404182e+117) (sqrt (+ (+ (* z z) (* x x)) (* y y))) z)))\n\n (sqrt (+ (+ (* x x) (* y y)) (* z z))))\n\n(FPCore  (x y z t)\n :name \"SynthBasics:moogVCF from YampaSynth-0.2\"\n :alt \n (! :herbie-platform default\n  (+ x (* y (* z (- (tanh (/ t y)) (tanh (/ x y)))))))\n  \n (+ x (* (* y z) (- (tanh (/ t y)) (tanh (/ x y))))))\n"
  },
  {
    "path": "bench/libraries/fast-math.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (d1 d2 d3)\n :name \"FastMath dist\"\n :alt \n (! :herbie-platform c\n  (* d1 (+ d2 d3)))\n\n (+ (* d1 d2) (* d1 d3)))\n\n(FPCore (d)\n :name \"FastMath test1\"\n :alt \n (! :herbie-platform c (* d 30))\n\n (+ (* d 10) (* d 20)))\n\n(FPCore (d1 d2)\n :name \"FastMath test2\"\n :alt \n (! :herbie-platform c\n  (* d1 (+ 30 d2)))\n\n (+ (+ (* d1 10) (* d1 d2)) (* d1 20)))\n\n(FPCore (d1 d2 d3)\n :name \"FastMath dist3\"\n :alt \n (! :herbie-platform c\n  (* d1 (+ 37 d3 d2)))\n\n (+ (+ (* d1 d2) (* (+ d3 5) d1)) (* d1 32)))\n\n(FPCore (d1 d2 d3 d4)\n :name \"FastMath dist4\"\n :alt \n (! :herbie-platform c\n  (* d1 (- (+ (- d2 d3) d4) d1)))\n\n (- (+ (- (* d1 d2) (* d1 d3)) (* d4 d1)) (* d1 d1)))\n\n(FPCore (d1 d2 d3)\n :name \"FastMath test3\"\n :alt \n (! :herbie-platform c\n  (* d1 (+ 3 d2 d3)))\n\n (+ (+ (* d1 3) (* d1 d2)) (* d1 d3)))\n\n(FPCore (d1)\n :name \"FastMath repmul\"\n :alt \n (! :herbie-platform c (pow d1 4))\n\n (* (* (* d1 d1) d1) d1))\n\n(FPCore (d1)\n :name \"FastMath test5\"\n :alt \n (! :herbie-platform c (pow d1 10))\n \n (* (* d1 (* (* (* (* (* d1 (* d1 d1)) d1) d1) (* d1 d1)) d1)) d1))\n"
  },
  {
    "path": "bench/libraries/jmatjs.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (z)\n :name \"Jmat.Real.gamma, branch z greater than 0.5\"\n :pre (> z 0.5)\n (let ((z* (- z 1)) (g 7))\n   (let ((x\n          (+ (+ (+ (+ (+ (+ (+ \n          (+ 0.9999999999998099 (/ 676.5203681218851 (+ z* 1)))\n           (/ -1259.1392167224028 (+ z* 2)))\n           (/ 771.3234287776531 (+ z* 3)))\n           (/ -176.6150291621406 (+ z* 4)))\n           (/ 12.507343278686905 (+ z* 5)))\n           (/ -0.13857109526572012 (+ z* 6)))\n           (/ 9.984369578019572e-06 (+ z* 7)))\n           (/ 1.5056327351493116e-07 (+ z* 8))))\n         (t (+ (+ z* g) 0.5)))\n     (* (* (* (sqrt (* PI 2)) (pow t (+ z* 0.5))) (exp (- t))) x))))\n\n(FPCore (z)\n :name \"Jmat.Real.gamma, branch z less than 0.5\"\n :pre (<= z 0.5)\n (let ((z* (- (- 1 z) 1)) (g 7))\n   (let ((x\n          (+ (+ (+ (+ (+ (+ (+ \n          (+ 0.9999999999998099 (/ 676.5203681218851 (+ z* 1)))\n           (/ -1259.1392167224028 (+ z* 2)))\n           (/ 771.3234287776531 (+ z* 3)))\n           (/ -176.6150291621406 (+ z* 4)))\n           (/ 12.507343278686905 (+ z* 5)))\n           (/ -0.13857109526572012 (+ z* 6)))\n           (/ 9.984369578019572e-06 (+ z* 7)))\n           (/ 1.5056327351493116e-07 (+ z* 8))))\n         (t (+ (+ z* g) 0.5)))\n     (*\n      (/ PI (sin (* PI z)))\n      (* (* (* (sqrt (* PI 2)) (pow t (+ z* 0.5))) (exp (- t))) x)))))\n\n(FPCore (x)\n :name \"Jmat.Real.lambertw, estimator\"\n (- (log x) (log (log x))))\n\n(FPCore (wj x)\n :name \"Jmat.Real.lambertw, newton loop step\"\n :alt \n (! :herbie-platform c\n  (let ((ew (exp wj)))\n   (- wj (- (/ wj (+ wj 1)) (/ x (+ ew (* wj ew)))))))\n   \n (let ((ew (exp wj)))\n   (- wj (/ (- (* wj ew) x) (+ ew (* wj ew))))))\n\n(FPCore (x)\n :name \"Jmat.Real.dawson\"\n (let ((p1 0.1049934947) (p2 0.0424060604) (p3 0.0072644182)\n       (p4 0.0005064034) (p5 0.0001789971) (q1 0.7715471019)\n       (q2 0.2909738639) (q3 0.0694555761) (q4 0.0140005442)\n       (q5 0.0008327945))\n   (let ((x2 (* x x)))\n     (let ((x4 (* x2 x2)))\n       (let ((x6 (* x4 x2)))\n         (let ((x8 (* x6 x2)))\n           (let ((x10 (* x8 x2)))\n             (let ((x12 (* x10 x2)))\n               (*\n                (/ (+ (+ (+ (+ (+ 1 (* p1 x2)) (* p2 x4)) (* p3 x6)) (* p4 x8)) (* p5 x10))\n                   (+ (+ (+ (+ (+ (+ 1 (* q1 x2)) (* q2 x4)) (* q3 x6)) (* q4 x8)) (* q5 x10)) (* (* 2 p5) x12)))\n                x)))))))))\n\n(FPCore (x)\n :name \"Jmat.Real.erfi, branch x less than or equal to 0.5\"\n :pre (<= x 0.5)\n (let ((sqrtPI (sqrt PI)))\n   (let ((ps (/ 1 sqrtPI)))\n     (let ((x* (fabs x)))\n       (let ((x3 (* (* x* x*) x*)))\n         (let ((x5 (* (* x3 x*) x*)))\n           (let ((x7 (* (* x5 x*) x*)))\n             (let ((t (+ (+ (+ (* 2 x*) (* (/ 2 3) x3)) (* (/ 1 5) x5)) (* (/ 1 21) x7))))\n               (fabs (* ps t))))))))))\n\n(FPCore (x)\n :name \"Jmat.Real.erfi, branch x greater than or equal to 5\"\n :pre (>= x 0.5)\n (let ((sqrtPI (sqrt PI)))\n   (let ((ps (/ 1 sqrtPI)))\n     (let ((x* (fabs x)))\n       (let ((xi (/ 1 x*)))\n         (let ((xi3 (* (* xi xi) xi)))\n           (let ((xi5 (* (* xi3 xi) xi)))\n             (let ((xi7 (* (* xi5 xi) xi)))\n               (let ((e (exp (* x* x*))))\n                 (let ((t (+ (+ (+ xi (* (/ 1 2) xi3)) (* (/ 3 4) xi5)) (* (/ 15 8) xi7))))\n                   (* (* ps e) t)))))))))))\n\n(FPCore (x)\n :name \"Jmat.Real.erf\"\n (let ((x* (fabs x)))\n   (let ((t (/ 1 (+ 1 (* 0.3275911 x*)))))\n     (let ((p (* t (+ 0.254829592 (* t (+ -0.284496736 (* t (+ 1.421413741 (* t (+ -1.453152027 (* t 1.061405429)))))))))))\n       (- 1 (* p (exp (- (* x* x*)))))))))\n"
  },
  {
    "path": "bench/libraries/mathjs/arithmetic.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore modulus (re im)\n :name \"math.abs on complex\"\n (sqrt (+ (* re re) (* im im))))\n\n(FPCore modulus_sqr (re im)\n :name \"math.abs on complex (squared)\"\n (+ (* re re) (* im im)))\n\n(FPCore re_sqr (re im)\n :name \"math.square on complex, real part\"\n (- (* re re) (* im im)))\n\n(FPCore im_sqr (re im)\n :name \"math.square on complex, imaginary part\"\n (+ (* re im) (* im re)))\n\n(FPCore (x)\n :name \"math.cube on real\"\n :alt \n (! :herbie-platform c (pow x 3))\n (* (* x x) x))\n\n(FPCore (x.re x.im)\n :name \"math.cube on complex, real part\"\n :alt \n (! :herbie-platform c\n  (+ (* (* x.re x.re) (- x.re x.im))\n    (* (* x.re x.im) (- x.re (* 3 x.im)))))\n\n (-\n  (* (re_sqr x.re x.im) x.re)\n  (* (im_sqr x.re x.im) x.im)))\n\n(FPCore (x.re x.im)\n :name \"math.cube on complex, imaginary part\"\n :alt \n (! :herbie-platform c\n  (+\n   (* (* x.re x.im) (* 2 x.re))\n   (* (* x.im (- x.re x.im)) (+ x.re x.im))))\n\n (+\n  (* (re_sqr x.re x.im) x.im)\n  (* (im_sqr x.re x.im) x.re)))\n\n(FPCore (x.re x.im y.re y.im)\n :name \"_divideComplex, real part\"\n (/ (+ (* x.re y.re) (* x.im y.im)) (modulus_sqr y.re y.im)))\n\n(FPCore (x.re x.im y.re y.im)\n :name \"_divideComplex, imaginary part\"\n (/ (- (* x.im y.re) (* x.re y.im)) (modulus_sqr y.re y.im)))\n\n(FPCore (re im)\n :name \"math.exp on complex, real part\"\n (* (exp re) (cos im)))\n\n(FPCore (re im)\n :name \"math.exp on complex, imaginary part\"\n (* (exp re) (sin im)))\n\n(FPCore (re im)\n :name \"math.log/1 on complex, real part\"\n (log (modulus re im)))\n\n(FPCore (re im)\n :name \"math.log/1 on complex, imaginary part\"\n (atan2 im re))\n\n(FPCore (re im base)\n :name \"math.log/2 on complex, real part\"\n (/\n  (+ (* (log (modulus re im)) (log base)) (* (atan2 im re) 0))\n  (+ (* (log base) (log base)) (* 0 0))))\n\n(FPCore (re im base)\n :name \"math.log/2 on complex, imaginary part\"\n (/\n  (- (* (atan2 im re) (log base)) (* (log (modulus re im)) 0))\n  (+ (* (log base) (log base)) (* 0 0))))\n\n(FPCore (re im)\n :name \"math.log10 on complex, real part\"\n (/ (log (modulus re im)) (log 10)))\n\n(FPCore (re im)\n :name \"math.log10 on complex, imaginary part\"\n (/ (atan2 im re) (log 10)))\n\n(FPCore (x.re x.im y.re y.im)\n :name \"_multiplyComplex, real part\"\n (- (* x.re y.re) (* x.im y.im)))\n\n(FPCore (x.re x.im y.re y.im)\n :name \"_multiplyComplex, imaginary part\"\n (+ (* x.re y.im) (* x.im y.re)))\n\n(FPCore (x.re x.im y.re y.im)\n :name \"powComplex, real part\"\n (*\n  (exp\n   (-\n    (* (log (modulus x.re x.im)) y.re)\n    (* (atan2 x.im x.re) y.im)))\n  (cos\n   (+\n    (* (log (modulus x.re x.im)) y.im)\n    (* (atan2 x.im x.re) y.re)))))\n\n(FPCore (x.re x.im y.re y.im)\n :name \"powComplex, imaginary part\"\n (*\n  (exp\n   (-\n    (* (log (modulus x.re x.im)) y.re)\n    (* (atan2 x.im x.re) y.im)))\n  (sin\n   (+\n    (* (log (modulus x.re x.im)) y.im)\n    (* (atan2 x.im x.re) y.re)))))\n\n(FPCore (re im)\n :name \"math.sqrt on complex, real part\"\n :alt \n (! :herbie-platform c\n  (if (< re 0)\n   (* 0.5 (* (sqrt 2) (sqrt (/ (* im im) (- (modulus re im) re)))))\n   (* 0.5 (sqrt (* 2.0 (+ (modulus re im) re))))))\n   \n (* 0.5 (sqrt (* 2.0 (+ (modulus re im) re)))))\n\n(FPCore (re im)\n :name \"math.sqrt on complex, imaginary part, im greater than 0 branch\"\n :pre (> im 0)\n (* 0.5 (sqrt (* 2.0 (- (modulus re im) re)))))\n"
  },
  {
    "path": "bench/libraries/mathjs/complex.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (re im)\n :name \"math.arg on complex\"\n (atan2 im re))\n"
  },
  {
    "path": "bench/libraries/mathjs/probability.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (u1 u2)\n :name \"normal distribution\"\n :pre (and (<= 0 u1 1) (<= 0 u2 1))\n (+ (* (* (/ 1 6) (pow (* -2 (log u1)) 0.5)) (cos (* (* 2 PI) u2))) 0.5))\n"
  },
  {
    "path": "bench/libraries/mathjs/trigonometry.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (re im)\n :name \"math.cos on complex, real part\"\n (* (* 0.5 (cos re)) (+ (exp (- im)) (exp im))))\n\n(FPCore (re im)\n :name \"math.cos on complex, imaginary part\"\n :alt \n (! :herbie-platform default\n  (if (< (fabs im) 1)\n   (- (* (sin re) (+ im (* 1/6 im im im) (* 1/120 im im im im im))))\n   (* (* 0.5 (sin re)) (- (exp (- im)) (exp im)))))\n\n (* (* 0.5 (sin re)) (- (exp (- im)) (exp im))))\n\n(FPCore (re im)\n :name \"math.sin on complex, real part\"\n (* (* 0.5 (sin re)) (+ (exp (- 0 im)) (exp im))))\n\n(FPCore (re im)\n :name \"math.sin on complex, imaginary part\"\n :alt \n (! :herbie-platform default\n  (if (< (fabs im) 1)\n   (- (* (cos re) (+ im (* 1/6 im im im) (* 1/120 im im im im im))))\n   (* (* 0.5 (cos re)) (- (exp (- 0 im)) (exp im)))))\n\n (* (* 0.5 (cos re)) (- (exp (- 0 im)) (exp im))))\n\n\n(FPCore (x)\n :name \"Ian Simplification\"\n :alt \n  (! :herbie-platform default (asin x))\n \n (- (/ PI 2)\n    (* 2 (asin (sqrt (/ (- 1 x) 2))))))\n"
  },
  {
    "path": "bench/libraries/octave/CollocWt.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (alpha beta)\n :pre (and (> alpha -1) (> beta -1))\n :name \"Octave 3.8, jcobi/1\"\n (let ((ab (+ alpha beta)) (ad (- beta alpha)) (ap (* beta alpha)))\n   (/ (+ (/ ad (+ ab 2.0)) 1.0) 2.0)))\n\n; TODO: i should be an integer\n(FPCore (alpha beta i)\n :pre (and (> alpha -1) (> beta -1) (> i 0))\n :name \"Octave 3.8, jcobi/2\"\n (let ((ab (+ alpha beta)) (ad (- beta alpha)) (ap (* beta alpha)))\n   (let ((z (+ ab (* 2 i))))\n     (/ (+ (/ (/ (* ab ad) z) (+ z 2.0)) 1.0) 2.0))))\n\n(FPCore (alpha beta)\n :pre (and (> alpha -1) (> beta -1))\n :name \"Octave 3.8, jcobi/3\"\n (let ((i 1) (ab (+ alpha beta)) (ad (- beta alpha)) (ap (* beta alpha)))\n   (let ((z1 i))\n     (let ((z (+ ab (* 2 z1))))\n       (/ (/ (/ (+ (+ ab ap) 1.0) z) z) (+ z 1.0))))))\n\n(FPCore (alpha beta i) ; TODO: i should be an integer\n :pre (and (> alpha -1) (> beta -1) (> i 1))\n :name \"Octave 3.8, jcobi/4\"\n (let ((ab (+ alpha beta)) (ad (- beta alpha)) (ap (* beta alpha)))\n   (let ((z (+ ab (* 2 i))))\n     (let ((z* (* z z)) (y (* i (+ ab i))))\n       (let ((y* (* y (+ ap y))))\n         (/ (/ y* z*) (- z* 1.0)))))))\n; TODO: i should be an integer\n(FPCore (i)\n :pre (and (> i 0))\n :name \"Octave 3.8, jcobi/4, as called\"\n (let ((z (* 2 i)))\n   (let ((z* (* z z)) (y (* i i)))\n     (let ((y* (* y y))) (/ (/ y* z*) (- z* 1.0))))))\n"
  },
  {
    "path": "bench/libraries/octave/randgamma.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (a rand)\n :name \"Octave 3.8, oct_fill_randg\"\n (let ((d (- a (/ 1.0 3.0))))\n   (let ((c (/ 1 (sqrt (* 9 d)))) (x rand))\n     (let ((v (+ 1 (* c x))))\n       (let ((v* (* v (* v v))) (xsq (* x x)))\n         (* d v))))))\n"
  },
  {
    "path": "bench/libraries/rust.fpcore",
    "content": "(FPCore (x)\n  :name \"Rust f64::asinh\"\n  :spec (asinh x)\n\n  :alt \n  (! :herbie-platform c\n   (let* ([ax (fabs x)] [ix (/ 1 ax)])\n    (copysign (log1p (+ ax (/ ax (+ (hypot 1 ix) ix)))) x)))\n\n  (copysign (log (+ (fabs x) (sqrt (+ (* x x) 1)))) x))\n\n(FPCore (x)\n  :name \"Rust f32::asinh\"\n  :spec (asinh x)\n  :precision binary32\n\n  :alt \n  (! :herbie-platform c\n   (let* ([ax (fabs x)] [ix (/ 1 ax)])\n    (copysign (log1p (+ ax (/ ax (+ (hypot 1 ix) ix)))) x)))\n\n  (copysign (log (+ (fabs x) (sqrt (+ (* x x) 1)))) x))\n\n(FPCore (x)\n  :name \"Rust f64::acosh\"\n  :spec (acosh x)\n  :pre (>= x 1)\n\n  :alt \n  (! :herbie-platform c\n   (log (+ x (* (sqrt (- x 1)) (sqrt (+ x 1))))))\n\n  (log (+ x (sqrt (- (* x x) 1)))))\n\n(FPCore (x)\n  :name \"Rust f32::acosh\"\n  :spec (acosh x)\n  :precision binary32\n  :pre (>= x 1)\n\n  :alt \n  (! :herbie-platform c\n   (log (+ x (* (sqrt (- x 1)) (sqrt (+ x 1))))))\n\n  (log (+ x (sqrt (- (* x x) 1)))))\n\n(FPCore (x)\n  :name \"Rust f64::atanh\"\n  :spec (atanh x)\n\n  (* 0.5 (log1p (/ (* 2 x) (- 1 x)))))\n\n(FPCore (x)\n  :name \"Rust f32::atanh\"\n  :spec (atanh x)\n  :precision binary32\n\n  (* 0.5 (log1p (/ (* 2 x) (- 1 x)))))\n"
  },
  {
    "path": "bench/mathematics/arvind.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (a b)\n :name \"Exp of sum of logs\"\n :alt \n (! :herbie-platform c (* a b))\n\n (exp (+ (log a) (log b))))\n\n(FPCore (a b)\n :name \"Quotient of sum of exps\"\n :alt \n (! :herbie-platform c\n  (/ 1 (+ 1 (exp (- b a)))))\n\n (/ (exp a) (+ (exp a) (exp b))))\n\n(FPCore (a1 a2 b1 b2)\n :name \"Quotient of products\"\n :alt \n (! :herbie-platform c\n  (* (/ a1 b1) (/ a2 b2)))\n  \n (/ (* a1 a2) (* b1 b2)))\n"
  },
  {
    "path": "bench/mathematics/beta-distribution.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (m v)\n :pre (and (< 0 m) (< 0 v) (< v 0.25))\n :name \"a parameter of renormalized beta distribution\"\n (* (- (/ (* m (- 1 m)) v) 1) m))\n\n(FPCore (m v)\n :pre (and (< 0 m) (< 0 v) (< v 0.25))\n :name \"b parameter of renormalized beta distribution\"\n (* (- (/ (* m (- 1 m)) v) 1) (- 1 m)))\n"
  },
  {
    "path": "bench/mathematics/dirichlet-mixture-model.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (c_p c_n t s)\n :pre (and (< 0 c_p) (< 0 c_n))\n :name \"Harley's example\"\n :alt \n (! :herbie-platform c\n  (*\n   (pow (/ (+ 1 (exp (- t))) (+ 1 (exp (- s)))) c_p)\n   (pow (/ (+ 1 (exp t)) (+ 1 (exp s))) c_n)))\n   \n (/\n  (* (pow (/ 1 (+ 1 (exp (- s)))) c_p) (pow (- 1 (/ 1 (+ 1 (exp (- s))))) c_n))\n  (* (pow (/ 1 (+ 1 (exp (- t)))) c_p) (pow (- 1 (/ 1 (+ 1 (exp (- t))))) c_n))))\n"
  },
  {
    "path": "bench/mathematics/excel.fpcore",
    "content": "(FPCore (x0 x1)\n  :name \"(- (/ x0 (- 1 x1)) x0)\"\n  :pre (or (and (== x0 1.855) (== x1 0.000209)) (and (== x0 2.985) (== x1 0.0186)))\n  :alt \n  (! :herbie-platform c \n    (/ (* x0 x1) (- 1 x1)))\n    \n  (- (/ x0 (- 1 x1)) x0))\n"
  },
  {
    "path": "bench/mathematics/gui.fpcore",
    "content": ";; from racket/gui https://github.com/racket/gui/commit/e8decf79852b9dac06ebd91a9aae5c0c3b215c34\n\n;; Robby simplifies this to just (/ (* 4 F) (pow (* x-scale y-scale) 2))\n(FPCore (a b angle x-scale y-scale)\n  :name \"Simplification of discriminant from scale-rotated-ellipse\"\n  (let* ([θ (* (/ angle 180) PI)]\n         [F (* (* b a) (* b (- a)))]\n         [A (/ (/ (+ (pow (* a (sin θ)) 2) (pow (* b (cos θ)) 2))\n                x-scale) x-scale)]\n         [B (/ (/ (* (* (* 2 (- (pow b 2) (pow a 2))) (sin θ)) (cos θ))\n                x-scale) y-scale)]\n         [C (/ (/ (+ (pow (* a (cos θ)) 2) (pow (* b (sin θ)) 2))\n                y-scale) y-scale)])\n        (- (* B B) (* (* 4 A) C))))\n\n\n(FPCore (a b angle x-scale y-scale)\n  :name \"raw-angle from scale-rotated-ellipse\"\n  (let* ([θ (* (/ angle 180) PI)]\n         [F (* (* b a) (* b (- a)))]\n         [A (/ (/ (+ (pow (* a (sin θ)) 2) (pow (* b (cos θ)) 2))\n                x-scale) x-scale)]\n         [B (/ (/ (* (* (* 2 (- (pow b 2) (pow a 2))) (sin θ)) (cos θ))\n                x-scale) y-scale)]\n         [C (/ (/ (+ (pow (* a (cos θ)) 2) (pow (* b (sin θ)) 2))\n                y-scale) y-scale)]\n         [B^2-4AC (/ (* 4 F) (pow (* x-scale y-scale) 2))]\n         [q (* (* 2 B^2-4AC) F)]\n         [r (sqrt (+ (pow (- A C) 2) (pow B 2)))])\n        (* 180 (/ (atan (/ (- (- C A) r) B)) PI))))\n\n(FPCore (a b angle x-scale y-scale)\n  :name \"a from scale-rotated-ellipse\"\n  (let* ([θ (* (/ angle 180) PI)]\n         [F (* (* b a) (* b (- a)))]\n         [A (/ (/ (+ (pow (* a (sin θ)) 2) (pow (* b (cos θ)) 2))\n                x-scale) x-scale)]\n         [B (/ (/ (* (* (* 2 (- (pow b 2) (pow a 2))) (sin θ)) (cos θ))\n                x-scale) y-scale)]\n         [C (/ (/ (+ (pow (* a (cos θ)) 2) (pow (* b (sin θ)) 2))\n                y-scale) y-scale)]\n         [B^2-4AC (/ (* 4 F) (pow (* x-scale y-scale) 2))]\n         [q (* (* 2 B^2-4AC) F)]\n         [r (sqrt (+ (pow (- A C) 2) (pow B 2)))])\n        (/ (- (sqrt (* q (+ (+ A C) r))))\n         B^2-4AC)))\n\n(FPCore (a b angle x-scale y-scale)\n  :name \"b from scale-rotated-ellipse\"\n  (let* ([θ (* (/ angle 180) PI)]\n         [F (* (* b a) (* b (- a)))]\n         [A (/ (/ (+ (pow (* a (sin θ)) 2) (pow (* b (cos θ)) 2))\n                x-scale) x-scale)]\n         [B (/ (/ (* (* (* 2 (- (pow b 2) (pow a 2))) (sin θ)) (cos θ))\n                x-scale) y-scale)]\n         [C (/ (/ (+ (pow (* a (cos θ)) 2) (pow (* b (sin θ)) 2))\n                y-scale) y-scale)]\n         [B^2-4AC (/ (* 4 F) (pow (* x-scale y-scale) 2))]\n         [q (* (* 2 B^2-4AC) F)]\n         [r (sqrt (+ (pow (- A C) 2) (pow B 2)))])\n        (/ (- (sqrt (* q (- (+ A C) r))))\n       B^2-4AC)))\n\n\n;; the following 7 are broken-down versions of the three above\n(FPCore (a b angle)\n  :name \"ab-angle->ABCF A\"\n  (+ (pow (* a (sin (* (/ angle 180) PI))) 2) (pow (* b (cos (* (/ angle 180) PI))) 2)))\n\n(FPCore (a b angle)\n  :name \"ab-angle->ABCF B\"\n  (* (* (* 2 (- (pow b 2) (pow a 2))) (sin (* PI (/ angle 180)))) (cos (* PI (/ angle 180)))))\n\n(FPCore (a b angle)\n  :name \"ab-angle->ABCF C\"\n  (+  (pow (* a (cos (* PI (/ angle 180)))) 2) (pow (* b (sin (* PI (/ angle 180)))) 2)))\n\n(FPCore (a b)\n  :name \"ab-angle->ABCF D\"\n  (- (* (* (* a a) b) b)))\n\n\n(FPCore (A B C)\n  :name \"ABCF->ab-angle angle\"\n  (let ([r (sqrt (+ (pow (- A C) 2) (pow B 2)))])\n    (* 180\n      (/ (atan (* (/ 1 B) (- (- C A) r))) PI))))\n\n(FPCore (A B C F)\n  :name \"ABCF->ab-angle a\"\n  (let* ([B2-4AC (- (pow B 2) (* (* 4 A) C))]\n         [q (* 2 (* B2-4AC F))]\n         [r (sqrt (+ (pow (- A C) 2) (pow B 2)))])\n         (/ (- (sqrt (* q (+ (+ A C) r))))\n            B2-4AC)))\n\n\n(FPCore (A B C F)\n  :name \"ABCF->ab-angle b\"\n  (let* ([B2-4AC (- (pow B 2) (* (* 4 A) C))]\n         [q (* 2 (* B2-4AC F))]\n         [r (sqrt (+ (pow (- A C) 2) (pow B 2)))])\n         (/ (- (sqrt (* q (- (+ A C) r))))\n            B2-4AC)))\n\n(FPCore (eh ew t )\n :name \"Example from Robby\"\n (let ([t1 (atan (/ (/ eh ew) (tan t)))])\n  (fabs (+ (* (* ew (sin t)) (cos t1)) (* (* eh (cos t)) (sin t1))))))\n\n(FPCore (eh ew t)\n  :name \"Example 2 from Robby\"\n  (let ([t2 (atan (/ (* (- eh) (tan t)) ew))])\n    (fabs (- (* (* ew (cos t)) (cos t2)) (* (* eh (sin t)) (sin t2))))))\n  \n"
  },
  {
    "path": "bench/mathematics/hyperbolic-functions.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (x)\n :name \"Hyperbolic sine\"\n (/ (- (exp x) (exp (- x))) 2))\n\n(FPCore (x)\n :name \"Hyperbolic tangent\"\n (/ (- (exp x) (exp (- x))) (+ (exp x) (exp (- x)))))\n\n(FPCore (x)\n :name \"Hyperbolic secant\"\n (/ 2 (+ (exp x) (exp (- x)))))\n\n(FPCore (x)\n :name \"Hyperbolic arcsine\"\n :alt \n (! :herbie-platform c\n  (if (< x 0)\n   (log (/ -1 (- x (sqrt (+ (* x x) 1)))))\n   (log (+ x (sqrt (+ (* x x) 1))))))\n   \n (log (+ x (sqrt (+ (* x x) 1)))))\n\n(FPCore (x)\n :name \"Hyperbolic arc-cosine\"\n (log (+ x (sqrt (- (* x x) 1)))))\n\n(FPCore (x)\n :name \"Hyperbolic arc-(co)tangent\"\n (* (/ 1 2) (log (/ (+ 1 x) (- 1 x)))))\n\n(FPCore (x)\n :name \"Hyperbolic arc-(co)secant\"\n (log (+ (/ 1 x) (/ (sqrt (- 1 (* x x))) x))))\n"
  },
  {
    "path": "bench/mathematics/latlong.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (R lambda1 lambda2 phi1 phi2)\n :name \"Distance on a great circle\"\n (let ((dlambda (- lambda1 lambda2)))\n   (let ((dphi (- phi1 phi2)))\n     (let ((a\n            (+\n             (pow (sin (/ dphi 2)) 2)\n             (* (* (*\n              (cos phi1)\n              (cos phi2))\n              (sin (/ dlambda 2)))\n              (sin (/ dlambda 2))))))\n       (let ((c (* 2 (atan2 (sqrt a) (sqrt (- 1 a))))))\n         (let ((d (* R c)))\n           d))))))\n\n(FPCore (R lambda1 lambda2 phi1 phi2)\n :name \"Spherical law of cosines\"\n (* (acos (+ (* (sin phi1) (sin phi2))\n             (* (* (cos phi1) (cos phi2)) (cos (- lambda1 lambda2))))) R))\n\n(FPCore (R lambda1 lambda2 phi1 phi2)\n :name \"Equirectangular approximation to distance on a great circle\"\n (let ((x (* (- lambda1 lambda2) (cos (/ (+ phi1 phi2) 2)))))\n   (let ((y (- phi1 phi2)))\n     (let ((d (* R (sqrt (+ (* x x) (* y y))))))\n       d))))\n\n(FPCore (lambda1 lambda2 phi1 phi2)\n :name \"Bearing on a great circle\"\n (atan2\n  (* (sin (- lambda1 lambda2)) (cos phi2))\n  (-\n   (* (cos phi1) (sin phi2))\n   (* (* (sin phi1) (cos phi2)) (cos (- lambda1 lambda2))))))\n\n(FPCore (lambda1 lambda2 phi1 phi2)\n :name \"Midpoint on a great circle\"\n (let ((dlambda (- lambda1 lambda2)))\n   (let ((Bx (* (cos phi2) (cos dlambda))) (By (* (cos phi2) (sin dlambda))))\n     (let ((phim\n            (atan2\n             (+ (sin phi1) (sin phi2))\n             (sqrt (+ (pow (+ (cos phi1) Bx) 2) (* By By)))))\n           (lambdam (+ lambda1 (atan2 By (+ (cos phi1) Bx)))))\n       lambdam))))\n\n;; TODO: phi2 unused\n(FPCore (lambda1 phi1 phi2 delta theta)\n :name \"Destination given bearing on a great circle\"\n (let ((phi2\n        (asin\n         (+\n          (* (sin phi1) (cos delta))\n          (* (* (cos phi1) (sin delta)) (cos theta))))))\n   (let ((lambda2\n          (+\n           lambda1\n           (atan2\n            (* (* (sin theta) (sin delta)) (cos phi1))\n            (- (cos delta) (* (sin phi1) (sin phi2)))))))\n     lambda2)))\n"
  },
  {
    "path": "bench/mathematics/logistic-regression.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (x y)\n :name \"Logistic regression 2\"\n :alt \n (! :herbie-platform c\n  (if (<= x 0)\n   (- (log (+ 1 (exp x))) (* x y))\n   (- (log (+ 1 (exp (- x)))) (* (- x) (- 1 y)))))\n   \n (- (log (+ 1 (exp x))) (* x y)))\n\n(FPCore (x)\n :name \"Logistic function from Lakshay Garg\"\n (- (/ 2 (+ 1 (exp (* -2 x)))) 1))\n"
  },
  {
    "path": "bench/mathematics/sarnoff.fpcore",
    "content": ";; From Jeffrey Sarnoff <jeffrey.sarnoff@gmail.com>\n\n(FPCore (a b c)\n  :name \"Quadratic roots, full range\"\n  (/ (+ (- b) (sqrt (- (* b b) (* (* 4 a) c)))) (* 2 a)))\n\n(FPCore (a b c)\n  :name \"Quadratic roots, narrow range\"\n  :pre (and (< 1.0536712127723509e-8 a 9.490626562425156e7)\n            (< 1.0536712127723509e-8 b 9.490626562425156e7)\n            (< 1.0536712127723509e-8 c 9.490626562425156e7))\n  (/ (+ (- b) (sqrt (- (* b b) (* (* 4 a) c)))) (* 2 a)))\n\n(FPCore (a b c)\n  :name \"Quadratic roots, medium range\"\n  :pre (and (< 1.1102230246251565e-16 a 9.007199254740992e15)\n            (< 1.1102230246251565e-16 b 9.007199254740992e15)\n            (< 1.1102230246251565e-16 c 9.007199254740992e15))\n  (/ (+ (- b) (sqrt (- (* b b) (* (* 4 a) c)))) (* 2 a)))\n\n(FPCore (a b c)\n  :name \"Quadratic roots, wide range\"\n  :pre (and (< 4.930380657631324e-32 a 2.028240960365167e31)\n            (< 4.930380657631324e-32 b 2.028240960365167e31)\n            (< 4.930380657631324e-32 c 2.028240960365167e31))\n  (/ (+ (- b) (sqrt (- (* b b) (* (* 4 a) c)))) (* 2 a)))\n\n(FPCore (a b c)\n  :name \"Cubic critical\"\n  (/ (+ (- b) (sqrt (- (* b b) (* (* 3 a) c)))) (* 3 a)))\n\n(FPCore (a b c)\n  :name \"Cubic critical, narrow range\"\n  :pre (and (< 1.0536712127723509e-8 a 9.490626562425156e7)\n            (< 1.0536712127723509e-8 b 9.490626562425156e7)\n            (< 1.0536712127723509e-8 c 9.490626562425156e7))\n  (/ (+ (- b) (sqrt (- (* b b) (* (* 3 a) c)))) (* 3 a)))\n\n(FPCore (a b c)\n  :name \"Cubic critical, medium range\"\n  :pre (and (< 1.1102230246251565e-16 a 9.007199254740992e15)\n            (< 1.1102230246251565e-16 b 9.007199254740992e15)\n            (< 1.1102230246251565e-16 c 9.007199254740992e15))\n  (/ (+ (- b) (sqrt (- (* b b) (* (* 3 a) c)))) (* 3 a)))\n\n(FPCore (a b c)\n  :name \"Cubic critical, wide range\"\n  :pre (and (< 4.930380657631324e-32 a 2.028240960365167e31)\n            (< 4.930380657631324e-32 b 2.028240960365167e31)\n            (< 4.930380657631324e-32 c 2.028240960365167e31))\n  (/ (+ (- b) (sqrt (- (* b b) (* (* 3 a) c)))) (* 3 a)))\n\n(FPCore (x)\n  :name \"Asymptote A\" (- (/ 1 (+ x 1)) (/ 1 (- x 1))))\n(FPCore (x)\n  :name \"Asymptote B\" (+ (/ 1 (- x 1)) (/ x (+ x 1))))\n(FPCore (x)\n  :name \"Asymptote C\" (- (/ x (+ x 1)) (/ (+ x 1) (- x 1))))\n\n(FPCore (a b)\n  :name \"Eccentricity of an ellipse\"\n  :pre (<= 0 b a 1)\n  (sqrt (fabs (/ (- (* a a) (* b b)) (* a a)))))\n\n(FPCore (e v)\n  :name \"Trigonometry A\"\n  :pre (<= 0 e 1)\n  (/ (* e (sin v)) (+ 1 (* e (cos v)))))\n\n(FPCore (x)\n  :name \"Trigonometry B\"\n  (/ (- 1 (* (tan x) (tan x))) (+ 1 (* (tan x) (tan x)))))\n"
  },
  {
    "path": "bench/mathematics/statistics.fpcore",
    "content": "\n(FPCore (g h a)\n  :name \"2-ancestry mixing, positive discriminant\"\n  (+ (cbrt (* (/ 1 (* 2 a)) (+ (- g) (sqrt (- (* g g) (* h h))))))\n     (cbrt (* (/ 1 (* 2 a)) (- (- g) (sqrt (- (* g g) (* h h))))))))\n\n(FPCore (g a)\n  :name \"2-ancestry mixing, zero discriminant\"\n  (cbrt (/ g (* 2 a))))\n\n(FPCore (g h)\n  :name \"2-ancestry mixing, negative discriminant\"\n  (* 2 (cos (+ (/ (* 2 PI) 3) (/ (acos (/ (- g) h)) 3)))))\n"
  },
  {
    "path": "bench/mathematics/symmetry.fpcore",
    "content": "(FPCore (a b)\n  :name \"symmetry log of sum of exp\"\n  (log (+ (exp a) (exp b))))\n"
  },
  {
    "path": "bench/mathematics/xkcd-expr.fpcore",
    "content": "(FPCore ()\n  :name \"xkcd217 (a numerical coincidence)\"\n  :precision binary64\n  (- 20 (- (exp PI) PI)))\n"
  },
  {
    "path": "bench/numerics/conte.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (x)\n  :name \"ENA, Section 1.4, Mentioned, A\"\n  :cite (conte-et-al-1980)\n  :pre (<= -0.01 x 0.01)\n  :alt \n  (! :herbie-platform c\n   (/ (* (sin x) (sin x)) (+ 1 (cos x))))\n\n  (- 1 (cos x)))\n\n(FPCore (x)\n  :name \"ENA, Section 1.4, Mentioned, B\"\n  :cite (conte-et-al-1980)\n  :pre (<= 0.999 x 1.001)\n  (/ 10 (- 1 (* x x))))\n\n(FPCore (x)\n  :name \"ENA, Section 1.4, Exercise 4a\"\n  :cite (conte-et-al-1980)\n  :pre (<= -1 x 1)\n  :alt \n  (! :herbie-platform c\n   (* 1/6 (* x x)))\n\n  (/ (- x (sin x)) (tan x)))\n\n(FPCore (x)\n  :name \"ENA, Section 1.4, Exercise 1\"\n  :cite (conte-et-al-1980)\n  :pre (<= 1.99 x 2.01)\n  (* (cos x) (exp (* 10 (* x x)))))\n\n(FPCore (x eps)\n  :name \"ENA, Section 1.4, Exercise 4b, n=2\"\n  :cite (conte-et-al-1980)\n  :pre (and (<= -1e9 x 1e9) (<= -1 eps 1))\n  (- (pow (+ x eps) 2) (pow x 2)))\n\n(FPCore (x eps)\n  :name \"ENA, Section 1.4, Exercise 4b, n=5\"\n  :cite (conte-et-al-1980)\n  :pre (and (<= -1e9 x 1e9) (<= -1 eps 1))\n  (- (pow (+ x eps) 5) (pow x 5)))\n\n(FPCore (x eps)\n  :name \"ENA, Section 1.4, Exercise 4d\"\n  :cite (conte-et-al-1980)\n  :pre (and (<= 0 x 1e9) (<= -1 eps 1))\n  :alt \n  (! :herbie-platform c\n    (/ eps (+ x (sqrt (- (* x x) eps)))))\n    \n  (- x (sqrt (- (* x x) eps))))\n"
  },
  {
    "path": "bench/numerics/every-cs.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (a b c)\n :name \"The quadratic formula (r1)\"\n :alt \n (! :herbie-platform c\n  (let ((d (- (* b b) (* (* 4 a) c))))\n   (let ((r1 (/ (+ (- b) (sqrt d)) (* 2 a))))\n     (let ((r2 (/ (- (- b) (sqrt d)) (* 2 a))))\n       (if (< b 0) r1 (/ c (* a r2)))))))\n\n (let ((d (- (* b b) (* (* 4 a) c))))\n   (/ (+ (- b) (sqrt d)) (* 2 a))))\n\n(FPCore (a b c)\n :name \"The quadratic formula (r2)\"\n :alt \n (! :herbie-platform c\n  (let ((d (sqrt (- (* b b) (* 4 (* a c))))))\n   (let ((r1 (/ (+ (- b) d) (* 2 a))))\n     (let ((r2 (/ (- (- b) d) (* 2 a)))) (if (< b 0) (/ c (* a r1)) r2)))))\n\n (let ((d (sqrt (- (* b b) (* 4 (* a c))))))\n   (/ (- (- b) d) (* 2 a))))\n\n(FPCore (a b)\n :name \"Difference of squares\"\n :alt \n (! :herbie-platform c\n  (* (+ a b) (- a b)))\n\n (- (* a a) (* b b)))\n\n(FPCore (a b c)\n :name \"Area of a triangle\"\n :pre (and (< 0 a (+ b c)) (< 0 b (+ a c)) (< 0 c (+ a b)))\n :alt \n (! :herbie-platform c\n  (/ (sqrt (* (+ a (+ b c)) (- c (- a b)) (+ c (- a b)) (+ a (- b c)))) 4))\n\n (let ((s (/ (+ (+ a b) c) 2)))\n   (sqrt (* (* (* s (- s a)) (- s b)) (- s c)))))\n\n(FPCore (x)\n :name \"ln(1 + x)\"\n :alt \n (! :herbie-platform c\n  (if (== (+ 1 x) 1) x (/ (* x (log (+ 1 x))) (- (+ 1 x) 1))))\n\n (log (+ 1 x)))\n\n(FPCore (i n)\n :name \"Compound Interest\"\n :alt \n (! :herbie-platform c\n  (let ((lnbase\n        (if (== (+ 1 (/ i n)) 1)\n          (/ i n)\n          (/ (* (/ i n) (log (+ 1 (/ i n)))) (- (+ (/ i n) 1) 1)))))\n   (* 100 (/ (- (exp (* n lnbase)) 1) (/ i n)))))\n\n (* 100 (/ (- (pow (+ 1 (/ i n)) n) 1) (/ i n))))\n\n(FPCore (x)\n :name \"x / (x^2 + 1)\"\n :alt \n (! :herbie-platform c\n  (/ 1 (+ x (/ 1 x))))\n\n (/ x (+ (* x x) 1)))\n\n(FPCore (a b c d)\n :name \"Complex division, real part\"\n :alt \n (! :herbie-platform c\n  (if (< (fabs d) (fabs c))\n    (/ (+ a (* b (/ d c))) (+ c (* d (/ d c))))\n    (/ (+ b (* a (/ c d))) (+ d (* c (/ c d))))))\n\n (/ (+ (* a c) (* b d)) (+ (* c c) (* d d))))\n\n(FPCore (a b c d)\n :name \"Complex division, imag part\"\n :alt \n (! :herbie-platform c\n  (if (< (fabs d) (fabs c))\n    (/ (- b (* a (/ d c))) (+ c (* d (/ d c))))\n    (/ (+ (- a) (* b (/ c d))) (+ d (* c (/ c d))))))\n\n (/ (- (* b c) (* a d)) (+ (* c c) (* d d))))\n\n(FPCore (x)\n :name \"arccos\"\n (* 2 (atan (sqrt (/ (- 1 x) (+ 1 x))))))\n"
  },
  {
    "path": "bench/numerics/fma.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (t)\n :name \"fma_test1\"\n :pre (<= 0.9 t 1.1)\n :alt \n (! :herbie-platform c\n  (let ([x (+ 1 (* t 2e-16))]\n       [z (- -1 (* 2 (* t 2e-16)))])\n   (fma x x z)))\n\n (let ([x (+ 1 (* t 2e-16))]\n       [z (- -1 (* 2 (* t 2e-16)))])\n   (+ (* x x) z)))\n\n(FPCore (t)\n :name \"fma_test2\"\n :pre (<= 1.9 t 2.1)\n :alt \n (! :herbie-platform c\n  (let ([x 1.7e308])\n   (fma x t (- x))))\n   \n (let ([x 1.7e308])\n   (- (* x t) x)))\n"
  },
  {
    "path": "bench/numerics/great-debate.fpcore",
    "content": "(FPCore (y)\n  :name \"Kahan's Monster\"\n  :pre (<= 1 y 9999) ; Integers only in Kahan's example but this is not essential\n  (let ([Qx (- (fabs (- y (sqrt (+ (* y y) 1))))\n               (/ 1  (+ y (sqrt (+ (* y y) 1)))))])\n    (let ([z (* Qx Qx)])\n      (if (== z 0) 1 (/ (- (exp z) 1) z)))))\n\n(FPCore (y)\n  :name \"Kahan's Unum-Targeted Monster\"\n  :pre (<= 1 y 9999) ; Integers only in Kahan's example but this is not essential\n  (let ([Qx (- (fabs (- y (sqrt (+ (* y y) 1)))) (/ 1 (+ y (sqrt (+ (* y y) 1)))))])\n    (let ([z (+ (* Qx Qx) (pow (pow 10 -300) (* 10000 (+ y 1))))])\n      (if (== z 0) 1 (/ (- (exp z) 1) z)))))\n\n(FPCore (x y)\n  :name \"Kahan p9 Example\"\n  :pre (and (< 0 x 1) (< y 1))\n  :alt \n  (! :herbie-platform c\n   (if (< 0.5 (fabs (/ x y)) 2)\n      (/ (* (- x y) (+ x y)) (+ (* x x) (* y y)))\n      (- 1 (/ 2 (+ 1 (* (/ x y) (/ x y)))))))\n\n  (/ (* (- x y) (+ x y)) (+ (* x x) (* y y))))\n\n(FPCore (t)\n  :name \"Kahan p13 Example 1\"\n  (let ([u (/ (* 2 t) (+ 1 t))])\n    (/ (+ 1 (* u u)) (+ 2 (* u u)))))\n\n(FPCore (t)\n  :name \"Kahan p13 Example 2\"\n  (let ([v (- 2 (/ (/ 2 t) (+ 1 (/ 1 t))))])\n    (/ (+ 1 (* v v)) (+ 2 (* v v)))))\n\n(FPCore (t)\n  :name \"Kahan p13 Example 3\"\n  (let ([v (- 2 (/ (/ 2 t) (+ 1 (/ 1 t))))])\n    (- 1 (/ 1 (+ 2 (* v v))))))\n"
  },
  {
    "path": "bench/numerics/hamming-misc.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (x eps)\n :name \"NMSE Section 6.1 mentioned, A\"\n (/\n  (-\n   (* (+ 1 (/ 1 eps)) (exp (- (* (- 1 eps) x))))\n   (* (- (/ 1 eps) 1) (exp (- (* (+ 1 eps) x)))))\n  2))\n\n(FPCore (a b)\n :name \"NMSE Section 6.1 mentioned, B\"\n (* (* (/ PI 2) (/ 1 (- (* b b) (* a a)))) (- (/ 1 a) (/ 1 b))))\n\n(FPCore (x y)\n :name \"Radioactive exchange between two surfaces\"\n (- (pow x 4) (pow y 4)))\n"
  },
  {
    "path": "bench/numerics/kahan.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (x)\n :name \"Kahan's exp quotient\"\n :alt \n (! :herbie-platform c\n  (if (and (< x 1) (> x -1))\n   (/ (- (exp x) 1) (log (exp x)))\n   (/ (- (exp x) 1) x)))\n   \n (/ (- (exp x) 1) x))\n"
  },
  {
    "path": "bench/numerics/libm.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (x y z)\n :name \"simple fma test\"\n :alt \n (! :herbie-platform c -1)\n\n (- (fma x y z) (+ 1 (+ (* x y) z))))\n\n(FPCore (x)\n  :name \"find-atanh\"\n  :alt (* 2 (atanh x))\n  (log (/ (+ 1 x) (- 1 x))))\n"
  },
  {
    "path": "bench/numerics/martel.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore ()\n :name \"Rectangular parallelepiped of dimension a×b×c\"\n :alt \n (! :herbie-platform c\n  (let ([d 2] [a 1] [b (/ 1 9)] [c (/ 1 9)])\n   (+ (+ (* (* c a) d) (* d (* b c))) (* d (* a b)))))\n   \n (let ([d 2] [a 1] [b (/ 1 9)] [c (/ 1 9)])\n   (* d (+ (+ (* a b) (* b c)) (* c a)))))\n\n(FPCore (a b c d)\n :pre (and (<= 56789 a 98765) (<= 0 b 1) (<= 0 c 0.0016773) (<= 0 d 0.0016773))\n :name \"Expression, p14\"\n :alt \n (! :herbie-platform c\n  (+ (* a b) (* a (+ c d))))\n\n (* a (+ (+ b c) d)))\n\n(FPCore (a b c d e)\n :pre (<= 1 a 2 b 4 c 8 d 16 e 32)\n :name \"Expression 1, p15\"\n :alt \n (! :herbie-platform c\n  (+ (+ d (+ c (+ a b))) e))\n\n (+ (+ (+ (+ e d) c) b) a))\n\n(FPCore (x)\n :pre (<= 0 x 2)\n :name \"Expression 2, p15\"\n :alt \n (! :herbie-platform c\n  (* (+ 1.0 x) x))\n\n (+ x (* x x)))\n\n(FPCore (x)\n :pre (<= 0  x 2)\n :name \"Expression 3, p15\"\n :alt \n (! :herbie-platform c\n  (* (* (+ 1.0 x) x) x))\n\n (+ (* x (* x x)) (* x x)))\n\n(FPCore (a b)\n :pre (and (<= 5 a 10) (<= 0 b 0.001))\n :name \"Expression 4, p15\"\n :alt \n (! :herbie-platform c\n  (+ (+ (+ (* b a) (* b b)) (* b a)) (* a a)))\n\n (* (+ a b) (+ a b)))\n\n(FPCore (a b c d)\n :pre (and (<= -14 a -13) (<= -3 b -2) (<= 3 c 3.5) (<= 12.5 d 13.5))\n :name \"Expression, p6\"\n :alt \n (! :herbie-platform c\n  (let ((e 2)) (+ (* (+ a b) e) (* (+ c d) e))))\n  \n (let ((e 2)) (* (+ a (+ b (+ c d))) e)))\n"
  },
  {
    "path": "bench/numerics/polynomial-cancellation.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore ()\n :name \"From Warwick Tucker's Validated Numerics\"\n (let ([x 77617] [y 33096])\n   (+ (+ (+\n    (* 333.75 (pow y 6))\n    (* (* x x) (+ (+ (+ (* (* 11 (* x x)) (* y y)) (- (pow y 6))) (* -121 (pow y 4))) -2)))\n    (* 5.5 (pow y 8)))\n    (/ x (* 2 y)))))\n"
  },
  {
    "path": "bench/numerics/rosa.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (u v t1)\n :name \"Rosa's DopplerBench\"\n (/ (* (- t1) v) (* (+ t1 u) (+ t1 u))))\n\n(FPCore (x)\n :name \"Rosa's Benchmark\"\n (- (* 0.954929658551372 x) (* 0.12900613773279798 (* (* x x) x))))\n\n(FPCore (x1 x2)\n :name \"Rosa's FloatVsDoubleBenchmark\"\n (let ((t (- (+ (* (* 3 x1) x1) (* 2 x2)) x1))\n       (t* (- (- (* (* 3 x1) x1) (* 2 x2)) x1))\n       (d (+ (* x1 x1) 1)))\n   (let ((s (/ t d)) (s* (/ t* d)))\n     (+ x1\n        (+\n         (* (+ (* (* 2 x1) s (- s 3)) (* (* x1 x1) (- (* 4 s) 6))) d)\n         (* 3 x1 x1 s)\n         (* x1 x1 x1)\n         x1\n         (* 3 s*))))))\n\n(FPCore (v w r)\n :name \"Rosa's TurbineBenchmark\"\n (- (+ 3 (/ 2 (* r r))) (/ (* 0.125 (- 3 (* 2 v)) (* w w r r)) (- 1 v)) 4.5))\n"
  },
  {
    "path": "bench/numerics/rump.fpcore",
    "content": "(FPCore (x y)\n  :name \"Rump's expression from Stadtherr's award speech\"\n  :pre (and (== x 77617) (== y 33096))\n  :spec -54767/66192\n  (+ (+ (+ (* 333.75 (pow y 6))\n     (* (* x x)\n        (- (- (- (* (* (* (* 11 x) x) y) y)\n           (pow y 6))\n           (* 121 (pow y 4)))\n           2)))\n     (* 5.5 (pow y 8)))\n     (/ x (* 2 y))))\n\n;; From\n;; How Reliable are the Results of Computers\n;; Jahrbuch Uberblicke Mathematik (1983)\n\n(FPCore (x y)\n  :name \"From Rump in a 1983 paper\"\n  :pre (and (== x 10864) (== y 18817))\n  ;:pre (and (< 10500 x 11000) (< 18500 y 19000))\n  (+ (- (* 9 (pow x 4)) (pow y 4)) (* 2 (* y y))))\n\n(FPCore (x y)\n  :name \"From Rump in a 1983 paper, rewritten\"\n  :pre (and (== x 10864) (== y 18817))\n  ;:pre (and (< 10500 x 11000) (< 18500 y 19000))\n  (- (* 9 (pow x 4)) (* (* y y) (- (* y y) 2))))\n"
  },
  {
    "path": "bench/physics/ballistics.fpcore",
    "content": "\n(FPCore (v H)\n  :name \"Optimal throwing angle\"\n  (let ([g 9.8])\n    (atan (/ v (sqrt (- (* v v) (* (* 2 g) H)))))))\n"
  },
  {
    "path": "bench/physics/dimer-escape.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (J K U)\n :name \"Maksimov and Kolovsky, Equation (3)\"\n (* (* (* -2 J) (cos (/ K 2))) (sqrt (+ 1 (pow (/ U (* (* 2 J) (cos (/ K 2)))) 2)))))\n\n(FPCore (J l K U)\n :name \"Maksimov and Kolovsky, Equation (4)\"\n (+ (* (* J (- (exp l) (exp (- l)))) (cos (/ K 2))) U))\n\n(FPCore (K m n M l)\n :name \"Maksimov and Kolovsky, Equation (32)\"\n (*\n  (cos (- (/ (* K (+ m n)) 2) M))\n  (exp (- (- (pow (- (/ (+ m n) 2) M) 2)) (- l (fabs (- m n)))))))\n"
  },
  {
    "path": "bench/physics/gated-magnetic-field.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (NdChar Ec Vef EDonor mu KbT NaChar Ev EAccept)\n :name \"Bulmash initializePoisson\"\n (+\n  (/ NdChar (+ 1 (exp (/ (- (- (- (- Ec Vef) EDonor) mu)) KbT))))\n  (/ NaChar (+ 1 (exp (/ (+ (+ (+ Ev Vef) EAccept) (- mu)) KbT))))))\n"
  },
  {
    "path": "bench/physics/gravitation.fpcore",
    "content": "; -*- mode: scheme -*-\n\n;; Translated from:\n;; https://github.com/sandialabs/elaenia/blob/main/examples/03_vectors/gravitation.c\n;; Original comments cite:\n;; - Ellipsoidal gravity vector source:\n;;   https://www.mathworks.com/matlabcentral/fileexchange/8359-ellipsoidal-gravity-vector/files/xyz2grav.m\n;; - Example ECEF coordinates source:\n;;   https://dominoc925-pages.appspot.com/mapplets/cs_ecef.html\n;; - Constants/provenance in the C example:\n;;   WGS84 Earth gravitational constant and equatorial radius, with J2-only\n;;   ellipsoidal gravity correction (\"gravity anomaly\" terms omitted).\n\n(FPCore norm-3 ((a 3))\n :name \"3D vector norm\"\n :precision binary64\n :pre (and (<= (fabs (ref a 0)) 1e154)\n           (<= (fabs (ref a 1)) 1e154)\n           (<= (fabs (ref a 2)) 1e154))\n (sqrt (+ (* (ref a 0) (ref a 0))\n          (+ (* (ref a 1) (ref a 1))\n             (* (ref a 2) (ref a 2))))))\n\n(FPCore gravitation-ecef ((r_e 3))\n :name \"ECEF gravitation vector\"\n :precision binary64\n :pre (and (<= (fabs (ref r_e 0)) 1e154)\n           (<= (fabs (ref r_e 1)) 1e154)\n           (<= (fabs (ref r_e 2)) 1e154)\n           (< 0 (sqrt (+ (* (ref r_e 0) (ref r_e 0))\n                         (+ (* (ref r_e 1) (ref r_e 1))\n                            (* (ref r_e 2) (ref r_e 2)))))))\n (let* ([MU 3.986004418e14]\n        [R 6378137.0]\n        [J2 0.00108263]\n        [r (sqrt (+ (* (ref r_e 0) (ref r_e 0))\n                    (+ (* (ref r_e 1) (ref r_e 1))\n                       (* (ref r_e 2) (ref r_e 2)))))]\n        [sub1 (* (* 1.5 J2) (/ (* R R) (* r r)))]\n        [sub2 (/ (* (* 5 (ref r_e 2)) (ref r_e 2)) (* r r))]\n        [sub3 (/ (- MU) (* (* r r) r))]\n        [sub4 (* sub3 (- 1 (* sub1 (- sub2 1.0))))])\n   (array (* (ref r_e 0) sub4)\n          (* (ref r_e 1) sub4)\n          (* (* (ref r_e 2) sub3) (- 1 (* sub1 (- sub2 3.0)))))))\n"
  },
  {
    "path": "bench/physics/kalman.fpcore",
    "content": "(FPCore (dt r)\n        :name \"Kalman filter per K\"\n        :pre (and (> dt 0) (> r 0))\n        ; initializing matrices\n        (let ([p00 25.0]\n              [p01 0.0]\n              [p02 0.0]\n              [p10 0.0]\n              [p11 10.0]\n              [p12 0.0]\n              [p20 0.0]\n              [p21 0.0]\n              [p22 1.0]\n        \n              [f00 1.0]\n              [f01 dt]\n              [f02 (* 0.5 (* dt dt))]\n              [f10 0.0]\n              [f11 1.0]\n              [f12 dt]\n              [f20 0.0]\n              [f21 0.0]\n              [f22 1.0]\n        \n              [q00 (* 0.25 (* dt (* dt (* dt dt))))]\n              [q01 (* 0.5 (* dt (* dt dt)))]\n              [q02 (* 0.5 (* dt dt))]\n              [q10 (* 0.5 (* dt (* dt dt)))]\n              [q11 (* dt dt)]\n              [q12 dt]\n              [q20 (* 0.5 (* dt dt))]\n              [q21 dt]\n              [q22 1])\n          ; axbT_33(P, F, P)\n          (let ([p00* (+ (+ (* p00 f00) (* p01 f01)) (* p02 f02))]\n                [p01* (+ (+ (* p00 f10) (* p01 f11)) (* p02 f12))]\n                [p02* (+ (+ (* p00 f20) (* p01 f21)) (* p02 f22))]\n                [p10* (+ (+ (* p10 f00) (* p11 f01)) (* p12 f02))]\n                [p11* (+ (+ (* p10 f10) (* p11 f11)) (* p12 f12))]\n                [p12* (+ (+ (* p10 f20) (* p11 f21)) (* p12 f22))]\n                [p20* (+ (+ (* p20 f00) (* p21 f01)) (* p22 f02))]\n                [p21* (+ (+ (* p20 f10) (* p21 f11)) (* p22 f12))]\n                [p22* (+ (+ (* p20 f20) (* p21 f21)) (* p22 f22))])\n            ; axb_33(F, P, P)\n            (let ([p00** (+ (+ (* f00 p00*) (* f01 p10*)) (* f02 p20*))]\n                  [p01** (+ (+ (* f00 p01*) (* f01 p11*)) (* f02 p21*))]\n                  [p02** (+ (+ (* f00 p02*) (* f01 p12*)) (* f02 p22*))]\n                  [p10** (+ (+ (* f10 p00*) (* f11 p10*)) (* f12 p20*))]\n                  [p11** (+ (+ (* f10 p01*) (* f11 p11*)) (* f12 p21*))]\n                  [p12** (+ (+ (* f10 p02*) (* f11 p12*)) (* f12 p22*))]\n                  [p20** (+ (+ (* f20 p00*) (* f21 p10*)) (* f22 p20*))]\n                  [p21** (+ (+ (* f20 p01*) (* f21 p11*)) (* f22 p21*))]\n                  [p22** (+ (+ (* f20 p02*) (* f21 p12*)) (* f22 p22*))])\n              ; a_add_b_33(P, Q, P)\n              (let ([p00*** (+ p00** q00)]\n                    [p01*** (+ p01** q01)]\n                    [p02*** (+ p02** q02)]\n                    [p10*** (+ p10** q10)]\n                    [p11*** (+ p11** q11)]\n                    [p12*** (+ p12** q12)]\n                    [p20*** (+ p20** q20)]\n                    [p21*** (+ p21** q21)]\n                    [p22*** (+ p22** q22)])\n                ; update_K\n                (let ([K0 (/ p00*** (+ p00*** r))]\n                      [K1 (/ p10*** (+ p00*** r))]\n                      [K2 (/ p20*** (+ p00*** r))])\n                  K0))))))\n                      \n(FPCore (x0 x1 x2 dt r sensor)\n        :name \"Kalman filter per x\"\n        :pre (and (> dt 0) (> r 0) (> sensor 0))\n        ; initializing matrices\n        (let ([p00 25.0]\n              [p01 0.0]\n              [p02 0.0]\n              [p10 0.0]\n              [p11 10.0]\n              [p12 0.0]\n              [p20 0.0]\n              [p21 0.0]\n              [p22 1.0]\n        \n              [f00 1.0]\n              [f01 dt]\n              [f02 (* 0.5 (* dt dt))]\n              [f10 0.0]\n              [f11 1.0]\n              [f12 dt]\n              [f20 0.0]\n              [f21 0.0]\n              [f22 1.0]\n        \n              [q00 (* 0.25 (* dt (* dt (* dt dt))))]\n              [q01 (* 0.5 (* dt (* dt dt)))]\n              [q02 (* 0.5 (* dt dt))]\n              [q10 (* 0.5 (* dt (* dt dt)))]\n              [q11 (* dt dt)]\n              [q12 dt]\n              [q20 (* 0.5 (* dt dt))]\n              [q21 dt]\n              [q22 1])\n          ; axbT_33(P, F, P)\n          (let ([p00* (+ (+ (* p00 f00) (* p01 f01)) (* p02 f02))]\n                [p01* (+ (+ (* p00 f10) (* p01 f11)) (* p02 f12))]\n                [p02* (+ (+ (* p00 f20) (* p01 f21)) (* p02 f22))]\n                [p10* (+ (+ (* p10 f00) (* p11 f01)) (* p12 f02))]\n                [p11* (+ (+ (* p10 f10) (* p11 f11)) (* p12 f12))]\n                [p12* (+ (+ (* p10 f20) (* p11 f21)) (* p12 f22))]\n                [p20* (+ (+ (* p20 f00) (* p21 f01)) (* p22 f02))]\n                [p21* (+ (+ (* p20 f10) (* p21 f11)) (* p22 f12))]\n                [p22* (+ (+ (* p20 f20) (* p21 f21)) (* p22 f22))])\n            ; axb_33(F, P, P)\n            (let ([p00** (+ (+ (* f00 p00*) (* f01 p10*)) (* f02 p20*))]\n                  [p01** (+ (+ (* f00 p01*) (* f01 p11*)) (* f02 p21*))]\n                  [p02** (+ (+ (* f00 p02*) (* f01 p12*)) (* f02 p22*))]\n                  [p10** (+ (+ (* f10 p00*) (* f11 p10*)) (* f12 p20*))]\n                  [p11** (+ (+ (* f10 p01*) (* f11 p11*)) (* f12 p21*))]\n                  [p12** (+ (+ (* f10 p02*) (* f11 p12*)) (* f12 p22*))]\n                  [p20** (+ (+ (* f20 p00*) (* f21 p10*)) (* f22 p20*))]\n                  [p21** (+ (+ (* f20 p01*) (* f21 p11*)) (* f22 p21*))]\n                  [p22** (+ (+ (* f20 p02*) (* f21 p12*)) (* f22 p22*))])\n              ; a_add_b_33(P, Q, P)\n              (let ([p00*** (+ p00** q00)]\n                    [p01*** (+ p01** q01)]\n                    [p02*** (+ p02** q02)]\n                    [p10*** (+ p10** q10)]\n                    [p11*** (+ p11** q11)]\n                    [p12*** (+ p12** q12)]\n                    [p20*** (+ p20** q20)]\n                    [p21*** (+ p21** q21)]\n                    [p22*** (+ p22** q22)])\n                ; update_K\n                (let ([K0 (/ p00*** (+ p00*** r))]\n                      [K1 (/ p10*** (+ p00*** r))]\n                      [K2 (/ p20*** (+ p00*** r))])\n                  ; predict_x\n                  (let ([x0* (+ x0 (+ x1 (* 0.5 (* dt (* dt x2)))))]\n                        [x1* (+ x1 x2)]\n                        [x2* x2])\n                    (let ([y (- sensor x0*)])\n                      ; update_x\n                      (let ([x0** (+ x0* (* K0 y))]\n                            [x1** (+ x1* (* K1 y))]\n                            [x2** (+ x2* (* K2 y))])\n                        x0**)))))))))\n                        \n(FPCore (dt r)\n        :name \"Kalman filter per P\"\n        :pre (and (> dt 0) (> r 0))\n        ; initializing matrices\n        (let ([p00 25.0]\n              [p01 0.0]\n              [p02 0.0]\n              [p10 0.0]\n              [p11 10.0]\n              [p12 0.0]\n              [p20 0.0]\n              [p21 0.0]\n              [p22 1.0]\n        \n              [f00 1.0]\n              [f01 dt]\n              [f02 (* 0.5 (* dt dt))]\n              [f10 0.0]\n              [f11 1.0]\n              [f12 dt]\n              [f20 0.0]\n              [f21 0.0]\n              [f22 1.0]\n        \n              [q00 (* 0.25 (* dt (* dt (* dt dt))))]\n              [q01 (* 0.5 (* dt (* dt dt)))]\n              [q02 (* 0.5 (* dt dt))]\n              [q10 (* 0.5 (* dt (* dt dt)))]\n              [q11 (* dt dt)]\n              [q12 dt]\n              [q20 (* 0.5 (* dt dt))]\n              [q21 dt]\n              [q22 1])\n          ; axbT_33(P, F, P)\n          (let ([p00* (+ (+ (* p00 f00) (* p01 f01)) (* p02 f02))]\n                [p01* (+ (+ (* p00 f10) (* p01 f11)) (* p02 f12))]\n                [p02* (+ (+ (* p00 f20) (* p01 f21)) (* p02 f22))]\n                [p10* (+ (+ (* p10 f00) (* p11 f01)) (* p12 f02))]\n                [p11* (+ (+ (* p10 f10) (* p11 f11)) (* p12 f12))]\n                [p12* (+ (+ (* p10 f20) (* p11 f21)) (* p12 f22))]\n                [p20* (+ (+ (* p20 f00) (* p21 f01)) (* p22 f02))]\n                [p21* (+ (+ (* p20 f10) (* p21 f11)) (* p22 f12))]\n                [p22* (+ (+ (* p20 f20) (* p21 f21)) (* p22 f22))])\n            ; axb_33(F, P, P)\n            (let ([p00** (+ (+ (* f00 p00*) (* f01 p10*)) (* f02 p20*))]\n                  [p01** (+ (+ (* f00 p01*) (* f01 p11*)) (* f02 p21*))]\n                  [p02** (+ (+ (* f00 p02*) (* f01 p12*)) (* f02 p22*))]\n                  [p10** (+ (+ (* f10 p00*) (* f11 p10*)) (* f12 p20*))]\n                  [p11** (+ (+ (* f10 p01*) (* f11 p11*)) (* f12 p21*))]\n                  [p12** (+ (+ (* f10 p02*) (* f11 p12*)) (* f12 p22*))]\n                  [p20** (+ (+ (* f20 p00*) (* f21 p10*)) (* f22 p20*))]\n                  [p21** (+ (+ (* f20 p01*) (* f21 p11*)) (* f22 p21*))]\n                  [p22** (+ (+ (* f20 p02*) (* f21 p12*)) (* f22 p22*))])\n              ; a_add_b_33(P, Q, P)\n              (let ([p00*** (+ p00** q00)]\n                    [p01*** (+ p01** q01)]\n                    [p02*** (+ p02** q02)]\n                    [p10*** (+ p10** q10)]\n                    [p11*** (+ p11** q11)]\n                    [p12*** (+ p12** q12)]\n                    [p20*** (+ p20** q20)]\n                    [p21*** (+ p21** q21)]\n                    [p22*** (+ p22** q22)])\n                ; update_K\n                (let ([K0 (/ p00*** (+ p00*** r))]\n                      [K1 (/ p10*** (+ p00*** r))]\n                      [K2 (/ p20*** (+ p00*** r))])\n                  ; update_P\n                  (let ([eyekh00 (- 1 K0)]\n                        [eyekh01 0.0]\n                        [eyekh02 0.0]\n                        [eyekh10 (- K1)]\n                        [eyekh11 1.0]\n                        [eyekh12 0.0]\n                        [eyekh20 (- K2)]\n                        [eyekh21 0.0]\n                        [eyekh22 1.0])\n                    ; axb_33(&eyekh, P, P)\n                    (let ([p00**** (+ (+ (* eyekh00 p00***) (* eyekh01 p10***)) (* eyekh02 p20***))]\n                          [p01**** (+ (+ (* eyekh00 p01***) (* eyekh01 p11***)) (* eyekh02 p21***))]\n                          [p02**** (+ (+ (* eyekh00 p02***) (* eyekh01 p12***)) (* eyekh02 p22***))]\n                          [p10**** (+ (+ (* eyekh10 p00***) (* eyekh11 p10***)) (* eyekh12 p20***))]\n                          [p11**** (+ (+ (* eyekh10 p01***) (* eyekh11 p11***)) (* eyekh12 p21***))]\n                          [p12**** (+ (+ (* eyekh10 p02***) (* eyekh11 p12***)) (* eyekh12 p22***))]\n                          [p20**** (+ (+ (* eyekh20 p00***) (* eyekh21 p10***)) (* eyekh22 p20***))]\n                          [p21**** (+ (+ (* eyekh20 p01***) (* eyekh21 p11***)) (* eyekh22 p21***))]\n                          [p22**** (+ (+ (* eyekh20 p02***) (* eyekh21 p12***)) (* eyekh22 p22***))])\n                      p00****))))))))\n"
  },
  {
    "path": "bench/physics/multiphoton-states.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (k n)\n :name \"Migdal et al, Equation (51)\"\n (* (/ 1 (sqrt k)) (pow (* (* 2 PI) n) (/ (- 1 k) 2))))\n\n(FPCore (a1 a2 th)\n :name \"Migdal et al, Equation (64)\"\n (+ (* (/ (cos th) (sqrt 2)) (* a1 a1)) (* (/ (cos th) (sqrt 2)) (* a2 a2))))\n"
  },
  {
    "path": "bench/physics/quantum-walk.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (v t)\n :name \"Falkner and Boettcher, Equation (20:1,3)\"\n (/\n  (- 1 (* 5 (* v v)))\n  (* (* (* PI t) (sqrt (* 2 (- 1 (* 3 (* v v)))))) (- 1 (* v v)))))\n\n(FPCore (v)\n :name \"Falkner and Boettcher, Equation (22+)\"\n (/ 4 (* (* (* 3 PI) (- 1 (* v v))) (sqrt (- 2 (* 6 (* v v)))))))\n\n(FPCore (a k m)\n :name \"Falkner and Boettcher, Appendix A\"\n (/ (* a (pow k m)) (+ (+ 1 (* 10 k)) (* k k))))\n\n(FPCore (v)\n :name \"Falkner and Boettcher, Appendix B, 1\"\n (acos (/ (- 1 (* 5 (* v v))) (- (* v v) 1))))\n\n(FPCore (v)\n :name \"Falkner and Boettcher, Appendix B, 2\"\n (* (* (/ (sqrt 2) 4) (sqrt (- 1 (* 3 (* v v))))) (- 1 (* v v))))\n"
  },
  {
    "path": "bench/physics/sidey.fpcore",
    "content": ";; Code courtesy of Sidey P. Timmins of NASA\n\n;; In the original, x was (- q r)\n(FPCore (p x)\n  :name \"Given's Rotation SVD example\"\n  :pre (< 1e-150 (fabs x) 1e150)\n  :alt \n  (! :herbie-platform c\n   (sqrt (+ 1/2 (/ (copysign 1/2 x) (hypot 1 (/ (* 2 p) x))))))\n\n  (sqrt (* 0.5 (+ 1 (/ x (sqrt (+ (* (* 4 p) p) (* x x))))))))\n\n;; Here, I'm doing (1 - the above), and x here is (2p / x)\n(FPCore (x)\n  :name \"Given's Rotation SVD example, simplified\"\n  (- 1 (sqrt (* 1/2 (+ 1 (/ 1 (hypot 1 x)))))))\n"
  },
  {
    "path": "bench/physics/superfluidity-breakdown.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (t l Om Omc)\n :name \"Toniolo and Linder, Equation (2)\"\n (asin (sqrt (/ (- 1 (pow (/ Om Omc) 2)) (+ 1 (* 2 (pow (/ t l) 2)))))))\n\n(FPCore (l Om kx ky)\n :name \"Toniolo and Linder, Equation (3a)\"\n (sqrt\n  (*\n   (/ 1 2)\n   (+\n    1\n    (/\n     1\n     (sqrt\n      (+ 1 (* (pow (/ (* 2 l) Om) 2) (+ (pow (sin kx) 2) (pow (sin ky) 2))))))))))\n\n(FPCore (kx ky th)\n :name \"Toniolo and Linder, Equation (3b), real\"\n (* (/ (sin ky) (sqrt (+ (pow (sin kx) 2) (pow (sin ky) 2)))) (sin th)))\n\n(FPCore (x l t)\n :name \"Toniolo and Linder, Equation (7)\"\n (/\n  (* (sqrt 2) t)\n  (sqrt (- (* (/ (+ x 1) (- x 1)) (+ (* l l) (* 2 (* t t)))) (* l l)))))\n\n(FPCore (t l k)\n :name \"Toniolo and Linder, Equation (10+)\"\n (/ 2 (* (* (* (/ (pow t 3) (* l l)) (sin k)) (tan k)) (+ (+ 1 (pow (/ k t) 2)) 1))))\n\n(FPCore (t l k)\n :name \"Toniolo and Linder, Equation (10-)\"\n (/ 2 (* (* (* (/ (pow t 3) (* l l)) (sin k)) (tan k)) (- (+ 1 (pow (/ k t) 2)) 1))))\n\n(FPCore (n U t l Om U*)\n :name \"Toniolo and Linder, Equation (13)\"\n (sqrt (* (* (* 2 n) U) (- (- t (* 2 (/ (* l l) Om))) (* (* n (pow (/ l Om) 2)) (- U U*))))))\n"
  },
  {
    "path": "bench/physics/tea-flows.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (F l)\n :name \"VandenBroeck and Keller, Equation (6)\"\n (- (* PI l) (* (/ 1 (* F F)) (tan (* PI l)))))\n\n(FPCore (f)\n :name \"VandenBroeck and Keller, Equation (20)\"\n (let ((PI/4 (/ PI 4)))\n   (let ((exp+ (exp (* PI/4 f))))\n     (let ((exp- (exp (- (* PI/4 f)))))\n       (- (* (/ 1 PI/4) (log (/ (+ exp+ exp-) (- exp+ exp-)))))))))\n\n(FPCore (F B x)\n :name \"VandenBroeck and Keller, Equation (23)\"\n (+\n  (- (* x (/ 1 (tan B))))\n  (* (/ F (sin B)) (pow (+ (+ (* F F) 2) (* 2 x)) (- (/ 1 2))))))\n\n(FPCore (B x)\n :name \"VandenBroeck and Keller, Equation (24)\"\n (+ (- (* x (/ 1 (tan B)))) (/ 1 (sin B))))\n"
  },
  {
    "path": "bench/physics/tea-whistle.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (c0 A V l)\n :name \"Henrywood and Agarwal, Equation (3)\"\n (* c0 (sqrt (/ A (* V l)))))\n\n(FPCore (w0 M D h l d)\n :name \"Henrywood and Agarwal, Equation (9a)\"\n (* w0 (sqrt (- 1 (* (pow (/ (* M D) (* 2 d)) 2) (/ h l))))))\n\n(FPCore (d h l M D)\n :name \"Henrywood and Agarwal, Equation (12)\"\n (* (*\n  (pow (/ d h) (/ 1 2))\n  (pow (/ d l) (/ 1 2)))\n  (- 1 (* (* (/ 1 2) (pow (/ (* M D) (* 2 d)) 2)) (/ h l)))))\n\n(FPCore (c0 w h D d M)\n :name \"Henrywood and Agarwal, Equation (13)\"\n (let ((x (/ (* c0 (* d d)) (* (* w h) (* D D)))))\n   (* (/ c0 (* 2 w)) (+ x (sqrt (- (* x x) (* M M)))))))\n"
  },
  {
    "path": "bench/physics/universal-linear-optics.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (a b)\n :name \"Bouland and Aaronson, Equation (24)\"\n (-\n  (+\n   (pow (+ (* a a) (* b b)) 2)\n   (* 4 (+ (* (* a a) (- 1 a)) (* (* b b) (+ 3 a)))))\n  1))\n\n(FPCore (a b)\n :name \"Bouland and Aaronson, Equation (25)\"\n (-\n  (+\n   (pow (+ (* a a) (* b b)) 2)\n   (* 4 (+ (* (* a a) (+ 1 a)) (* (* b b) (- 1 (* 3 a))))))\n  1))\n\n(FPCore (a b)\n :name \"Bouland and Aaronson, Equation (26)\"\n (- (+ (pow (+ (* a a) (* b b)) 2) (* 4 (* b b))) 1))\n"
  },
  {
    "path": "bench/proj/krovak.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (phi0 es)\n :name \"setup-alpha\"\n :pre (and (>= es 0.0)\n           (< es 1.0))\n (sqrt (+ 1.0\n          (/ (* es (pow (cos phi0) 4.0))\n             (- 1.0 es)))))\n\n(FPCore (u0 phi0 alpha g)\n :name \"setup-k\"\n :pre (and (> g 0.0)\n           (> alpha 0.0))\n (let* ([tan-u0  (tan (+ (* 0.5 u0) (/ PI 4.0)))]\n        [tan-phi0 (tan (+ (* 0.5 phi0) (/ PI 4.0)))]\n        [pow-term (pow tan-phi0 alpha)])\n   (/ (* tan-u0 g) pow-term)))\n\n(FPCore (phi0 es)\n :name \"setup-n0\"\n :pre (and (>= es 0.0)\n           (< es 1.0))\n (/ (sqrt (- 1.0 es))\n    (- 1.0 (* es (* (sin phi0) (sin phi0))))))\n\n(FPCore (k0 n0)\n :name \"setup-rho0\"\n :pre (and (> k0 0.0)\n           (> n0 0.0))\n (let* ([S0 1.37008346281555]\n        [tanS0 (tan S0)])\n   (/ (* k0 n0) tanS0)))\n\n(FPCore (phi evar alpha)\n :name \"forward-gfi\"\n :pre (and (>= evar 0.0)\n           (< evar 1.0))\n (pow (/ (+ 1.0 (* evar (sin phi)))\n         (- 1.0 (* evar (sin phi))))\n      (* 0.5 (* alpha evar))))\n\n(FPCore (phi k alpha gfi)\n :name \"forward-u\"\n :pre (and (> k 0.0)\n           (> alpha 0.0)\n           (> gfi 0.0))\n (let* ([tan-term (tan (+ (* 0.5 phi) (/ PI 4.0)))]\n        [pow-term (pow tan-term alpha)]\n        [ratio    (/ (* k pow-term) gfi)])\n   (* 2.0 (- (atan ratio) (/ PI 4.0)))))\n\n(FPCore (u ad deltav)\n :name \"krovak-forward-s\"\n (asin (+ (* (cos ad) (sin u))\n          (* (sin ad) (* (cos u) (cos deltav))))))\n\n(FPCore (rho0 s n)\n :name \"forward-rho\"\n :pre (and (> rho0 0.0)\n           (> n 0.0))\n (let* ([S0       1.37008346281555]\n        [tan-s0   (tan (+ (* 0.5 S0) (/ PI 4.0)))]\n        [tan-term (tan (+ (* 0.5 s) (/ PI 4.0)))]\n        [num      (pow tan-s0 n)]\n        [den      (pow tan-term n)])\n   (/ (* rho0 num) den)))\n\n(FPCore (Xr Yr)\n :name \"mod-dX\"\n (let* ([C1  2.946529277E-02]\n        [C3  1.193845912E-07]\n        [C4 -4.668270147E-07]\n        [C5  9.233980362E-12]\n        [C6  1.523735715E-12]\n        [C7  1.696780024E-18]\n        [C8  4.408314235E-18]\n        [C9 -8.331083518E-24]\n        [C10 -3.689471323E-24]\n        [Xr2 (* Xr Xr)]\n        [Yr2 (* Yr Yr)]\n        [Xr4 (* Xr2 Xr2)]\n        [Yr4 (* Yr2 Yr2)]\n        [diff (- Xr2 Yr2)])\n   (+ C1\n   (+ (* C3 Xr)\n   (+ (* (- C4) Yr)\n   (+ (* -2.0 (* C6 (* Xr Yr)))\n   (+ (* C5 diff)\n   (+ (* C7 (* Xr (- Xr2 (* 3.0 Yr2))))\n   (+ (* (- C8) (* Yr (- (* 3.0 Xr2) Yr2)))\n   (+ (* 4.0 (* C9 (* Xr (* Yr diff))))\n      (* C10 (+ Xr4 (+ Yr4 (* -6.0 (* Xr2 Yr2)))))))))))))))\n\n(FPCore (Xr Yr)\n :name \"mod-dY\"\n (let* ([C2  2.515965696E-02]\n        [C3  1.193845912E-07]\n        [C4 -4.668270147E-07]\n        [C5  9.233980362E-12]\n        [C6  1.523735715E-12]\n        [C7  1.696780024E-18]\n        [C8  4.408314235E-18]\n        [C9 -8.331083518E-24]\n        [C10 -3.689471323E-24]\n        [Xr2 (* Xr Xr)]\n        [Yr2 (* Yr Yr)]\n        [Xr4 (* Xr2 Xr2)]\n        [Yr4 (* Yr2 Yr2)]\n        [diff (- Xr2 Yr2)])\n   (+ C2\n   (+ (* C3 Yr)\n   (+ (* C4 Xr)\n   (+ (* 2.0 (* C5 (* Xr Yr)))\n   (+ (* C6 diff)\n   (+ (* C8 (* Xr (- Xr2 (* 3.0 Yr2))))\n   (+ (* C7 (* Yr (- (* 3.0 Xr2) Yr2)))\n   (+ (* -4.0 (* C10 (* Xr (* Yr diff))))\n      (* C9 (+ Xr4 (+ Yr4 (* -6.0 (* Xr2 Yr2)))))))))))))))\n\n(FPCore (rho0 rho n)\n :name \"inverse-s\"\n :pre (and (> rho0 0.0)\n           (> rho 0.0))\n (let* ([S0       1.37008346281555]\n        [tan-s0   (tan (+ (* 0.5 S0) (/ PI 4.0)))]\n        [ratio    (/ rho0 rho)]\n        [pow-term (pow ratio (/ 1.0 n))]\n        [product  (* pow-term tan-s0)])\n   (* 2.0 (- (atan product) (/ PI 4.0)))))\n\n(FPCore (ad s d)\n :name \"inverse-u\"\n (asin (+ (* (cos ad) (sin s))\n          (* -1.0 (* (sin ad) (* (cos s) (cos d)))))))\n\n(FPCore (u k alpha evar fi)\n :name \"inverse-phi-iter\"\n :pre (and (> k 0.0)\n           (> alpha 0.0)\n           (>= evar 0.0)\n           (< evar 1.0))\n (let* ([pow-k    (pow k (/ -1.0 alpha))]\n        [tan-term (tan (+ (* 0.5 u) (/ PI 4.0)))]\n        [pow-tan  (pow tan-term (/ 1.0 alpha))]\n        [ratio    (/ (+ 1.0 (* evar (sin fi)))\n                     (- 1.0 (* evar (sin fi))))]\n        [pow-ratio (pow ratio (* 0.5 evar))]\n        [product   (* pow-k (* pow-tan pow-ratio))])\n   (* 2.0 (- (atan product) (/ PI 4.0)))))\n"
  },
  {
    "path": "bench/proj/omerc.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (E_var tsfn_phi B)\n :name \"forward-W\"\n (/ E_var (pow tsfn_phi B)))\n\n(FPCore (W)\n :name \"forward-half-diff\"\n (* 0.5 (- W (/ 1.0 W))))\n\n(FPCore (W)\n :name \"forward-half-sum\"\n (* 0.5 (+ W (/ 1.0 W))))\n\n(FPCore (S T singam cosgam B lam)\n :name \"forward-U\"\n (let ([V (sin (* B lam))])\n   (/ (- (* S singam) (* V cosgam)) T)))\n\n(FPCore (U ArB)\n :name \"forward-v\"\n (* 0.5 (* ArB (log (/ (- 1.0 U) (+ 1.0 U))))))\n\n(FPCore (S B lam cosgam singam ArB)\n :name \"forward-u-atan\"\n (let* ([V (sin (* B lam))]\n        [temp (cos (* B lam))]\n        [numer (+ (* S cosgam) (* V singam))])\n   (* ArB (atan2 numer temp))))\n\n(FPCore (u v cosrot sinrot u0)\n :name \"forward-rot-x\"\n (let ([udiff (- u u0)])\n   (+ (* v cosrot) (* udiff sinrot))))\n\n(FPCore (u v cosrot sinrot u0)\n :name \"forward-rot-y\"\n (let ([udiff (- u u0)])\n   (- (* udiff cosrot) (* v sinrot))))\n\n(FPCore (BrA v)\n :name \"inverse-Qp\"\n (exp (- (* BrA v))))\n\n(FPCore (Sp Tp Vp singam cosgam)\n :name \"inverse-Up\"\n (/ (+ (* Vp cosgam) (* Sp singam)) Tp))\n\n(FPCore (Up Esc)\n :name \"inverse-prephi\"\n (/ Esc (sqrt (/ (+ 1.0 Up) (- 1.0 Up)))))\n\n(FPCore (Sp Vp cosgam singam BrA u rB)\n :name \"inverse-lambda\"\n (let ([temp (cos (* BrA u))]\n        [numer (- (* Sp cosgam) (* Vp singam))])\n   (- (* rB (atan2 numer temp)))))\n\n(FPCore (phi0 es)\n :name \"init-con\"\n :pre (and (>= es 0.0)\n           (< es 1.0))\n (let ([sinphi0 (sin phi0)])\n   (- 1.0 (* es (* sinphi0 sinphi0)))))\n\n(FPCore (phi0 es one_es)\n :name \"init-B\"\n :pre (and (>= es 0.0)\n           (< es 1.0)\n           (> one_es 0.0))\n (let* ([cosphi0 (cos phi0)]\n        [cos2 (* cosphi0 cosphi0)]\n        [cos4 (* cos2 cos2)])\n   (sqrt (+ 1.0 (/ (* es cos4) one_es)))))\n\n(FPCore (phi0 es one_es com)\n :name \"init-D\"\n :pre (and (>= es 0.0)\n           (< es 1.0)\n           (> one_es 0.0)\n           (> com 0.0))\n (let* ([sinphi0 (sin phi0)]\n        [cosphi0 (cos phi0)]\n        [cos2 (* cosphi0 cosphi0)]\n        [cos4 (* cos2 cos2)]\n        [con (- 1.0 (* es (* sinphi0 sinphi0)))]\n        [B (sqrt (+ 1.0 (/ (* es cos4) one_es)))]\n        [root (sqrt con)])\n   (/ (* B com) (* cosphi0 root))))\n\n(FPCore (D phi0)\n :name \"init-F\"\n (let ([Fraw (- (* D D) 1.0)])\n   (if (<= Fraw 0.0)\n       0.0\n       (let ([Froot (sqrt Fraw)])\n         (if (< phi0 0.0)\n             (- Froot)\n             Froot)))))\n\n(FPCore (alpha_c D)\n :name \"init-gamma0-from-alpha\"\n (asin (/ (sin alpha_c) D)))\n\n(FPCore (gamma0 D)\n :name \"init-alpha-from-gamma0\"\n (asin (* D (sin gamma0))))\n\n(FPCore (lamc F gamma0 B)\n :name \"init-lam0-alpha\"\n (let* ([half_diff (* 0.5 (- F (/ 1.0 F)))]\n        [angle (asin (* half_diff (tan gamma0)))])\n   (- lamc (/ angle B))))\n\n(FPCore (L H)\n :name \"init-p\"\n (/ (- L H) (+ L H)))\n\n(FPCore (E_var L H)\n :name \"init-J\"\n (let ([E2 (* E_var E_var)]\n        [LH (* L H)])\n   (/ (- E2 LH) (+ E2 LH))))\n\n(FPCore (lam1 lam2 B J p)\n :name \"init-lam0-twopoint\"\n (let* ([delta (- lam1 lam2)]\n        [lam2_adj (if (< delta (- PI))\n                      (+ lam2 (* 2.0 PI))\n                      (if (> delta PI)\n                          (- lam2 (* 2.0 PI))\n                          lam2))]\n        [delta_adj (- lam1 lam2_adj)]\n        [center (* 0.5 (+ lam1 lam2_adj))]\n        [halfBdelta (* 0.5 (* B delta_adj))]\n        [angle (atan (/ (* J (tan halfBdelta)) p))])\n   (- center (/ angle B))))\n\n(FPCore (ArB D alpha_c phi0)\n :name \"init-u0\"\n (let* ([ratio (/ (sqrt (- (* D D) 1.0)) (cos alpha_c))]\n        [angle (atan ratio)]\n        [scaled (* ArB angle)]\n        [mag (fabs scaled)])\n   (if (< phi0 0.0)\n       (- mag)\n       mag)))\n\n(FPCore (ArB gamma0)\n :name \"init-v-pole-n\"\n (* ArB (log (tan (- (/ PI 4.0) (* 0.5 gamma0))))))\n\n(FPCore (phi e)\n :name \"pj_tsfn\"\n (let* ([sinphi (sin phi)]\n        [e_sin (* e sinphi)])\n   (* (tan (* 0.5 (- (/ PI 2) phi)))\n      (pow (/ (+ 1.0 e_sin) \n              (- 1.0 e_sin)) \n           (* 0.5 e)))))\n"
  },
  {
    "path": "bench/proj/som.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (lam p22 sa t w q)\n :name \"seraz0-s\"\n (let* ([sd (sin lam)]\n        [sdsq (* sd sd)]\n        [numer (+ 1.0 (* t sdsq))]\n        [denom (* (+ 1.0 (* w sdsq)) (+ 1.0 (* q sdsq)))])\n   (* p22 (* sa (* (cos lam) (sqrt (/ numer denom)))))))\n\n(FPCore (lam p22 ca q w)\n :name \"seraz0-h\"\n (let* ([sd (sin lam)]\n        [sdsq (* sd sd)]\n        [d1 (+ 1.0 (* q sdsq))]\n        [wterm (+ 1.0 (* w sdsq))]\n        [ratio (/ (+ 1.0 (* q sdsq)) wterm)]\n        [scale (- (/ wterm (* d1 d1)) (* p22 ca))])\n   (* (sqrt ratio) scale)))\n\n(FPCore (mult h xj s)\n :name \"seraz0-fc-a2\"\n (let* ([sq (sqrt (+ (* xj xj) (* s s)))])\n   (* mult (/ (- (* h xj) (* s s)) sq))))\n\n(FPCore (mult h xj s)\n :name \"seraz0-fc-c1\"\n (let* ([sq (sqrt (+ (* xj xj) (* s s)))])\n   (* mult (/ (* s (+ h xj)) sq))))\n\n(FPCore (lamt one_es tanphi sa ca)\n :name \"forward-xlam\"\n (/\n  (+ (* one_es (* tanphi sa))\n     (* (sin lamt) ca))\n  (cos lamt)))\n\n(FPCore (phi es one_es ca sa lamt)\n :name \"forward-phidp\"\n (let* ([sp (sin phi)]\n        [cosphi (cos phi)]\n        [sinlamt (sin lamt)]\n        [denom (sqrt (- 1.0 (* es (* sp sp))))]\n        [arg (/ (- (* one_es (* ca sp)) (* sa (* cosphi sinlamt))) denom)])\n   (asin arg)))\n\n(FPCore (phidp)\n :name \"forward-tanph\"\n (let ([theta (+ (/ PI 4.0) (* 0.5 phidp))])\n   (log (tan theta))))\n\n(FPCore (lamdp b a2 a4 tanph s xj)\n :name \"forward-xy-x\"\n (let* ([d (sqrt (+ (* xj xj) (* s s)))])\n   (+ (* b lamdp)\n    (+  (* a2 (sin (* 2.0 lamdp)))\n    (+  (* a4 (sin (* 4.0 lamdp)))\n      (- (* tanph (/ s d))))))))\n\n(FPCore (lamdp c1 c3 tanph s xj)\n :name \"forward-xy-y\"\n (let* ([d (sqrt (+ (* xj xj) (* s s)))]\n        [sd (sin lamdp)])\n   (+ (* c1 sd)\n   (+ (* c3 (sin (* 3.0 lamdp)))\n      (* tanph (/ xj d))))))\n\n(FPCore (lamdp xy_x xy_y s xj a2 a4 c1 c3 b)\n :name \"inverse-lamdp-update\"\n (let* ([sinlam (sin lamdp)]\n        [sin2 (sin (* 2.0 lamdp))]\n        [sin3 (sin (* 3.0 lamdp))]\n        [sin4 (sin (* 4.0 lamdp))]\n        [ratio (/ s xj)]\n        [base (+ xy_x (* xy_y ratio))]\n        [poly (- (- base (* a2 sin2)) (* a4 sin4))]\n        [corr (* ratio (+ (* c1 sinlam) (* c3 sin3)))])\n   (/ (- poly corr) b)))\n\n(FPCore (s xj xy_y c1 c3 lamdp)\n :name \"inverse-fac\"\n (let* ([ratio (/ (* s s) (* xj xj))]\n        [scale (sqrt (+ 1.0 ratio))]\n        [sl (sin lamdp)]\n        [inner (- xy_y\n                  (+ (* c1 sl)\n                     (* c3 (sin (* 3.0 lamdp)))))])\n   (exp (* scale inner))))\n\n(FPCore (fac)\n :name \"inverse-phidp\"\n (* 2.0 (- (atan fac) (/ PI 4.0))))\n\n(FPCore (lamdp spp q u rone_es ca sa)\n :name \"inverse-lamt\"\n (let* ([sppsq (* spp spp)]\n        [dd (* (sin lamdp) (sin lamdp))]\n        [coslam (cos lamdp)]\n        [denom (- 1.0 (* sppsq (+ 1.0 u)))]\n        [kterm (+ 1.0 (* q dd))]\n        [root (sqrt (- (* kterm (- 1.0 sppsq)) (* sppsq u)))]\n        [term1 (* (- 1.0 (* sppsq rone_es)) (* (tan lamdp) ca))]\n        [term2 (/ (* spp (* sa root)) coslam)]\n        [frac (/ (- term1 term2) denom)])\n   (atan frac)))\n\n(FPCore (lamdp lamt ca one_es sa)\n :name \"inverse-phi\"\n (atan (/ (- (* (tan lamdp) (cos lamt)) (* ca (sin lamt)))\n         (* one_es sa))))\n\n(FPCore (spp es one_es)\n :name \"inverse-phi-degenerate\"\n (let* ([one_es2 (* one_es one_es)]\n        [denom (sqrt (+ one_es2 (* es (* spp spp))))])\n   (asin (/ spp denom))))\n\n(FPCore (es ca rone_es)\n :name \"setup-w\"\n :pre (> rone_es 0.0)\n (let* ([esc (* es (* ca ca))]\n        [scaled (* (- 1.0 esc) rone_es)])\n   (- (* scaled scaled) 1.0)))\n\n(FPCore (es sa rone_es)\n :name \"setup-t\"\n :pre (> rone_es 0.0)\n (let ([ess (* es (* sa sa))]\n        [rone2 (* rone_es rone_es)])\n   (* ess (* (- 2.0 es) rone2))))\n\n(FPCore (one_es)\n :name \"setup-xj\"\n :pre (> one_es 0.0)\n (* one_es (* one_es one_es)))"
  },
  {
    "path": "bench/proj/somerc.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (phi)\n :name \"forward-tanlog\"\n (log (tan (+ (/ PI 4.0) (* 0.5 phi)))))\n\n(FPCore (phi ecc)\n :name \"forward-ellipsoid-logratio\"\n :pre (and (> ecc 0.0)\n           (< ecc 1.0))\n (let ([sp (* ecc (sin phi))])\n   (log (/ (+ 1.0 sp) (- 1.0 sp)))))\n\n(FPCore (phi ecc c hlf_e K)\n :name \"forward-phip\"\n :pre (and (> ecc 0.0)\n           (< ecc 1.0))\n (let* ([sp (* ecc (sin phi))]\n        [log_tan (log (tan (+ (/ PI 4.0) (* 0.5 phi))))]\n        [log_ratio (log (/ (+ 1.0 sp) (- 1.0 sp)))]\n        [exponent (+ (* c (- log_tan (* hlf_e log_ratio))) K)])\n   (- (* 2.0 (atan (exp exponent))) (/ PI 2.0))))\n\n(FPCore (phip cosp0 sinp0 lamp)\n :name \"forward-phipp\"\n (asin (- (* cosp0 (sin phip)) (* sinp0 (* (cos phip) (cos lamp))))))\n\n(FPCore (cp lamp phipp)\n :name \"forward-lampp\"\n (asin (/ (* cp (sin lamp)) (cos phipp))))\n\n(FPCore (kR phipp)\n :name \"forward-y\"\n :pre (> kR 0.0)\n (* kR (log (tan (+ (/ PI 4.0) (* 0.5 phipp))))))\n\n(FPCore (y kR)\n :name \"inverse-phipp\"\n :pre (> kR 0.0)\n (* 2.0 (- (atan (exp (/ y kR))) (/ PI 4.0))))\n\n(FPCore (phipp cosp0 sinp0 lampp)\n :name \"inverse-phip\"\n (asin (+ (* cosp0 (sin phipp)) (* sinp0 (* (cos phipp) (cos lampp))))))\n\n(FPCore (phipp lampp phip)\n :name \"inverse-lamp\"\n (asin (/ (* (cos phipp) (sin lampp)) (cos phip))))\n\n(FPCore (K c phip)\n :name \"inverse-con\"\n (/ (- K (log (tan (+ (/ PI 4.0) (* 0.5 phip))))) c))\n\n(FPCore (phip ecc)\n :name \"inverse-esp\"\n :pre (and (> ecc 0.0)\n           (< ecc 1.0))\n (* ecc (sin phip)))\n\n(FPCore (phip ecc hlf_e con rone_es)\n :name \"inverse-delp\"\n :pre (and (> ecc 0.0)\n           (< ecc 1.0))\n (let* ([esp (* ecc (sin phip))]\n        [log_tan (log (tan (+ (/ PI 4.0) (* 0.5 phip))))]\n        [log_ratio (log (/ (+ 1.0 esp) (- 1.0 esp)))]\n        [term (- (+ con log_tan) (* hlf_e log_ratio))]\n        [factor (* (- 1.0 (* esp esp)) (* (cos phip) rone_es))])\n   (* term factor)))\n\n(FPCore (phi0 es rone_es)\n :name \"init-c\"\n :pre (and (>= es 0.0)\n           (< es 1.0)\n           (> rone_es 0.0))\n (let* ([cosphi0 (cos phi0)]\n        [cos2 (* cosphi0 cosphi0)]\n        [cos4 (* cos2 cos2)])\n   (sqrt (+ 1.0 (* es (* cos4 rone_es))))))\n\n(FPCore (phi0 c)\n :name \"init-sinp0\"\n (/ (sin phi0) c))\n\n(FPCore (phi0 phip0 c hlf_e ecc)\n :name \"init-K\"\n :pre (and (> c 0.0)\n           (> ecc 0.0)\n           (< ecc 1.0))\n (let* ([sp (* ecc (sin phi0))]\n        [log_tan_phi   (log (tan (+ (/ PI 4.0) (* 0.5 phi0))))]\n        [log_tan_phip0 (log (tan (+ (/ PI 4.0) (* 0.5 phip0))))]\n        [log_ratio     (log (/ (+ 1.0 sp) (- 1.0 sp)))])\n   (- log_tan_phip0\n      (* c (- log_tan_phi (* hlf_e log_ratio))))))\n\n(FPCore (k0 one_es ecc phi0)\n :name \"init-kR\"\n :pre (and (> k0 0.0)\n           (> one_es 0.0)\n           (> ecc 0.0)\n           (< ecc 1.0))\n (let ([sp (* ecc (sin phi0))])\n   (/ (* k0 (sqrt one_es)) (- 1.0 (* sp sp)))))\n   "
  },
  {
    "path": "bench/proj/tmerc.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (phi)\n :name \"approx-t-guarded\"\n (let ([sinphi (sin phi)]\n       [cosphi (cos phi)])\n   (if (> (fabs cosphi) 1e-10)\n       (/ sinphi cosphi)\n       0.0)))\n\n(FPCore (phi lam es)\n :name \"approx-scaled-lambda\"\n :pre (and (>= es 0.0)\n           (< es 1.0))\n (let* ([sinphi (sin phi)]\n        [cosphi (cos phi)]\n        [den (- 1.0 (* es (* sinphi sinphi)))])\n   (/ (* cosphi lam)\n      (sqrt den))))\n\n(FPCore (phi x es k0)\n :name \"approx-inv-d-term\"\n :pre (and (>= es 0.0)\n           (< es 1.0)\n           (> k0 0.0))\n (let* ([sinphi (sin phi)]\n        [con (- 1.0 (* es (* sinphi sinphi)))])\n   (/ (* x (sqrt con)) k0)))\n\n(FPCore (phi lam)\n :name \"spherical-fwd-b\"\n (let ([cosphi (cos phi)]\n       [sinlam (sin lam)])\n   (* cosphi sinlam)))\n\n(FPCore (b ml0)\n :name \"spherical-fwd-x-from-b\"\n (* ml0\n    (log (/ (+ 1.0 b)\n            (- 1.0 b)))))\n\n(FPCore (phi lam)\n :name \"spherical-fwd-y-cos-quotient\"\n (let* ([cosphi (cos phi)]\n        [coslam (cos lam)]\n        [b (* cosphi (sin lam))]\n        [one-minus-b2 (- 1.0 (* b b))])\n   (/ (* cosphi coslam)\n      (sqrt one-minus-b2))))\n\n(FPCore (x esp)\n :name \"spherical-inv-g-from-exp\"\n :pre (> esp 0.0)\n (let ([h (exp (/ x esp))])\n   (* 0.5 (- h (/ 1.0 h)))))\n\n(FPCore (y esp phi0 g)\n :name \"spherical-inv-latitude-angle\"\n :pre (> esp 0.0)\n (let* ([D (+ phi0 (/ y esp))]\n        [cosD (cos D)]\n        [numer (- 1.0 (* cosD cosD))]\n        [denom (+ 1.0 (* g g))])\n   (* (copysign 1.0 D)\n      (asin (sqrt (/ numer denom))))))\n\n(FPCore (y esp phi0 g)\n :name \"spherical-inv-longitude\"\n :pre (> esp 0.0)\n (let* ([D (+ phi0 (/ y esp))]\n        [cD (cos D)])\n   (if (or (> (fabs g) 0.0)\n           (> (fabs cD) 0.0))\n       (atan2 g cD)\n       0.0)))\n\n(FPCore (Cn lam)\n :name \"exact-forward-conformal-lat\"\n (let ([sC (sin Cn)]\n       [cC (cos Cn)]\n       [cE (cos lam)])\n   (atan2 sC (* cC cE))))\n\n(FPCore (Cn lam)\n :name \"exact-forward-tanCe\"\n (let* ([sC (sin Cn)]\n        [cC (cos Cn)]\n        [sE (sin lam)]\n        [cE (cos lam)]\n        [den (sqrt (+ (* sC sC)\n                      (* cC (* cC (* cE cE)))))])\n   (/ (* sE cC) den)))\n\n(FPCore (Cn lam)\n :name \"exact-forward-two-inv-denom\"\n (let* ([sC (sin Cn)]\n        [cC (cos Cn)]\n        [cE (cos lam)]\n        [den (sqrt (+ (* sC sC)\n                      (* cC (* cC (* cE cE)))))])\n   (/ 2.0 den)))\n\n(FPCore (sin_arg_r cosh_arg_i cos_arg_r sinh_arg_i hr hi)\n :name \"clenshaw-final-real\"\n (let ([r (* sin_arg_r cosh_arg_i)]\n       [i (* cos_arg_r sinh_arg_i)])\n   (- (* r hr) (* i hi))))\n\n(FPCore (sin_arg_r cosh_arg_i cos_arg_r sinh_arg_i hr hi)\n :name \"clenshaw-final-imag\"\n (let ([r (* sin_arg_r cosh_arg_i)]\n       [i (* cos_arg_r sinh_arg_i)])\n   (+ (* r hi) (* i hr))))\n\n(FPCore (Ce)\n :name \"exact-inv-exp2Ce\"\n (exp (* 2.0 Ce)))\n\n(FPCore (Ce)\n :name \"exact-inv-half-inv-exp\"\n (let ([exp2-val (exp (* 2.0 Ce))])\n   (/ 0.5 exp2-val)))\n\n(FPCore (Ce)\n :name \"exact-inv-cosh-arg\"\n (let* ([exp2-val (exp (* 2.0 Ce))]\n        [half (/ 0.5 exp2-val)])\n   (+ (* 0.5 exp2-val) half)))\n\n(FPCore (Cn Ce)\n :name \"exact-inv-Ce-angle\"\n (let* ([sinhCe (sinh Ce)]\n        [cosC (cos Cn)])\n   (atan2 sinhCe cosC)))\n\n(FPCore (Cn Ce)\n :name \"exact-inv-Cn-angle\"\n (let* ([sinhCe (sinh Ce)]\n        [cosC (cos Cn)]\n        [sinC (sin Cn)]\n        [mod (sqrt (+ (* sinhCe sinhCe)\n                      (* cosC cosC)))])\n   (atan2 sinC mod)))\n\n(FPCore (Cn Ce)\n :name \"exact-inv-rr\"\n (let* ([sinhCe (sinh Ce)]\n        [cosC (cos Cn)]\n        [sinC (sin Cn)]\n        [mod (sqrt (+ (* sinhCe sinhCe)\n                      (* cosC cosC)))])\n   (sqrt (+ (* sinC sinC)\n            (* mod mod)))))\n"
  },
  {
    "path": "bench/regression.fpcore",
    "content": "; -*- mode: scheme -*-\n\n; This is a cool example that fails in cases of overflow\n\n(FPCore (lo hi x)\n  :name \"xlohi (overflows)\"\n  :pre (and (< lo -1e308) (> hi 1e308))\n  :precision binary64\n  (/ (- x lo) (- hi lo)))\n\n; These once crashed Herbie\n\n(FPCore (x y z a)\n :name \"tan-example (used to crash)\"\n :pre (and (or (== x 0) (<= 0.5884142 x 505.5909))\n           (or (<= -1.796658e+308 y -9.425585e-310) (<= 1.284938e-309 y 1.751224e+308))\n           (or (<= -1.776707e+308 z -8.599796e-310) (<= 3.293145e-311 z 1.725154e+308))\n           (or (<= -1.796658e+308 a -9.425585e-310) (<= 1.284938e-309 a 1.751224e+308)))\n (+ x (- (tan (+ y z)) (tan a))))\n\n(FPCore (x c s)\n  :name \"mixedcos\"\n  (/ (cos (* 2 x)) (* (pow c 2) (* (* x (pow s 2)) x))))\n\n(FPCore (x)\n  :name \"x (used to be hard to sample)\"\n  :pre (or (== x 0) (== x 10))\n  x)\n\n; These should yield the same result\n\n(FPCore (r a b)\n :name \"rsin A (should all be same)\"\n (/ (* r (sin b)) (cos (+ a b))))\n\n(FPCore (r a b)\n :name \"rsin B (should all be same)\"\n (* r (/ (sin b) (cos (+ a b)))))\n\n; These should yield the same result\n\n(FPCore (x)\n :name \"sqrt A (should all be same)\"\n (sqrt (+ (* x x) (* x x))))\n\n(FPCore (x)\n :name \"sqrt B (should all be same)\"\n (sqrt (* (* 2 x) x)))\n\n(FPCore (x)\n :name \"sqrt C (should all be same)\"\n (sqrt (* 2 (* x x))))\n\n(FPCore (x)\n :name \"sqrt D (should all be same)\"\n (sqrt (* 2 (pow x 2))))\n\n(FPCore (x)\n :name \"sqrt E (should all be same)\"\n (sqrt (+ (pow x 2) (pow x 2))))\n\n; This used to cause crashes\n\n(FPCore (w l)\n :name \"exp-w (used to crash)\"\n (* (exp (- w)) (pow l (exp w))))\n\n(FPCore (x)\n :name \"expfmod (used to be hard to sample)\"\n (* (fmod (exp x) (sqrt (cos x))) (exp (- x))))\n\n; Regression tests from user-filed bugs\n\n(FPCore (x)\n  :name \"bug323 (missed optimization)\"\n  :pre (<= 0 x 0.5)\n  :alt \n  (! :herbie-platform default\n    (* 2 (asin (sqrt (/ x 2)))))\n\n  (acos (- 1 x)))\n\n(FPCore (x y)\n  :name \"bug329 (missed optimization)\"\n  :pre (>= x 0)\n  :alt \n  (! :herbie-platform default\n   (atan2 y x))\n\n  (atan (/ y x)))\n\n(FPCore (x)\n  :name \"bug333 (missed optimization)\"\n  :pre (<= -1 x 1)\n  :alt \n  (! :herbie-platform default\n   (/ (* 2 x) (+ (sqrt (+ 1 x)) (sqrt (- 1 x)))))\n  \n  (- (sqrt (+ 1 x)) (sqrt (- 1 x))))\n\n(FPCore (x y z)\n  :name \"bug366 (missed optimization)\"\n  :alt \n  (! :herbie-platform default\n   (hypot x (hypot y z)))\n\n  (sqrt (+ (* x x) (+ (* y y) (* z z)))))\n\n(FPCore (a b)\n  :name \"bug366, discussion (missed optimization)\"\n  :alt \n  (! :herbie-platform default\n   (let* ([fa (fabs a)] [fb (fabs b)])\n     (* (sqrt (+ fa fb)) (sqrt (- fa fb)))))\n\n  (sqrt (- (* a a) (* b b))))\n\n(FPCore (x)\n  :name \"bug500 (missed optimization)\"\n  :pre (< -1e3 x 1e3)\n  :alt \n  (! :herbie-platform default\n    (if (< (fabs x) 0.07)\n      (- (+ (- (/ (pow x 3) 6) (/ (pow x 5) 120)) (/ (pow x 7) 5040)))\n      (- (sin x) x)))\n\n  (- (sin x) x))\n\n(FPCore (x)\n  :name \"bug500, discussion (missed optimization)\"\n  :alt \n  (! :herbie-platform default\n   (if (< (fabs x) .085)\n      (let ([x2 (* x x)])\n        (* x2 (fma (fma (fma -1/37800 x2 1/2835) x2 -1/180) x2 1/6)))\n      (log (/ (sinh x) x))))\n  \n  (log (/ (sinh x) x)))\n\n(FPCore (x)\n  :name \"bug1188 (missed optimization)\"\n  :alt\n  (! :herbie-platform default\n   (if (>= (fabs x) (pow 2 52))\n      0.0\n      (sin (* PI x))))\n\n  (sin (* PI x)))\n"
  },
  {
    "path": "bench/tutorial.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (x)\n :name \"Cancel like terms\"\n (- (+ 1 x) x))\n\n(FPCore (x)\n :name \"Expanding a square\"\n (- (* (+ x 1) (+ x 1)) 1))\n\n(FPCore (x y z)\n :name \"Commute and associate\"\n (- (+ (+ x y) z) (+ x (+ y z))))\n"
  },
  {
    "path": "egg-herbie/.gitignore",
    "content": "target\n**/*.rs.bk\n\ndots/\negg/data/\n\n# nix stuff\n.envrc\ndefault.nix\n\n# Racket\n*.zo\n*.dep\n"
  },
  {
    "path": "egg-herbie/Cargo.toml",
    "content": "[package]\nname = \"egg-herbie\"\nversion = \"0.3.0\"\nauthors = [ \"Oliver Flatt <oflatt@gmail.com>\", \"Max Willsey <me@mwillsey.com>\" ]\nedition = \"2021\"\n\n[dependencies]\negg = { git = \"https://github.com/egraphs-good/egg.git\", rev = \"6f2ac1ee72d0ec6b51d12c9ca59e94ada6615e87\" }\n\nlog = \"0.4\"\nindexmap = \"1\"\nlibc = \"0.2.125\"\n\nnum-bigint = \"0.4.3\"\nnum-integer = \"0.1.45\"\nnum-rational = \"0.4.0\"\nnum-traits = \"0.2.15\"\nenv_logger = { version = \"0.9\", default-features = false }\n\n[lib]\nname = \"egg_math\"\ncrate-type = [\"rlib\", \"cdylib\"]\n\n[profile.test]\ndebug = true\nopt-level = 1\n\n[profile.release]\ndebug = true\nlto = \"fat\"\ncodegen-units = 1\n"
  },
  {
    "path": "egg-herbie/LICENSE",
    "content": "Copyright 2019 Max Willsey\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "egg-herbie/README.md",
    "content": "# Herbie's FFI to egraphs-good/egg\r\n\r\nThis is a small Rust+Racket package co-developed with Herbie so that\r\nHerbie can bind to and use the [egg](https://egraphs-good.github.io)\r\nequality saturation library.\r\n\r\nThe Racket side is in [`main.rkt`](main.rkt). It does only two things:\r\nfind the `libegg_math` shared library and expose its main functions to\r\nRacket. It has a bit of logic for detecting architecture mismatches\r\ndue to Rosetta Apple Silicon.\r\n\r\nThe Rust side is implemented in standard Rust using the `egg` library.\r\nThe `math` module contains math-specific implementation work while the\r\n`lib` module contains code to interface with Racket.\r\n\r\nThe main Herbie repository's Github Actions build and publish versions\r\nof the Racket package (including pre-built Rust libraries).\r\n"
  },
  {
    "path": "egg-herbie/info.rkt",
    "content": "#lang info\n\n(define collection \"egg-herbie\")\n(define version \"2.2\")\n\n(define pkg-desc \"Racket bindings for simplifying math expressions using egg\")\n(define pkg-authors `(\"Oliver Flatt\" \"Brett Saiki\" \"Pavel Panchekha\"))\n\n(define build-deps '(\"rackunit-lib\"))\n\n(define deps '((\"base\" #:version \"8.0\")))\n\n(define license 'MIT)\n"
  },
  {
    "path": "egg-herbie/main.rkt",
    "content": "#lang racket\n\n(require ffi/unsafe\n         ffi/unsafe/define\n         ffi/vector\n         racket/runtime-path)\n\n(provide egraph_create\n         egraph_destroy\n         egraph_add_expr\n         egraph_add_root\n         egraph_add_node\n         egraph_run\n         egraph_copy\n         egraph_get_stop_reason\n         egraph_find\n         egraph_serialize\n         egraph_get_eclasses\n         egraph_get_eclass\n         egraph_get_simplest\n         egraph_get_variants\n         egraph_get_cost\n         egraph_is_unsound_detected\n         egraph_get_times_applied\n         egraph_get_proof\n         (struct-out iteration-data)\n         (struct-out FFIRule)\n         make-ffi-rule)\n\n(define-runtime-path libeggmath-path\n                     (build-path \"target/release\"\n                                 (string-append (case (system-type)\n                                                  [(windows) \"egg_math\"]\n                                                  [else \"libegg_math\"])\n                                                (bytes->string/utf-8 (system-type 'so-suffix)))))\n\n; Checks if Racket is being run in emulation via rosetta\n(define (running-on-rosetta?)\n  (and (equal? (system-type 'os) 'macosx)\n       (equal? (system-type 'arch) 'x86_64)\n       (equal? (with-output-to-string (lambda () ; returns true if running in emulation\n                                        (system \"sysctl -n sysctl.proc_translated\")))\n               \"1\\n\")))\n\n; Note, this message should not be reached.\n(define fallback-message\n  (string-append \"Error: unable to load the 'egg-math' library\\n\"\n                 \"Please file a bug at https://github.com/herbie-fp/herbie/issues\"))\n\n; Note, refering to ARM as Apple Silicon to match Racket download page.\n(define rosetta-message\n  (string-append \"Error: You are running the 'x86' version of Racket via 'Rosetta' emulation.\\n\"\n                 \"  Please use the 'Apple Silicon' version of Racket instead.\\n\"\n                 \"You can install it from https://download.racket-lang.org\"))\n\n(define (handle-eggmath-import-failure)\n  (define error-message (if (running-on-rosetta?) rosetta-message fallback-message))\n  (raise-user-error error-message))\n\n; Checks for a condition on MacOS if x86 Racket is being used on an ARM mac.\n(define-ffi-definer define-eggmath (ffi-lib libeggmath-path #:fail handle-eggmath-import-failure))\n\n;; Frees a Rust-allocated C-string\n(define-eggmath destroy_string (_fun _pointer -> _void))\n\n;; Gets the length of a Rust-allocated C-string in bytes,\n;; excluding the nul terminator.\n(define-eggmath string_length (_fun _pointer -> _uint32))\n\n;; Converts a Racket string to a C-style string.\n(define (string->_rust/string s #:raw? [raw? #f])\n  (define bstr (string->bytes/utf-8 s))\n  (define n (bytes-length bstr))\n  (define p (malloc (if raw? 'raw 'atomic) (add1 n)))\n  (memcpy p bstr n)\n  (ptr-set! p _byte n 0)\n  p)\n\n;; Converts a non-NULL, Rust-allocated C-string to a Racket string,\n;; freeing the Rust string.\n(define (_rust/string->string p)\n  (define len (string_length p))\n  (define bstr (make-bytes len))\n  (memcpy bstr p len)\n  (destroy_string p)\n  (bytes->string/utf-8 bstr))\n\n;; Converts a non-NULL, Rust-allocated C-string to a Racket datum\n;; by repeatedly reading the string. The underlying Rust string\n;; is automatically freed.\n(define (_rust/string->data p)\n  (define len (string_length p))\n  (define bstr (make-bytes len))\n  (memcpy bstr p len)\n  (destroy_string p)\n  (for/list ([datum (in-port read (open-input-bytes bstr))])\n    datum))\n\n;; FFI type that converts Rust-allocated C-style strings\n;; to Racket strings, automatically freeing the Rust-side allocation.\n(define _rust/string\n  (make-ctype _pointer\n              (lambda (x) (and x (string->_rust/string x)))\n              (lambda (x) (and x (_rust/string->string x)))))\n\n;; FFI type that converts Rust-allocated C-style strings\n;; to a Racket datum via `read`, automatically freeing the Rust-side allocation.\n(define _rust/datum\n  (make-ctype _pointer\n              (lambda (x) (and x (string->_rust/string (~a x))))\n              (lambda (x) (and x (first (_rust/string->data x))))))\n\n;; FFI type that converts Rust-allocated C-style strings\n;; to multiple Racket datum via reapeated use of `read`,\n;; automatically freeing the Rust-side allocation.\n(define _rust/data\n  (make-ctype _pointer\n              (lambda (_) (error '_rust/data \"cannot be used as an input type\"))\n              (lambda (x) (and x (_rust/string->data x)))))\n\n; Egraph iteration data\n; Not managed by Racket GC.\n; Must call `destroy_egraphiters` to free.\n(define-cstruct _EGraphIter ([numnodes _uint] [numeclasses _uint] [time _double]) #:malloc-mode 'raw)\n\n;; Frees an array of _EgraphIter structs\n(define-eggmath destroy_egraphiters (_fun _pointer -> _void))\n\n;; Racket representation of `_EGraphIter`\n(struct iteration-data (num-nodes num-eclasses time))\n\n;; Rewrite rule that can be passed over the FFI boundary.\n;; Must be manually freed.\n(define-cstruct _FFIRule ([name _pointer] [left _pointer] [right _pointer]) #:malloc-mode 'raw)\n\n;; Constructs for `_FFIRule` struct.\n(define (make-ffi-rule name lhs rhs)\n  (define name* (string->_rust/string (~a name) #:raw? #t))\n  (define lhs* (string->_rust/string (~a lhs) #:raw? #t))\n  (define rhs* (string->_rust/string (~a rhs) #:raw? #t))\n  (define p (make-FFIRule name* lhs* rhs*))\n  (register-finalizer p free-ffi-rule)\n  p)\n\n;; Frees a `_FFIRule` struct.\n(define (free-ffi-rule rule)\n  (free (FFIRule-name rule))\n  (free (FFIRule-left rule))\n  (free (FFIRule-right rule))\n  (free rule))\n\n; GC'able egraph\n; If Racket GC can prove unreachable, `egraph_destroy` will be called\n(define _egraph-pointer\n  (_cpointer 'egraph\n             #f\n             #f\n             (lambda (p)\n               (register-finalizer p egraph_destroy)\n               p)))\n\n;; Constructs an e-graph instances.\n(define-eggmath egraph_create (_fun -> _egraph-pointer))\n\n;; Frees an e-graph instance.\n(define-eggmath egraph_destroy (_fun _egraph-pointer -> _void))\n\n;; Copies an e-graph instance.\n(define-eggmath egraph_copy (_fun _egraph-pointer -> _egraph-pointer))\n\n;; Adds an expression to the e-graph.\n;; egraph -> expr -> id\n(define-eggmath egraph_add_expr (_fun _egraph-pointer _rust/datum -> _uint))\n\n(define-eggmath egraph_add_root (_fun _egraph-pointer _uint -> _void))\n\n; egraph -> string -> ids -> bool -> id\n(define-eggmath egraph_add_node\n                (_fun [p : _egraph-pointer] ; egraph\n                      [f : _rust/string] ; enode op\n                      [v : _u32vector] ; id vector\n                      [_uint = (u32vector-length v)] ; id vector length\n                      ->\n                      _uint))\n\n(define-eggmath egraph_is_unsound_detected (_fun _egraph-pointer -> _stdbool))\n\n;; Runs the egraph with a set of rules, returning the statistics of the run.\n(define-eggmath egraph_run\n                (_fun _egraph-pointer ;; egraph\n                      (ffi-rules : (_list i _FFIRule-pointer)) ;; ffi rules\n                      (_uint = (length ffi-rules)) ;; number of rules\n                      (iterations-length : (_ptr o _uint)) ;; pointer to length of resulting array\n                      (iterations-ptr :\n                                      (_ptr o _pointer)) ;; pointer to array allocation, caller frees\n                      _uint ;; iter limit\n                      _uint ;; node limit\n                      _stdbool ;; simple scheduler?\n                      ->\n                      (iterations : _EGraphIter-pointer) ;; array of _EgraphIter structs\n                      ->\n                      (begin\n                        (define iter-data\n                          (for/list ([i (in-range iterations-length)])\n                            (define ptr (ptr-add iterations i _EGraphIter))\n                            (iteration-data (EGraphIter-numnodes ptr)\n                                            (EGraphIter-numeclasses ptr)\n                                            (EGraphIter-time ptr))))\n                        (destroy_egraphiters iterations-ptr)\n                        iter-data)))\n\n(define _stop_reason (_enum '(saturated iter-limit node-limit unsound) _uint))\n\n;; gets the stop reason as an integer\n(define-eggmath egraph_get_stop_reason (_fun _egraph-pointer -> _stop_reason))\n\n;; egraph -> string\n(define-eggmath egraph_serialize (_fun _egraph-pointer -> _rust/datum))\n\n;; egraph -> uint\n(define-eggmath egraph_size (_fun _egraph-pointer -> _uint))\n\n;; egraph -> id -> uint\n(define-eggmath egraph_eclass_size (_fun _egraph-pointer _uint -> _uint))\n\n;; egraph -> id -> idx -> uint\n(define-eggmath egraph_enode_size (_fun _egraph-pointer _uint _uint -> _uint))\n\n;; egraph -> u32vector\n(define-eggmath\n egraph_get_eclasses\n (_fun [e : _egraph-pointer] [v : _u32vector = (make-u32vector (egraph_size e))] -> _void -> v))\n\n;; egraph -> id -> u32 -> (or symbol? number? (cons symbol u32vector))\n;; UNSAFE: `v` must be large enough to contain the child ids\n(define-eggmath egraph_get_node\n                (_fun [e : _egraph-pointer]\n                      [id : _uint32]\n                      [idx : _uint32]\n                      [v : _u32vector]\n                      ->\n                      [f : _rust/string]\n                      ->\n                      (if (zero? (u32vector-length v))\n                          (or (string->number f) (string->symbol f))\n                          (cons (string->symbol f) v))))\n; u32vector\n(define empty-u32vec (make-u32vector 0))\n\n; egraph -> id -> (vectorof (or symbol? number? (cons symbol u32vector)))\n(define (egraph_get_eclass egg-ptr id)\n  (define n (egraph_eclass_size egg-ptr id))\n  (for/vector #:length n\n              ([i (in-range n)])\n    (define node-size (egraph_enode_size egg-ptr id i))\n    (if (zero? node-size)\n        (egraph_get_node egg-ptr id i empty-u32vec)\n        (egraph_get_node egg-ptr id i (make-u32vector node-size)))))\n\n;; egraph -> id -> id\n(define-eggmath egraph_find (_fun _egraph-pointer _uint -> _uint))\n\n;; egraph -> id -> (listof expr)\n(define-eggmath egraph_get_simplest\n                (_fun _egraph-pointer\n                      _uint ;; node id\n                      _uint ;; iteration\n                      ->\n                      _rust/datum)) ;; expr\n\n;; egraph -> id -> string -> (listof expr)\n(define-eggmath egraph_get_variants\n                (_fun _egraph-pointer\n                      _uint ;; node id\n                      _rust/datum ;; original expr\n                      ->\n                      _rust/data)) ;; listof expr\n\n;; egraph -> string -> string -> string\n;; TODO: in Herbie, we bail on converting the proof\n;; if the string is too big. It would be more efficient\n;; to bail here instead.\n(define-eggmath egraph_get_proof\n                (_fun _egraph-pointer ;; egraph\n                      _rust/datum ;; expr1\n                      _rust/datum ;; expr2\n                      ->\n                      _rust/string)) ;; string\n\n(define-eggmath egraph_get_cost\n                (_fun _egraph-pointer\n                      _uint ;; node id\n                      _uint ;; iteration\n                      ->\n                      _uint))\n\n(define-eggmath egraph_get_times_applied\n                (_fun _egraph-pointer\n                      _pointer ;; name of the rule\n                      ->\n                      _uint))\n"
  },
  {
    "path": "egg-herbie/src/lib.rs",
    "content": "#![allow(clippy::missing_safety_doc)]\n\npub mod math;\n\nuse egg::{BackoffScheduler, Extractor, FromOp, Id, Language, SimpleScheduler, StopReason, Symbol};\nuse indexmap::IndexMap;\nuse libc::{c_void, strlen};\nuse math::*;\n\nuse std::cmp::min;\nuse std::ffi::{CStr, CString};\nuse std::mem::{self, ManuallyDrop};\nuse std::os::raw::c_char;\nuse std::time::Duration;\nuse std::{slice, sync::atomic::Ordering};\n\npub struct Context {\n    iteration: usize,\n    runner: Runner,\n    rules: Vec<Rewrite>,\n}\n\n// I had to add $(rustc --print sysroot)/lib to LD_LIBRARY_PATH to get linking to work after installing rust with rustup\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_create() -> *mut Context {\n    Box::into_raw(Box::new(Context {\n        iteration: 0,\n        runner: Runner::new(Default::default()).with_explanations_enabled(),\n        rules: vec![],\n    }))\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_destroy(ptr: *mut Context) {\n    drop(Box::from_raw(ptr))\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn destroy_egraphiters(ptr: *mut c_void) {\n    // TODO: Switch ffi to use `usize` directly to avoid the risk of these being incorrect\n    drop(Box::from_raw(ptr as *mut Vec<EGraphIter>));\n    // drop(Vec::from_raw_parts(data, length as usize, capacity as usize))\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn destroy_string(ptr: *mut c_char) {\n    drop(CString::from_raw(ptr))\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn string_length(ptr: *const c_char) -> u32 {\n    strlen(ptr) as u32\n}\n\n#[repr(C)]\npub struct EGraphIter {\n    numnodes: u32,\n    numclasses: u32,\n    time: f64,\n}\n\n// a struct for loading rules from external source\n#[repr(C)]\npub struct FFIRule {\n    name: *const c_char,\n    left: *const c_char,\n    right: *const c_char,\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_add_expr(ptr: *mut Context, expr: *const c_char) -> u32 {\n    let _ = env_logger::try_init();\n    // Safety: `ptr` was box allocated by `egraph_create`\n    let mut context = Box::from_raw(ptr);\n\n    assert_eq!(context.iteration, 0);\n    let rec_expr = CStr::from_ptr(expr).to_str().unwrap().parse().unwrap();\n    context.runner = context.runner.with_expr(&rec_expr);\n    let id = usize::from(*context.runner.roots.last().unwrap())\n        .try_into()\n        .unwrap();\n\n    mem::forget(context);\n\n    id\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_add_root(ptr: *mut Context, id: u32) {\n    let mut context = ManuallyDrop::new(Box::from_raw(ptr));\n    context.runner.roots.push(Id::from(id as usize));\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_add_node(\n    ptr: *mut Context,\n    f: *const c_char,\n    ids_ptr: *const u32,\n    num_ids: u32,\n) -> u32 {\n    let _ = env_logger::try_init();\n    // Safety: `ptr` was box allocated by `egraph_create`\n    let mut context = ManuallyDrop::new(Box::from_raw(ptr));\n\n    let f = CStr::from_ptr(f).to_str().unwrap();\n    let len = num_ids as usize;\n    let ids: &[u32] = slice::from_raw_parts(ids_ptr, len);\n    let ids = ids.iter().map(|id| Id::from(*id as usize)).collect();\n    let node = Math::from_op(f, ids).unwrap();\n    let id = context.runner.egraph.add(node);\n    usize::from(id) as u32\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_copy(ptr: *mut Context) -> *mut Context {\n    // Safety: `ptr` was box allocated by `egraph_create`\n    let context = Box::from_raw(ptr);\n    let mut runner = Runner::new(Default::default())\n        .with_explanations_enabled()\n        .with_egraph(context.runner.egraph.clone());\n    runner.roots = context.runner.roots.clone();\n    runner.egraph.rebuild();\n\n    mem::forget(context);\n\n    Box::into_raw(Box::new(Context {\n        iteration: 0,\n        rules: vec![],\n        runner,\n    }))\n}\n\nunsafe fn ptr_to_string(ptr: *const c_char) -> String {\n    let bytes = CStr::from_ptr(ptr).to_bytes();\n    String::from_utf8(bytes.to_vec()).unwrap()\n}\n\n// todo don't just unwrap, also make sure the rules are validly parsed\nunsafe fn ffirule_to_tuple(rule_ptr: *mut FFIRule) -> (String, String, String) {\n    let rule = &mut *rule_ptr;\n    (\n        ptr_to_string(rule.name),\n        ptr_to_string(rule.left),\n        ptr_to_string(rule.right),\n    )\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_run(\n    ptr: *mut Context,\n    rules_array_ptr: *const *mut FFIRule,\n    rules_array_length: u32,\n    iterations_length: *mut u32,\n    iterations_ptr: *mut *mut c_void,\n    iter_limit: u32,\n    node_limit: u32,\n    simple_scheduler: bool,\n) -> *const EGraphIter {\n    // Safety: `ptr` was box allocated by `egraph_create`\n    let mut context = Box::from_raw(ptr);\n\n    if context.runner.stop_reason.is_none() {\n        let length: usize = rules_array_length as usize;\n        let ffi_rules: &[*mut FFIRule] = slice::from_raw_parts(rules_array_ptr, length);\n        let mut ffi_tuples: Vec<(&str, &str, &str)> = vec![];\n        let mut ffi_strings: Vec<(String, String, String)> = vec![];\n        for ffi_rule in ffi_rules.iter() {\n            let str_tuple = ffirule_to_tuple(*ffi_rule);\n            ffi_strings.push(str_tuple);\n        }\n\n        for ffi_string in ffi_strings.iter() {\n            ffi_tuples.push((&ffi_string.0, &ffi_string.1, &ffi_string.2));\n        }\n\n        let rules: Vec<Rewrite> = math::mk_rules(&ffi_tuples);\n        context.rules = rules;\n\n        context.runner = if simple_scheduler {\n            context.runner.with_scheduler(SimpleScheduler)\n        } else {\n            context.runner.with_scheduler(BackoffScheduler::default())\n        };\n\n        context.runner = context\n            .runner\n            .with_node_limit(node_limit as usize)\n            .with_iter_limit(iter_limit as usize) // should never hit\n            .with_time_limit(Duration::from_secs(u64::MAX))\n            .with_hook(|r| {\n                if r.egraph.analysis.unsound.load(Ordering::SeqCst) {\n                    Err(\"Unsoundness detected\".into())\n                } else {\n                    Ok(())\n                }\n            })\n            .run(&context.rules);\n    }\n\n    // Prune all e-nodes with children where its e-class has a leaf node (with no children). Pruning\n    // safely improves performance because pruning occurs right before extraction and leaf e-nodes\n    // always have a lower cost.\n    context.runner.egraph.classes_mut().for_each(|eclass| {\n        if eclass.nodes.iter().any(|n| n.is_leaf()) {\n            eclass.nodes.retain(|n| n.is_leaf());\n        }\n    });\n\n    let iterations = context\n        .runner\n        .iterations\n        .iter()\n        .map(|iteration| EGraphIter {\n            numnodes: iteration.egraph_nodes as u32,\n            numclasses: iteration.egraph_classes as u32,\n            time: iteration.total_time,\n        })\n        .collect::<Vec<_>>();\n    let iterations_data = iterations.as_ptr();\n\n    std::ptr::write(iterations_length, iterations.len() as u32);\n    std::ptr::write(\n        iterations_ptr,\n        Box::into_raw(Box::new(iterations)) as *mut c_void,\n    );\n    mem::forget(context);\n\n    iterations_data\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_get_stop_reason(ptr: *mut Context) -> u32 {\n    // Safety: `ptr` was box allocated by `egraph_create`\n    let context = ManuallyDrop::new(Box::from_raw(ptr));\n\n    match context.runner.stop_reason {\n        Some(StopReason::Saturated) => 0,\n        Some(StopReason::IterationLimit(_)) => 1,\n        Some(StopReason::NodeLimit(_)) => 2,\n        Some(StopReason::Other(_)) => 3,\n        _ => 4,\n    }\n}\n\nfn find_extracted(runner: &Runner, id: u32, iter: u32) -> &Extracted {\n    let id = runner.egraph.find(Id::from(id as usize));\n\n    // go back one more iter, egg can duplicate the final iter in the case of an error\n    let is_unsound = runner.egraph.analysis.unsound.load(Ordering::SeqCst);\n    let sound_iter = min(\n        runner\n            .iterations\n            .len()\n            .saturating_sub(if is_unsound { 3 } else { 1 }),\n        iter as usize,\n    );\n\n    runner.iterations[sound_iter]\n        .data\n        .extracted\n        .iter()\n        .find(|(i, _)| runner.egraph.find(*i) == id)\n        .map(|(_, ext)| ext)\n        .expect(\"Couldn't find matching extraction!\")\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_find(ptr: *mut Context, id: usize) -> u32 {\n    let context = ManuallyDrop::new(Box::from_raw(ptr));\n    let node_id = Id::from(id);\n    let canon_id = context.runner.egraph.find(node_id);\n    usize::from(canon_id) as u32\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_serialize(ptr: *mut Context) -> *const c_char {\n    // Safety: `ptr` was box allocated by `egraph_create`\n    let context = ManuallyDrop::new(Box::from_raw(ptr));\n    let mut ids: Vec<Id> = context.runner.egraph.classes().map(|c| c.id).collect();\n    ids.sort();\n\n    // Iterate through the eclasses and print each eclass\n    let mut s = String::from(\"(\");\n    for id in ids {\n        let c = &context.runner.egraph[id];\n        s.push_str(&format!(\"({}\", id));\n        for node in &c.nodes {\n            if matches!(node, Math::Symbol(_) | Math::Constant(_)) {\n                s.push_str(&format!(\" {}\", node));\n            } else {\n                s.push_str(&format!(\"({}\", node));\n                for c in node.children() {\n                    s.push_str(&format!(\" {}\", c));\n                }\n                s.push(')');\n            }\n        }\n\n        s.push(')');\n    }\n    s.push(')');\n\n    let c_string = ManuallyDrop::new(CString::new(s).unwrap());\n    c_string.as_ptr()\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_size(ptr: *mut Context) -> u32 {\n    let context = ManuallyDrop::new(Box::from_raw(ptr));\n    context.runner.egraph.number_of_classes() as u32\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_eclass_size(ptr: *mut Context, id: u32) -> u32 {\n    let context = ManuallyDrop::new(Box::from_raw(ptr));\n    let id = Id::from(id as usize);\n    context.runner.egraph[id].nodes.len() as u32\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_enode_size(ptr: *mut Context, id: u32, idx: u32) -> u32 {\n    let context = ManuallyDrop::new(Box::from_raw(ptr));\n    let id = Id::from(id as usize);\n    let idx = idx as usize;\n    context.runner.egraph[id].nodes[idx].len() as u32\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_get_eclasses(ptr: *mut Context, ids_ptr: *mut u32) {\n    let context = ManuallyDrop::new(Box::from_raw(ptr));\n    let mut ids: Vec<u32> = context\n        .runner\n        .egraph\n        .classes()\n        .map(|c| usize::from(c.id) as u32)\n        .collect();\n    ids.sort();\n\n    for (i, id) in ids.iter().enumerate() {\n        std::ptr::write(ids_ptr.offset(i as isize), *id);\n    }\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_get_node(\n    ptr: *mut Context,\n    id: u32,\n    idx: u32,\n    ids: *mut u32,\n) -> *const c_char {\n    let context = ManuallyDrop::new(Box::from_raw(ptr));\n    let id = Id::from(id as usize);\n    let idx = idx as usize;\n\n    let node = &context.runner.egraph[id].nodes[idx];\n    for (i, id) in node.children().iter().enumerate() {\n        std::ptr::write(ids.offset(i as isize), usize::from(*id) as u32);\n    }\n\n    let c_string = ManuallyDrop::new(CString::new(node.to_string()).unwrap());\n    c_string.as_ptr()\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_get_simplest(\n    ptr: *mut Context,\n    node_id: u32,\n    iter: u32,\n) -> *const c_char {\n    // Safety: `ptr` was box allocated by `egraph_create`\n    let context = ManuallyDrop::new(Box::from_raw(ptr));\n    let ext = find_extracted(&context.runner, node_id, iter);\n    let best_str = ManuallyDrop::new(CString::new(ext.best.to_string()).unwrap());\n\n    best_str.as_ptr()\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_get_proof(\n    ptr: *mut Context,\n    expr: *const c_char,\n    goal: *const c_char,\n) -> *const c_char {\n    // Safety: `ptr` was box allocated by `egraph_create`\n    let mut context = ManuallyDrop::new(Box::from_raw(ptr));\n    // Send `EGraph` since neither `Context` nor `Runner` are `Send`. `Runner::explain_equivalence` just forwards to `EGraph::explain_equivalence` so this is fine.\n    let egraph = &mut context.runner.egraph;\n    let expr_rec = CStr::from_ptr(expr).to_str().unwrap().parse().unwrap();\n    let goal_rec = CStr::from_ptr(goal).to_str().unwrap().parse().unwrap();\n\n    // extract the proof as a tree\n    let string = egraph\n        .explain_equivalence(&expr_rec, &goal_rec)\n        .get_string_with_let()\n        .replace('\\n', \" \");\n\n    let c_string = ManuallyDrop::new(CString::new(string).unwrap());\n    c_string.as_ptr()\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_get_variants(\n    ptr: *mut Context,\n    node_id: u32,\n    orig_expr: *const c_char,\n) -> *const c_char {\n    // Safety: `ptr` was box allocated by `egraph_create`\n    let context = ManuallyDrop::new(Box::from_raw(ptr));\n\n    // root (id, expr)\n    let id = Id::from(node_id as usize);\n    let orig_recexpr: RecExpr = CStr::from_ptr(orig_expr).to_str().unwrap().parse().unwrap();\n    let head_node = &orig_recexpr.as_ref()[orig_recexpr.as_ref().len() - 1];\n\n    // extractor\n    let extractor = Extractor::new(&context.runner.egraph, AltCost::new(&context.runner.egraph));\n    let mut cache: IndexMap<Id, RecExpr> = Default::default();\n\n    // extract variants\n    let mut exprs = vec![];\n    for n in &context.runner.egraph[id].nodes {\n        // assuming same ops in an eclass cannot\n        // have different precisions\n        if !n.matches(head_node) {\n            // extract if not in cache\n            n.for_each(|id| {\n                if cache.get(&id).is_none() {\n                    let (_, best) = extractor.find_best(id);\n                    cache.insert(id, best);\n                }\n            });\n\n            exprs.push(n.join_recexprs(|id| cache.get(&id).unwrap().as_ref()));\n        }\n    }\n\n    // format\n    let expr_strs: Vec<String> = exprs.iter().map(|r| r.to_string()).collect();\n    let best_str = ManuallyDrop::new(CString::new(expr_strs.join(\" \")).unwrap());\n\n    best_str.as_ptr()\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_is_unsound_detected(ptr: *mut Context) -> bool {\n    // Safety: `ptr` was box allocated by `egraph_create`\n    let context = ManuallyDrop::new(Box::from_raw(ptr));\n\n    context\n        .runner\n        .egraph\n        .analysis\n        .unsound\n        .load(Ordering::SeqCst)\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_get_times_applied(ptr: *mut Context, name: *const c_char) -> u32 {\n    // Safety: `ptr` was box allocated by `egraph_create`\n    let context = ManuallyDrop::new(Box::from_raw(ptr));\n    let sym = Symbol::from(ptr_to_string(name));\n\n    context\n        .runner\n        .iterations\n        .iter()\n        .map(|iter| *iter.applied.get(&sym).unwrap_or(&0) as u32)\n        .sum()\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_get_cost(ptr: *mut Context, node_id: u32, iter: u32) -> u32 {\n    // Safety: `ptr` was box allocated by `egraph_create`\n    let context = ManuallyDrop::new(Box::from_raw(ptr));\n    let ext = find_extracted(&context.runner, node_id, iter);\n\n    ext.cost as u32\n}\n\n#[no_mangle]\npub unsafe extern \"C\" fn egraph_get_size(ptr: *mut Context) -> u32 {\n    // Safety: `ptr` was box allocated by `egraph_create`\n    let context = ManuallyDrop::new(Box::from_raw(ptr));\n\n    context\n        .runner\n        .iterations\n        .last()\n        .map(|iteration| iteration.egraph_nodes as u32)\n        .unwrap_or_default()\n}\n"
  },
  {
    "path": "egg-herbie/src/math.rs",
    "content": "use egg::*;\nuse std::sync::atomic::{AtomicBool, Ordering};\n\nuse num_bigint::BigInt;\nuse num_integer::Integer;\nuse num_rational::Ratio;\nuse num_traits::{One, Pow, Signed, Zero};\nuse std::str::FromStr;\n\npub type Constant = num_rational::BigRational;\npub type RecExpr = egg::RecExpr<Math>;\npub type Pattern = egg::Pattern<Math>;\npub type EGraph = egg::EGraph<Math, ConstantFold>;\npub type Rewrite = egg::Rewrite<Math, ConstantFold>;\npub type Runner = egg::Runner<Math, ConstantFold, IterData>;\npub type Iteration = egg::Iteration<IterData>;\n\npub struct IterData {\n    pub extracted: Vec<(Id, Extracted)>,\n}\n\npub struct Extracted {\n    pub best: RecExpr,\n    pub cost: usize,\n}\n\n// cost function similar to AstSize except it will\n// penalize `(pow _ p)` where p is a fraction\npub struct AltCost<'a> {\n    pub egraph: &'a EGraph,\n}\n\nimpl<'a> AltCost<'a> {\n    pub fn new(egraph: &'a EGraph) -> Self {\n        Self { egraph }\n    }\n}\n\nimpl<'a> CostFunction<Math> for AltCost<'a> {\n    type Cost = usize;\n\n    fn cost<C>(&mut self, enode: &Math, mut costs: C) -> Self::Cost\n    where\n        C: FnMut(Id) -> Self::Cost,\n    {\n        if let Math::Pow([_, i]) = enode {\n            if let Some((n, _reason)) = &self.egraph[*i].data {\n                if !n.denom().is_one() && n.denom().is_odd() {\n                    return usize::MAX;\n                }\n            }\n        }\n\n        enode.fold(1, |sum, id| usize::saturating_add(sum, costs(id)))\n    }\n}\n\nimpl IterationData<Math, ConstantFold> for IterData {\n    fn make(runner: &Runner) -> Self {\n        let extractor = Extractor::new(&runner.egraph, AltCost::new(&runner.egraph));\n        let extracted = runner\n            .roots\n            .iter()\n            .map(|&root| {\n                let (cost, best) = extractor.find_best(root);\n                let ext = Extracted { cost, best };\n                (root, ext)\n            })\n            .collect();\n        Self { extracted }\n    }\n}\n\n// operators from FPCore\ndefine_language! {\n    pub enum Math {\n\n        // constant-folding operators\n\n        \"+\" = Add([Id; 2]),\n        \"-\" = Sub([Id; 2]),\n        \"*\" = Mul([Id; 2]),\n        \"/\" = Div([Id; 2]),\n        \"pow\" = Pow([Id; 2]),\n        \"neg\" = Neg([Id; 1]),\n        \"sqrt\" = Sqrt([Id; 1]),\n        \"fabs\" = Fabs([Id; 1]),\n        \"ceil\" = Ceil([Id; 1]),\n        \"floor\" = Floor([Id; 1]),\n        \"round\" = Round([Id; 1]),\n        \"log\" = Log([Id; 1]),\n        \"cbrt\" = Cbrt([Id; 1]),\n\n        Constant(Constant),\n        Symbol(egg::Symbol),\n        Other(egg::Symbol, Vec<Id>),\n    }\n}\n\npub struct ConstantFold {\n    pub unsound: AtomicBool,\n    pub max_abs_exponent: Ratio<BigInt>,\n    pub prune: bool,\n}\n\nimpl Clone for ConstantFold {\n    fn clone(&self) -> Self {\n        let unsound = AtomicBool::new(self.unsound.load(Ordering::SeqCst));\n        Self {\n            unsound,\n            max_abs_exponent: self.max_abs_exponent.clone(),\n            prune: self.prune,\n        }\n    }\n}\n\nimpl Default for ConstantFold {\n    fn default() -> Self {\n        Self {\n            unsound: AtomicBool::new(false),\n            // Avoid calculating extremely large numbers. 16 is somewhat arbitrary, even 0 passes\n            // all tests.\n            max_abs_exponent: Ratio::new(BigInt::from(16), BigInt::from(1)),\n            prune: true,\n        }\n    }\n}\n\nimpl Analysis<Math> for ConstantFold {\n    type Data = Option<(Constant, (PatternAst<Math>, Subst))>;\n    fn make(egraph: &mut EGraph, enode: &Math) -> Self::Data {\n        let x = |id: &Id| egraph[*id].data.clone().map(|x| x.0);\n        let is_zero = |id: &Id| {\n            let data = egraph[*id].data.as_ref();\n            match data {\n                Some(data) => data.0.is_zero(),\n                None => false,\n            }\n        };\n\n        Some((\n            match enode {\n                Math::Constant(c) => c.clone(),\n\n                // real\n                Math::Add([a, b]) => x(a)? + x(b)?,\n                Math::Sub([a, b]) => x(a)? - x(b)?,\n                Math::Mul([a, b]) => x(a)? * x(b)?,\n                Math::Div([a, b]) => {\n                    if x(b)?.is_zero() {\n                        return None;\n                    } else {\n                        x(a)? / x(b)?\n                    }\n                }\n                Math::Neg([a]) => -x(a)?,\n                Math::Pow([a, b]) => {\n                    if is_zero(a) {\n                        if x(b)?.is_positive() {\n                            Ratio::new(BigInt::from(0), BigInt::from(1))\n                        } else {\n                            return None;\n                        }\n                    } else if is_zero(b) {\n                        Ratio::new(BigInt::from(1), BigInt::from(1))\n                    } else if x(b)?.is_integer() && x(b)?.abs() <= egraph.analysis.max_abs_exponent\n                    {\n                        Pow::pow(x(a)?, x(b)?.to_integer())\n                    } else {\n                        return None;\n                    }\n                }\n                Math::Sqrt([a]) => {\n                    let a = x(a)?;\n                    if *a.numer() > BigInt::from(0) && *a.denom() > BigInt::from(0) {\n                        let s1 = a.numer().sqrt();\n                        let s2 = a.denom().sqrt();\n                        let is_perfect = &(&s1 * &s1) == a.numer() && &(&s2 * &s2) == a.denom();\n                        if is_perfect {\n                            Ratio::new(s1, s2)\n                        } else {\n                            return None;\n                        }\n                    } else {\n                        return None;\n                    }\n                }\n                Math::Log([a]) => {\n                    if x(a)? == Ratio::new(BigInt::from(1), BigInt::from(1)) {\n                        Ratio::new(BigInt::from(0), BigInt::from(1))\n                    } else {\n                        return None;\n                    }\n                }\n                Math::Cbrt([a]) => {\n                    if x(a)? == Ratio::new(BigInt::from(1), BigInt::from(1)) {\n                        Ratio::new(BigInt::from(1), BigInt::from(1))\n                    } else {\n                        return None;\n                    }\n                }\n                Math::Fabs([a]) => x(a)?.abs(),\n                Math::Floor([a]) => x(a)?.floor(),\n                Math::Ceil([a]) => x(a)?.ceil(),\n                Math::Round([a]) => x(a)?.round(),\n\n                _ => return None,\n            },\n            {\n                let mut pattern: PatternAst<Math> = Default::default();\n                let mut var_counter = 0;\n                let mut subst: Subst = Default::default();\n                enode.for_each(|child| {\n                    if let Some(constant) = x(&child) {\n                        pattern.add(ENodeOrVar::ENode(Math::Constant(constant)));\n                    } else {\n                        let var = (\"?\".to_string() + &var_counter.to_string())\n                            .parse()\n                            .unwrap();\n                        pattern.add(ENodeOrVar::Var(var));\n                        subst.insert(var, child);\n                        var_counter += 1;\n                    }\n                });\n                let mut counter = 0;\n                let mut head = enode.clone();\n                head.update_children(|_child| {\n                    let res = Id::from(counter);\n                    counter += 1;\n                    res\n                });\n                pattern.add(ENodeOrVar::ENode(head));\n                (pattern, subst)\n            },\n        ))\n    }\n\n    fn merge(&mut self, to: &mut Self::Data, from: Self::Data) -> DidMerge {\n        match (&to, from) {\n            (None, None) => DidMerge(false, false),\n            (Some(_), None) => DidMerge(false, true), // no update needed\n            (None, Some(c)) => {\n                *to = Some(c);\n                DidMerge(true, false)\n            }\n            (Some(a), Some(ref b)) => {\n                if a.0 != b.0 && !self.unsound.swap(true, Ordering::SeqCst) {\n                    log::warn!(\"Bad merge detected: {} != {}\", a.0, b.0);\n                }\n                DidMerge(false, false)\n            }\n        }\n    }\n\n    fn modify(egraph: &mut EGraph, class_id: Id) {\n        let class = &mut egraph[class_id];\n        if let Some((c, (pat, subst))) = class.data.clone() {\n            egraph.union_instantiations(\n                &pat,\n                &format!(\"{}\", c).parse().unwrap(),\n                &subst,\n                \"metadata-eval\".to_string(),\n            );\n        }\n    }\n}\n\npub fn mk_rules(tuples: &[(&str, &str, &str)]) -> Vec<Rewrite> {\n    tuples\n        .iter()\n        .map(|(name, left, right)| {\n            let left = Pattern::from_str(left).unwrap();\n            let right = Pattern::from_str(right).unwrap();\n            Rewrite::new(*name, left, right).unwrap()\n        })\n        .collect()\n}\n"
  },
  {
    "path": "infra/.gitignore",
    "content": "*.log\n*exceptions*.rkt\ngraphs-*/\n"
  },
  {
    "path": "infra/analyze-rules.rkt",
    "content": "#lang racket\n\n(require \"../src/core/egg-herbie.rkt\"\n         \"../src/syntax/batch.rkt\"\n         \"../src/syntax/types.rkt\"\n         \"../src/syntax/load-platform.rkt\"\n         \"../src/syntax/platform.rkt\"\n         \"../src/core/programs.rkt\"\n         \"../src/core/rules.rkt\"\n         \"../src/syntax/read.rkt\")\n\n(define *iters* (make-parameter 3))\n\n(module+ main\n  (command-line #:once-each\n                [(\"--iters\") iters \"How many iterations to analyze\" (*iters* (string->number iters))]\n                #:args ([dir \"bench/\"])\n                (run-analysis dir)))\n\n(define (run-analysis dir)\n  (activate-platform! \"c\")\n  (define tests (load-tests dir))\n\n  (printf \"Loaded ~a tests from ~a\\n\" (length tests) dir)\n\n  ;; Store accumulated impact: iter -> rule-name -> total-percentage\n  (define impact (make-vector (*iters*)))\n  (define iter-sizes (make-vector (*iters*) '())) ; iter -> list of final sizes\n\n  (for ([i (in-range (*iters*))])\n    (vector-set! impact i (make-hash)))\n\n  (for ([test (in-list tests)]\n        [i (in-naturals)])\n    (printf \"Processing test ~a/~a: ~a\\n\" (+ i 1) (length tests) (test-name test))\n    (define-values (batch brfs) (progs->batch (list (test-input test))))\n\n    (for ([iter (in-range (*iters*))])\n      (define-values (initial-size final-size sorted-results)\n        (egraph-analyze-rewrite-impact batch brfs (test-context test) iter))\n\n      (vector-set! iter-sizes iter (cons final-size (vector-ref iter-sizes iter)))\n      (for ([(rule delta) (in-dict sorted-results)])\n        (define pct (/ (* 100.0 delta) final-size))\n        (define iter-hash (vector-ref impact iter))\n        (hash-update! iter-hash (rule-name rule) (curry + pct) 0.0))))\n\n  (define count (length tests))\n  (for ([iter (in-range (*iters*))])\n    (define sizes (vector-ref iter-sizes iter))\n    (define log-sum (apply + (map log sizes)))\n    (define geomean (exp (/ log-sum count)))\n    (printf \"=== Iteration ~a (Geomean: ~a) ===\\n\" iter (exact-floor geomean))\n\n    (define iter-impact (vector-ref impact iter))\n    ;; Average the percentages\n    (define sorted-avg (sort (hash->list iter-impact) > #:key cdr))\n    (for ([item (in-list sorted-avg)]\n          [_ (in-range 10)])\n      (printf\n       \"~a ~a%\\n\"\n       (~a (car item) #:width 30)\n       (~a (~r (/ (cdr item) count) #:precision '(= 2) #:min-width 6) #:width 7 #:align 'right)))\n    (newline)))\n"
  },
  {
    "path": "infra/bench/posit-pherbie.fpcore",
    "content": "; -*- mode: scheme -*-\n\n(FPCore (x)\n :name \"2sqrt (example 3.1)\"\n :precision binary32\n :herbie-conversions ((binary32 posit16))\n (- (sqrt (+ x 1)) (sqrt x)))\n\n(FPCore (x eps)\n :name \"2sin (example 3.3)\"\n :precision binary32\n :herbie-conversions ((binary32 posit16))\n (- (sin (+ x eps)) (sin x)))\n\n(FPCore (x)\n :name \"tanhf (example 3.4)\"\n :precision binary32\n :herbie-conversions ((binary32 posit16))\n (/ (- 1 (cos x)) (sin x)))\n\n(FPCore (N)\n :name \"2atan (example 3.5)\"\n :precision binary32\n :herbie-conversions ((binary32 posit16))\n (- (atan (+ N 1)) (atan N)))\n\n(FPCore (x)\n :name \"2isqrt (example 3.6)\"\n :precision binary32\n :herbie-conversions ((binary32 posit16))\n (- (/ 1 (sqrt x)) (/ 1 (sqrt (+ x 1)))))\n\n(FPCore (x)\n :name \"2frac (problem 3.3.1)\"\n :precision binary32\n :herbie-conversions ((binary32 posit16))\n (- (/ 1 (+ x 1)) (/ 1 x)))\n\n(FPCore (x eps)\n :name \"2tan (problem 3.3.2)\"\n :precision binary32\n :herbie-conversions ((binary32 posit16))\n (- (tan (+ x eps)) (tan x)))\n\n(FPCore (x)\n :name \"3frac (problem 3.3.3)\"\n :precision binary32\n :herbie-conversions ((binary32 posit16))\n (+ (- (/ 1 (+ x 1)) (/ 2 x)) (/ 1 (- x 1))))\n\n(FPCore (x)\n :name \"2cbrt (problem 3.3.4)\"\n :precision binary32\n :herbie-conversions ((binary32 posit16))\n (- (cbrt (+ x 1)) (cbrt x)))\n\n(FPCore (x eps)\n :name \"2cos (problem 3.3.5)\"\n :precision binary32\n :herbie-conversions ((binary32 posit16))\n (- (cos (+ x eps)) (cos x)))\n\n(FPCore (N)\n :name \"2log (problem 3.3.6)\"\n :precision binary32\n :herbie-conversions ((binary32 posit16))\n (- (log (+ N 1)) (log N)))\n\n(FPCore (x)\n :name \"exp2 (problem 3.3.7)\"\n :precision binary32\n :herbie-conversions ((binary32 posit16))\n (+ (- (exp x) 2) (exp (- x))))\n"
  },
  {
    "path": "infra/bench/posits.fpcore",
    "content": "; -*- mode: scheme -*-\n\n; Herbie cannot properly sample points for this FPCore\n;\n; (FPCore (a b c)\n;  :pre (and (< 0 a) (< 0 b) (< 0 c))\n;  :name \"Area of a triangle\"\n;  :precision posit16\n;  :herbie-expected 16\n;  (let ([s (/ (+ (+ a b) c) 2)])\n;    (sqrt (* s (- s a) (- s b) (- s c)))))\n\n(FPCore (a b c)\n :name \"quadp (p42, positive)\"\n :precision posit16\n :herbie-expected 16\n (let ([d (sqrt (- (* b b) (* 4 (* a c))))])\n   (/ (+ (- b) d) (* 2 a))))\n\n(FPCore (a b c)\n :name \"quadm (p42, negative)\"\n :precision posit16\n :herbie-expected 16\n (let ([d (sqrt (- (* b b) (* 4 (* a c))))])\n   (/ (- (- b) d) (* 2 a))))\n\n(FPCore (a b_2 c)\n :name \"quad2m (problem 3.2.1, negative)\"\n :precision posit16\n :herbie-expected 16\n (let ([d (sqrt (- (* b_2 b_2) (* a c)))])\n   (/ (- (- b_2) d) a)))\n\n(FPCore (a b_2 c)\n :name \"quad2p (problem 3.2.1, positive)\"\n :precision posit16\n :herbie-expected 16\n (let ([d (sqrt (- (* b_2 b_2) (* a c)))])\n   (/ (+ (- b_2) d) a)))\n\n(FPCore (x)\n :name \"2sqrt (example 3.1)\"\n :precision posit16\n :herbie-expected 16\n (- (sqrt (+ x 1)) (sqrt x)))\n\n(FPCore (x)\n :name \"2isqrt (example 3.6)\"\n :precision posit16\n :herbie-expected 16\n (- (/ 1 (sqrt x)) (/ 1 (sqrt (+ x 1)))))\n\n(FPCore (x)\n :name \"2frac (problem 3.3.1)\"\n :precision posit16\n :herbie-expected 16\n (- (/ 1 (+ x 1)) (/ 1 x)))\n\n(FPCore (x)\n :name \"3frac (problem 3.3.3)\"\n :precision posit16\n :herbie-expected 16\n (+ (- (/ 1 (+ x 1)) (/ 2 x)) (/ 1 (- x 1))))\n\n(FPCore (re im)\n :name \"math.abs on complex\"\n :precision posit16\n :herbie-expected 16\n (sqrt (+ (* re re) (* im im))))\n\n(FPCore (x.re x.im)\n :name \"math.cube on complex, real part\"\n :precision posit16\n :herbie-expected 16\n (-\n  (* (- (* x.re x.re) (* x.im x.im)) x.re)\n  (* (+ (* x.re x.im) (* x.im x.re)) x.im)))\n\n(FPCore (x.re x.im)\n :name \"math.cube on complex, imaginary part\"\n :precision posit16\n :herbie-expected 16\n (+\n  (* (- (* x.re x.re) (* x.im x.im)) x.im)\n  (* (+ (* x.re x.im) (* x.im x.re)) x.re)))\n\n(FPCore (x.re x.im y.re y.im)\n :name \"_divideComplex, real part\"\n :precision posit16\n :herbie-expected 16\n (/ (+ (* x.re y.re) (* x.im y.im)) (+ (* y.re y.re) (* y.im y.im))))\n\n(FPCore (x.re x.im y.re y.im)\n :name \"_divideComplex, imaginary part\"\n :precision posit16\n :herbie-expected 16\n (/ (- (* x.im y.re) (* x.re y.im)) (+ (* y.re y.re) (* y.im y.im))))\n\n(FPCore (x.re x.im y.re y.im)\n :name \"_multiplyComplex, real part\"\n :precision posit16\n :herbie-expected 16\n (- (* x.re y.re) (* x.im y.im)))\n\n(FPCore (x.re x.im y.re y.im)\n :name \"_multiplyComplex, imaginary part\"\n :precision posit16\n :herbie-expected 16\n (+ (* x.re y.im) (* x.im y.re)))\n\n(FPCore (re im)\n :name \"math.sqrt on complex, real part\"\n :precision posit16\n :herbie-expected 16\n (* 0.5 (sqrt (* 2.0 (+ (sqrt (+ (* re re) (* im im))) re)))))\n\n(FPCore (re im)\n :name \"math.sqrt on complex, imaginary part, im greater than 0 branch\"\n :precision posit16\n :herbie-expected 16\n (* 0.5 (sqrt (* 2.0 (- (sqrt (+ (* re re) (* im im))) re)))))\n\n(FPCore (re im)\n :name \"math.square on complex, real part\"\n :precision posit16\n :herbie-expected 16\n (- (* re re) (* im im)))\n\n(FPCore (re im)\n :name \"math.square on complex, imaginary part\"\n :precision posit16\n :herbie-expected 16\n (+ (* re im) (* im re)))\n\n(FPCore (alpha beta)\n :pre (and (> alpha -1) (> beta -1))\n :name \"Octave 3.8, jcobi/1\"\n :precision posit16\n :herbie-expected 16\n (let ((ab (+ alpha beta)) (ad (- beta alpha)) (ap (* beta alpha)))\n   (/ (+ (/ ad (+ ab 2.0)) 1.0) 2.0)))\n\n(FPCore (alpha beta i)\n :pre (and (> alpha -1) (> beta -1) (> i 0))\n :name \"Octave 3.8, jcobi/2\"\n :precision posit16\n :herbie-expected 16\n (let ((ab (+ alpha beta)) (ad (- beta alpha)) (ap (* beta alpha)))\n   (let ((z (+ ab (* 2 i))))\n     (/ (+ (/ (* ab ad) z (+ z 2.0)) 1.0) 2.0))))\n\n(FPCore (alpha beta)\n :pre (and (> alpha -1) (> beta -1))\n :name \"Octave 3.8, jcobi/3\"\n :precision posit16\n :herbie-expected 16\n (let ((i 1) (ab (+ alpha beta)) (ad (- beta alpha)) (ap (* beta alpha)))\n   (let ((z1 i))\n     (let ((z (+ ab (* 2 z1))))\n       (/ (+ ab ap 1.0) z z (+ z 1.0))))))\n\n(FPCore (alpha beta i) ; TODO: i should be an integer\n :pre (and (> alpha -1) (> beta -1) (> i 1))\n :name \"Octave 3.8, jcobi/4\"\n :precision posit16\n :herbie-expected 16\n (let ((ab (+ alpha beta)) (ad (- beta alpha)) (ap (* beta alpha)))\n   (let ((z (+ ab (* 2 i))))\n     (let ((z* (* z z)) (y (* i (+ ab i))))\n       (let ((y* (* y (+ ap y))))\n         (/ y* z* (- z* 1.0)))))))\n\n(FPCore (i)\n :pre (and (> i 0))\n :name \"Octave 3.8, jcobi/4, as called\"\n :precision posit16\n :herbie-expected 16\n (let ((z (* 2 i)))\n   (let ((z* (* z z)) (y (* i i)))\n     (let ((y* (* y y))) (/ y* z* (- z* 1.0))))))\n\n(FPCore (a rand)\n :name \"Octave 3.8, oct_fill_randg\"\n :precision posit16\n :herbie-expected 16\n (let ((d (- a (/ 1.0 3.0))))\n   (let ((c (/ 1 (sqrt (* 9 d)))) (x rand))\n     (let ((v (+ 1 (* c x))))\n       (let ((v* (* v (* v v))) (xsq (* x x)))\n         (* d v))))))\n\n(FPCore (d1 d2 d3)\n :name \"FastMath dist\"\n :precision posit16\n :herbie-expected 16\n (+ (* d1 d2) (* d1 d3)))\n\n(FPCore (d)\n :name \"FastMath test1\"\n :precision posit16\n :herbie-expected 16\n (+ (* d 10) (* d 20)))\n\n(FPCore (d1 d2)\n :name \"FastMath test2\"\n :precision posit16\n :herbie-expected 16\n (+ (* d1 10) (* d1 d2) (* d1 20)))\n\n(FPCore (d1 d2 d3)\n :name \"FastMath dist3\"\n :precision posit16\n :herbie-expected 16\n (+ (* d1 d2) (* (+ d3 5) d1) (* d1 32)))\n\n(FPCore (d1 d2 d3 d4)\n :name \"FastMath dist4\"\n :precision posit16\n :herbie-expected 16\n (- (+ (- (* d1 d2) (* d1 d3)) (* d4 d1)) (* d1 d1)))\n\n(FPCore (d1 d2 d3)\n :name \"FastMath test3\"\n :precision posit16\n :herbie-expected 16\n (+ (* d1 3) (* d1 d2) (* d1 d3)))\n\n(FPCore (d1)\n :name \"FastMath repmul\"\n :precision posit16\n :herbie-expected 16\n (* d1 d1 d1 d1))\n\n(FPCore (x)\n :name \"Jmat.Real.dawson\"\n :precision posit16\n :herbie-expected 16\n (let ((p1 0.1049934947) (p2 0.0424060604) (p3 0.0072644182)\n       (p4 0.0005064034) (p5 0.0001789971) (q1 0.7715471019)\n       (q2 0.2909738639) (q3 0.0694555761) (q4 0.0140005442)\n       (q5 0.0008327945))\n   (let ((x2 (* x x)))\n     (let ((x4 (* x2 x2)))\n       (let ((x6 (* x4 x2)))\n         (let ((x8 (* x6 x2)))\n           (let ((x10 (* x8 x2)))\n             (let ((x12 (* x10 x2)))\n               (*\n                (/ (+ 1 (* p1 x2) (* p2 x4) (* p3 x6) (* p4 x8) (* p5 x10))\n                   (+ 1 (* q1 x2) (* q2 x4) (* q3 x6) (* q4 x8) (* q5 x10) (* 2 p5 x12)))\n                x)))))))))"
  },
  {
    "path": "infra/ci.rkt",
    "content": "#lang racket\n\n(require \"../src/utils/common.rkt\"\n         \"../src/core/points.rkt\"\n         \"../src/core/alternative.rkt\"\n         \"../src/api/sandbox.rkt\"\n         \"../src/syntax/read.rkt\"\n         \"../src/syntax/types.rkt\"\n         \"../src/syntax/platform.rkt\"\n         \"../src/syntax/load-platform.rkt\")\n\n(define *precision* (make-parameter #f))\n\n(define (test-successful? test input-bits target-bits output-bits)\n  (match* ((test-output test) (test-expected test))\n    [(_ #f) #t]\n    [(_ (? number? n)) (>= n output-bits)]\n    [('() #t) (>= input-bits output-bits)]\n    [(_ #t) (>= target-bits (- output-bits 1))]))\n\n(define (override-test-precision the-test repr)\n  (struct-copy test\n               the-test\n               [output-repr-name (representation-name repr)]\n               [var-repr-names\n                (for/list ([var (in-list (test-vars the-test))])\n                  (cons var (representation-name repr)))]))\n\n(define (run-tests . bench-dirs)\n  (activate-platform! (*platform-name*))\n  (define tests\n    (parameterize ([*default-precision* (*precision*)])\n      (append-map load-tests bench-dirs)))\n  (define seed (pseudo-random-generator->vector (current-pseudo-random-generator)))\n  (printf \"Running Herbie on ~a tests, seed: ~a\\n\" (length tests) seed)\n  (for/and ([the-test tests]\n            [i (in-naturals)])\n    (printf \"~a/~a\\t\" (~a (+ 1 i) #:width 3 #:align 'right) (length tests))\n    (define the-test*\n      (if (*precision*)\n          (override-test-precision the-test (get-representation (*precision*)))\n          the-test))\n    (define result (run-herbie 'improve the-test* #:seed seed))\n    (match-define (job-result _ test status time timeline profile warnings backend) result)\n    (match status\n      ['success\n       (match-define (improve-result _ start targets end) backend)\n       (match-define (alt-analysis start-alt start-error) start)\n       (match-define (alt-analysis end-alt end-error) (first end))\n\n       ;; Pick lowest target from all target\n       (define target-error\n         ; If the list is empty, return false\n         (if (empty? targets)\n             #f\n             (argmin errors-score (map alt-analysis-errors targets))))\n\n       (printf \"[ ~as]   ~a→~a\\t~a\\n\"\n               (~r (/ time 1000) #:min-width 7 #:precision '(= 3))\n               (~r (errors-score start-error) #:min-width 2 #:precision 0)\n               (~r (errors-score end-error) #:min-width 2 #:precision 0)\n               (test-name test))\n\n       (define success?\n         (test-successful? test\n                           (errors-score start-error)\n                           (and target-error (errors-score target-error))\n                           (errors-score end-error)))\n\n       (unless success?\n         (printf \"\\nInput (~a bits):\\n\" (errors-score start-error))\n         (pretty-print (alt-expr start-alt) (current-output-port) 1)\n         (printf \"\\nOutput (~a bits):\\n\" (errors-score end-error))\n         (pretty-print (alt-expr end-alt) (current-output-port) 1)\n\n         (when target-error\n           (printf \"\\nTarget (~a bits):\\n\" (errors-score target-error))\n           ;; internal tool so okay\n           (pretty-print (list-ref (test-output test) 0) (current-output-port) 1)))\n\n       success?]\n      ['failure\n       (define exn backend)\n       (printf \"[  CRASH  ]\\t\\t~a\\n\" (test-name test))\n       ((error-display-handler) (exn-message exn) exn)\n       #f]\n      ['timeout\n       (printf \"[  TIMEOUT]\\t\\t~a\\n\" (test-name test))\n       #f])))\n\n(module+ main\n  ;; Load all the plugins\n  (define seed (random 1 (expt 2 31)))\n  (set-seed! seed)\n\n  (command-line\n   #:program \"ci.rkt\"\n   #:once-each [(\"--seed\")\n                rs\n                \"The random seed to use in point generation. If false (#f), a random seed is used'\"\n                (define given-seed (read (open-input-string rs)))\n                (when given-seed\n                  (set-seed! given-seed))]\n   [(\"--egglog\") \"Switch to the egglog backend\" (enable-flag! 'generate 'egglog)]\n   [(\"--rival2\") \"Switch to the Rival 2 backend\" (enable-flag! 'setup 'rival2)]\n   [(\"--platform\") platform \"Which platform to use for tests\" (*platform-name* platform)]\n   [(\"--precision\") prec \"Which precision to use for tests\" (*precision* (string->symbol prec))]\n   [(\"--num-iters\")\n    num\n    \"The number of iterations to use for the main loop\"\n    (*num-iterations* (string->number num))]\n   [(\"--timeout\") s \"Timeout per test in seconds\" (*timeout* (* 1000 (string->number s)))]\n   #:args bench-dir\n   (exit (if (apply run-tests bench-dir) 0 1))))\n"
  },
  {
    "path": "infra/convert-demo-json.sh",
    "content": "#!/bin/bash\n\nif [ \"$#\" -ne 1 ]; then\n    echo \"Usage: supply the directory which contains the demo json files (v10.json, ect)\"\n    echo \"These files will be converted to fpcore and placed in bench/demosubmissions\"\n    exit 0\nfi\n\necho \"Converting user submitted data into benchmark suite\"\nif [ -d \"bench/demosubmissions\" ] ; then\n    rm -r \"bench/demosubmissions\"\nfi\n\nmkdir \"bench/demosubmissions\"\n\nfor f in \"$1\"/*.json; do\n    name=$(basename \"$f\" .json)\n    echo \"Converting $f\"\n    racket infra/convert-demo.rkt \"$f\" \"bench/demosubmissions/$name-unsorted.fpcore\"\n    racket infra/sort-fpcore.rkt \"bench/demosubmissions/$name-unsorted.fpcore\" \"bench/demosubmissions/$name.fpcore\"\n    rm \"bench/demosubmissions/$name-unsorted.fpcore\"\ndone\n"
  },
  {
    "path": "infra/convert-demo.rkt",
    "content": "#lang racket\n\n(require json)\n(require \"../src/core/programs.rkt\")\n\n(define op-map (make-hash `((expt . pow) (sqr . exp2) (abs . fabs))))\n\n(define version-10-constants (make-hash `((e . E) (pi . PI))))\n\n(define (format-op expr)\n  (if (equal? (first expr) 'cube)\n      (cons 'pow (append (rest expr) (list 3)))\n      (cons (hash-ref op-map (first expr) (first expr)) (rest expr))))\n\n(define (format-expr is-version-10 expr)\n  (match expr\n    [(? string?) (or (string->number expr) (raise (error \"string that is not a num\")))]\n    [(list op args ...) (format-op (cons op (map (curry format-expr is-version-10) args)))]\n    [(? symbol?)\n     (if is-version-10\n         (hash-ref version-10-constants expr expr)\n         expr)]\n    [else expr]))\n\n(define (read-expr expr-string is-version-10)\n  (format-expr is-version-10 (call-with-input-string expr-string read)))\n\n(define (make-fpcore expr)\n  (define vars (free-variables expr))\n  (format \"(FPCore (~a) ~a)\" (string-join (map symbol->string vars) \" \") expr))\n\n(define (convert-file file-name output-file existing-set is-version-10)\n  (define file-port (open-input-file file-name))\n  (define tests (hash-ref (read-json file-port) 'tests))\n  (define exprs-unfiltered\n    (for/list ([test tests])\n      (read-expr (hash-ref test 'input) is-version-10)))\n  (define exprs\n    (for/set ([expr exprs-unfiltered]\n              #:when (not (set-member? existing-set expr)))\n      expr))\n  (for ([expr (in-set exprs)])\n    (fprintf output-file \"~a\\n\" (make-fpcore expr)))\n  exprs)\n\n(define (convert-files json-files output-files expr-set is-version-10)\n  (unless (empty? json-files)\n    (define json-file (first json-files))\n\n    (define sub-path\n      (path-replace-extension (file-name-from-path (string->path json-file)) \".fpcore\"))\n\n    (define output-file (open-output-file (first output-files) #:exists 'replace))\n    (fprintf (current-output-port) \"Creating file ~a\\n\" (path->string sub-path))\n\n    (define new-expr-set\n      (set-union expr-set (convert-file json-file output-file expr-set is-version-10)))\n\n    (convert-files (rest json-files) (rest output-files) new-expr-set #f)))\n\n(module+ main\n  (define rebuilding? #f)\n  (command-line #:program \"convert-demo\"\n                #:args (input-json output-json)\n                (convert-files (list input-json) (list output-json) (set) #t)))\n"
  },
  {
    "path": "infra/convert-json.rkt",
    "content": "#lang racket\n\n(require json)\n(require \"../src/core/programs.rkt\")\n\n(define (fix-expr expr pre-fpcore?)\n  (let loop ([expr expr])\n    (match* (pre-fpcore? expr)\n      [(_ (? string?))\n       (or (string->number expr)\n           (raise-arguments-error 'fix-expr \"string that is not a num\" \"expr\" expr))]\n      [(#t (list 'expt (app loop a) (app loop b))) (list 'pow a b)]\n      [(#t (list 'cube (app loop a))) (list 'pow a 3)]\n      [(#t (list 'cot (app loop a))) (list '/ 1 (list 'tan a))]\n      [(#t (list 'sqr (app loop a))) (list '* a a)]\n      [(#t (list 'abs (app loop a))) (list 'fabs a)]\n      [(#t (list 'mod (app loop a))) (list 'fmod a)]\n      [(#t 'e) 'E]\n      [(#t 'pi) 'PI]\n      [(_ (list op (app loop args) ...)) (list* op args)]\n      [(_ _) expr])))\n\n(define (make-fpcore test pre-fpcore?)\n  (define expr (fix-expr (call-with-input-string (hash-ref test 'input) read) pre-fpcore?))\n  (define vars (map string->symbol (hash-ref test 'vars (λ () (map ~a (free-variables expr))))))\n  (define spec (fix-expr (call-with-input-string (hash-ref test 'spec (~s expr)) read) pre-fpcore?))\n  (define pre (fix-expr (call-with-input-string (hash-ref test 'pre \"TRUE\") read) pre-fpcore?))\n  `(FPCore ,vars\n           ,@(if (hash-has-key? test 'name)\n                 (list ':name (hash-ref test 'name))\n                 '())\n           ,@(if (not (equal? pre \"TRUE\"))\n                 (list ':pre pre)\n                 '())\n           ,@(if (not (equal? spec expr))\n                 (list ':spec spec)\n                 '())\n           ,@(if (hash-has-key? test 'prec)\n                 (list ':precision (string->symbol (hash-ref test 'prec)))\n                 '())\n           ,expr))\n\n(define (convert-files json-files pre-fpcore?)\n  (define seen (mutable-set))\n  (for ([json-file (in-list json-files)])\n    (define data (call-with-input-file json-file read-json))\n    (for ([test (hash-ref data 'tests)])\n      (define expr (make-fpcore test pre-fpcore?))\n      (unless (set-member? seen expr)\n        (set-add! seen expr)\n        (pretty-print expr (current-output-port) 1)\n        (newline)))))\n\n(module+ main\n  (define pre-fpcore? #f)\n  (command-line #:program \"convert-json\"\n                #:once-each\n                [(\"--pre-fpcore\") \"The demo file dates from before Herbie 1.0\" (set! pre-fpcore? #t)]\n                #:args json-files\n                (convert-files json-files pre-fpcore?)))\n"
  },
  {
    "path": "infra/coverage.rkt",
    "content": "#lang racket\n\n(require cover\n         json\n         racket/cmdline\n         racket/file\n         racket/format\n         racket/list\n         racket/path\n         racket/runtime-path\n         racket/set)\n\n(define-runtime-path here \".\")\n(define repo-root (simplify-path (build-path here \"..\")))\n(define main-file (simplify-path (build-path repo-root \"src\" \"main.rkt\")))\n(define src-dir (simplify-path (build-path repo-root \"src\")))\n(define default-seed \"1\")\n(define default-benchmark \"bench/hamming\")\n;; The full core RackUnit suite does not currently complete under `cover`;\n;; `bsearch` and `regimes` currently trigger `cover` internal errors.\n(define skipped-rackunit-coverage-files '(\"src/core/bsearch.rkt\" \"src/core/regimes.rkt\"))\n\n;; These core test modules were probed individually and completed cleanly\n;; in the merged tutorial run, so include them by default.\n(define stable-rackunit-coverage-files\n  '(\"src/core/arrays.rkt\" \"src/core/batch-reduce.rkt\"\n                          \"src/core/egg-herbie.rkt\"\n                          \"src/core/egglog-herbie-tests.rkt\"\n                          \"src/core/prove-rules.rkt\"\n                          \"src/core/test-rules.rkt\"))\n\n(define cover-namespace\n  (begin\n    (dynamic-require 'cover/cover #f)\n    (module->namespace 'cover/cover)))\n\n(define (cover-internal name)\n  (parameterize ([current-namespace cover-namespace])\n    (namespace-variable-value name)))\n\n(define current-live-files (cover-internal 'current-live-files))\n(define with-cover-loggersf (cover-internal 'with-cover-loggersf))\n(define make-cover-load/use-compiled (cover-internal 'make-cover-load/use-compiled))\n(define compile-file (cover-internal 'compile-file))\n(define run-file! (cover-internal 'run-file!))\n(define get-namespace/internal (cover-internal 'get-namespace))\n\n(struct file-summary (path relevant-lines covered-lines relevant-chars covered-chars) #:transparent)\n\n(define (collect-source-files)\n  (sort (find-files (lambda (path)\n                      (and (equal? (filename-extension path) #\"rkt\")\n                           (not (regexp-match? #rx\"/platforms/\" (path->string path)))))\n                    src-dir)\n        path<?))\n\n(define (collect-rackunit-files files)\n  (filter (lambda (path)\n            (and (regexp-match? #rx\"module\\\\+ test\" (file->string path))\n                 ;; The syntax/utils tests add useful coverage quickly and\n                 ;; reliably. Add the core modules that we have confirmed\n                 ;; behave well under merged coverage too.\n                 (or (regexp-match? #rx\"/src/syntax/\" (path->string path))\n                     (regexp-match? #rx\"/src/utils/\" (path->string path))\n                     (member (path->string (find-relative-path repo-root path))\n                             stable-rackunit-coverage-files))\n                 (not (member (path->string (find-relative-path repo-root path))\n                              skipped-rackunit-coverage-files))))\n          files))\n\n(define (normalize-rackunit-additions rackunit-additions)\n  (for/list ([path-string (in-list rackunit-additions)])\n    (simple-form-path path-string)))\n\n(define (path->coverage-key path)\n  (path->string (simplify-path path)))\n\n(define (benchmark-label benchmark)\n  (define path (simple-form-path benchmark))\n  (define name (path->string (file-name-from-path path)))\n  (if (equal? (filename-extension path) #\"fpcore\")\n      (path->string (path-replace-extension (file-name-from-path path) #\"\"))\n      name))\n\n(define (default-output-dir benchmark output-root)\n  (build-path output-root (format \"~a-run\" (benchmark-label benchmark))))\n\n(define (default-html-dir benchmark output-root)\n  (build-path output-root (format \"~a-html\" (benchmark-label benchmark))))\n\n(define (build-default-herbie-args benchmark output-root seed)\n  (list \"report\" \"--seed\" seed benchmark (path->string (default-output-dir benchmark output-root))))\n\n(define (with-coverage-runtime env source-files thunk)\n  (parameterize ([current-cover-environment env])\n    (define cover-load/use-compiled\n      (make-cover-load/use-compiled (map path->coverage-key source-files)))\n    (parameterize ([current-load/use-compiled cover-load/use-compiled]\n                   [current-namespace (get-namespace/internal)]\n                   [current-live-files #f])\n      (with-cover-loggersf thunk))))\n\n(define (run-benchmark-coverage source-files run-args)\n  (define env (make-cover-environment))\n  (with-coverage-runtime env\n                         source-files\n                         (lambda ()\n                           (compile-file (path->coverage-key main-file))\n                           (run-file! (path->coverage-key main-file) 'main run-args)))\n  (get-test-coverage env))\n\n(define (run-rackunit-coverages source-files test-files)\n  (printf \"Running RackUnit tests...\\n\")\n  (flush-output)\n  (for/fold ([coverages '()]\n             #:result (reverse coverages))\n            ([file (in-list test-files)])\n    (printf \"  RackUnit: ~a\\n\" (find-relative-path repo-root file))\n    (flush-output)\n    (with-handlers ([exn:fail? (lambda (e)\n                                 (printf \"Skipping RackUnit coverage for ~a\\n\" file)\n                                 (printf \"  ~a\\n\" (exn-message e))\n                                 (flush-output)\n                                 coverages)])\n      (define env (make-cover-environment))\n      (with-coverage-runtime env\n                             source-files\n                             (lambda ()\n                               (compile-file (path->coverage-key file))\n                               (run-file! (path->coverage-key file) 'test #())))\n      (cons (get-test-coverage env) coverages))))\n\n(define (covered-char-status coverage path pos)\n  (with-handlers ([exn:fail? (lambda (_) 'irrelevant)])\n    (coverage (path->coverage-key path) pos)))\n\n(define (merged-char-status coverages path pos)\n  (define statuses\n    (for/list ([coverage (in-list coverages)])\n      (covered-char-status coverage path pos)))\n  (cond\n    [(member 'covered statuses) 'covered]\n    [(member 'uncovered statuses) 'uncovered]\n    [else 'irrelevant]))\n\n(define (segment->jsexpr path segment)\n  (match-define (list status start end start-line start-col end-line end-col text) segment)\n  (hasheq 'file\n          (~a (find-relative-path repo-root path))\n          'status\n          (~a status)\n          'start\n          start\n          'end\n          end\n          'start-line\n          start-line\n          'start-column\n          start-col\n          'end-line\n          end-line\n          'end-column\n          end-col\n          'text\n          text))\n\n(define (collect-file-segments coverages path)\n  (define text (file->string path))\n  (define len (string-length text))\n  (let loop ([chars (string->list text)]\n             [pos 1]\n             [line 1]\n             [col 1]\n             [active #f]\n             [segments '()])\n    (define (finish active segments end-pos end-line end-col)\n      (match active\n        [#f segments]\n        [(list status start-pos start-line start-col chars)\n         (cons (list status\n                     start-pos\n                     end-pos\n                     start-line\n                     start-col\n                     end-line\n                     end-col\n                     (list->string (reverse chars)))\n               segments)]))\n    (match chars\n      ['() (reverse (finish active segments len line col))]\n      [(cons ch rest)\n       (define status (merged-char-status coverages path pos))\n       (define next-line\n         (if (char=? ch #\\newline)\n             (+ line 1)\n             line))\n       (define next-col\n         (if (char=? ch #\\newline)\n             1\n             (+ col 1)))\n       (cond\n         [(eq? status 'irrelevant)\n          (loop rest (+ pos 1) next-line next-col #f (finish active segments pos line col))]\n         [active\n          (match-define (list active-status start-pos start-line start-col active-chars) active)\n          (if (eq? status active-status)\n              (loop rest\n                    (+ pos 1)\n                    next-line\n                    next-col\n                    (list active-status start-pos start-line start-col (cons ch active-chars))\n                    segments)\n              (loop rest\n                    (+ pos 1)\n                    next-line\n                    next-col\n                    (list status pos line col (list ch))\n                    (finish active segments pos line col)))]\n         [else\n          (loop rest (+ pos 1) next-line next-col (list status pos line col (list ch)) segments)])])))\n\n(define (summarize-file coverages path)\n  (define text (file->string path))\n  (define relevant-lines (mutable-set))\n  (define covered-lines (mutable-set))\n  (define relevant-char-count 0)\n  (define covered-char-count 0)\n  (let loop ([chars (string->list text)]\n             [pos 1]\n             [line 1])\n    (match chars\n      ['()\n       (file-summary path\n                     (set-count relevant-lines)\n                     (set-count covered-lines)\n                     relevant-char-count\n                     covered-char-count)]\n      [(cons ch rest)\n       (define status (merged-char-status coverages path pos))\n       (unless (eq? status 'irrelevant)\n         (set-add! relevant-lines line)\n         (set! relevant-char-count (+ relevant-char-count 1))\n         (when (eq? status 'covered)\n           (set-add! covered-lines line)\n           (set! covered-char-count (+ covered-char-count 1))))\n       (loop rest\n             (+ pos 1)\n             (if (char=? ch #\\newline)\n                 (+ line 1)\n                 line))])))\n\n(define (summaries->totals summaries)\n  (for/fold ([relevant-lines 0]\n             [covered-lines 0]\n             [relevant-chars 0]\n             [covered-chars 0])\n            ([summary (in-list summaries)])\n    (values (+ relevant-lines (file-summary-relevant-lines summary))\n            (+ covered-lines (file-summary-covered-lines summary))\n            (+ relevant-chars (file-summary-relevant-chars summary))\n            (+ covered-chars (file-summary-covered-chars summary)))))\n\n(define (percent covered relevant)\n  (if (zero? relevant)\n      0.0\n      (* 100.0 (/ covered relevant))))\n\n(define (display-summary label summaries)\n  (define relevant-summaries\n    (filter (lambda (summary) (positive? (file-summary-relevant-lines summary))) summaries))\n  (define-values (relevant-lines covered-lines relevant-chars covered-chars)\n    (summaries->totals relevant-summaries))\n  (printf \"~a\\n\" label)\n  (printf \"  files with relevant coverage: ~a\\n\" (length relevant-summaries))\n  (printf \"  line coverage: ~a / ~a (~a%)\\n\"\n          covered-lines\n          relevant-lines\n          (~r (percent covered-lines relevant-lines) #:precision '(= 2)))\n  (printf \"  char coverage: ~a / ~a (~a%)\\n\"\n          covered-chars\n          relevant-chars\n          (~r (percent covered-chars relevant-chars) #:precision '(= 2)))\n  (printf \"  most uncovered files:\\n\")\n  (for ([summary (in-list (take (sort relevant-summaries\n                                      >\n                                      #:key (lambda (s)\n                                              (- (file-summary-relevant-lines s)\n                                                 (file-summary-covered-lines s))))\n                                (min 10 (length relevant-summaries))))])\n    (printf \"    ~a: ~a / ~a lines (~a%)\\n\"\n            (find-relative-path repo-root (file-summary-path summary))\n            (file-summary-covered-lines summary)\n            (file-summary-relevant-lines summary)\n            (~r (percent (file-summary-covered-lines summary) (file-summary-relevant-lines summary))\n                #:precision '(= 2)))))\n\n(define (detailed-report-path label output-root run-rackunit?)\n  (build-path output-root\n              (format \"~a-~a-coverage.json\" label (if run-rackunit? \"merged\" \"benchmark\"))))\n\n(define (write-detailed-report label output-root run-rackunit? summaries coverages)\n  (make-directory* output-root)\n  (define relevant-summaries\n    (filter (lambda (summary) (positive? (file-summary-relevant-lines summary))) summaries))\n  (define-values (relevant-lines covered-lines relevant-chars covered-chars)\n    (summaries->totals relevant-summaries))\n  (define out-path (detailed-report-path label output-root run-rackunit?))\n  (call-with-output-file\n   out-path\n   (lambda (out)\n     (write-json (hasheq 'label\n                         label\n                         'kind\n                         (if run-rackunit? \"merged\" \"benchmark\")\n                         'line-coverage\n                         (hasheq 'covered\n                                 covered-lines\n                                 'relevant\n                                 relevant-lines\n                                 'percent\n                                 (percent covered-lines relevant-lines))\n                         'char-coverage\n                         (hasheq 'covered\n                                 covered-chars\n                                 'relevant\n                                 relevant-chars\n                                 'percent\n                                 (percent covered-chars relevant-chars))\n                         'files\n                         (for/list ([summary (in-list relevant-summaries)])\n                           (define path (file-summary-path summary))\n                           (hasheq 'file\n                                   (~a (find-relative-path repo-root path))\n                                   'line-coverage\n                                   (hasheq 'covered\n                                           (file-summary-covered-lines summary)\n                                           'relevant\n                                           (file-summary-relevant-lines summary)\n                                           'percent\n                                           (percent (file-summary-covered-lines summary)\n                                                    (file-summary-relevant-lines summary)))\n                                   'char-coverage\n                                   (hasheq 'covered\n                                           (file-summary-covered-chars summary)\n                                           'relevant\n                                           (file-summary-relevant-chars summary)\n                                           'percent\n                                           (percent (file-summary-covered-chars summary)\n                                                    (file-summary-relevant-chars summary)))\n                                   'segments\n                                   (map (curry segment->jsexpr path)\n                                        (collect-file-segments coverages path)))))\n                 out))\n   #:exists 'replace)\n  out-path)\n\n(module+ main\n  (define html-output-dir #f)\n  (define output-root (build-path repo-root \"tmp-coverage\"))\n  (define run-label #f)\n  (define run-rackunit? #f)\n  (define rackunit-additions '())\n  (define seed default-seed)\n  (define benchmark default-benchmark)\n  (command-line\n   #:program \"coverage\"\n   #:once-each [(\"--benchmark\")\n                benchmark-path\n                \"Benchmark file or directory for the default Herbie run\"\n                (set! benchmark benchmark-path)]\n   [(\"--rackunit\") \"Run RackUnit test submodules before the benchmark run\" (set! run-rackunit? #t)]\n   [(\"--seed\") seed-value \"Seed for the default Herbie run\" (set! seed seed-value)]\n   [(\"--output-root\") dir \"Directory for coverage HTML and report output\" (set! output-root dir)]\n   [(\"--html\") dir \"Directory for HTML coverage output\" (set! html-output-dir dir)]\n   [(\"--label\") label \"Label to print for this run\" (set! run-label label)]\n   #:multi [(\"--rackunit-add\")\n            path-string\n            \"Add a RackUnit file to the default stable subset\"\n            (set! rackunit-additions (cons path-string rackunit-additions))]\n   #:args herbie-args\n   (define effective-run-label (or run-label (benchmark-label benchmark)))\n   (define effective-html-dir (or html-output-dir (default-html-dir benchmark output-root)))\n   (define effective-herbie-args\n     (if (null? herbie-args)\n         (build-default-herbie-args benchmark output-root seed)\n         herbie-args))\n   (make-directory* output-root)\n   (define source-files (collect-source-files))\n   (define default-test-files (collect-rackunit-files source-files))\n   (define test-files\n     (remove-duplicates (append default-test-files\n                                (normalize-rackunit-additions rackunit-additions))))\n   (define run-args (vector->immutable-vector (list->vector effective-herbie-args)))\n   (define benchmark-coverage (run-benchmark-coverage source-files run-args))\n   (define coverages\n     (if run-rackunit?\n         (cons benchmark-coverage (run-rackunit-coverages source-files test-files))\n         (list benchmark-coverage)))\n   (define summaries (map (curry summarize-file coverages) source-files))\n   (define relevant-files\n     (for/list ([summary (in-list summaries)]\n                #:when (positive? (file-summary-relevant-chars summary)))\n       (path->coverage-key (file-summary-path summary))))\n   (when effective-html-dir\n     (if run-rackunit?\n         (printf \"Skipping HTML output for merged benchmark+RackUnit coverage.\\n\")\n         (begin\n           (make-directory* effective-html-dir)\n           (generate-html-coverage benchmark-coverage relevant-files effective-html-dir))))\n   (define report-path\n     (write-detailed-report effective-run-label output-root run-rackunit? summaries coverages))\n   (printf \"Detailed report: ~a\\n\" report-path)\n   (display-summary effective-run-label summaries)))\n"
  },
  {
    "path": "infra/diagrams/.gitignore",
    "content": "*.png\n"
  },
  {
    "path": "infra/diagrams/1.5/herbie-system.drawio",
    "content": "<mxfile host=\"Electron\" modified=\"2022-05-23T20:11:07.584Z\" agent=\"5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/18.0.6 Chrome/100.0.4896.143 Electron/18.2.3 Safari/537.36\" etag=\"FttMo2tG1ugIgM2fdEyi\" version=\"18.0.6\" type=\"device\"><diagram id=\"PBjobV1qK8d18Rz6RHWu\" name=\"Page-1\">7V1Zk5u4Gv01XZV5MMUisTymlyz3JreS9OROkpcpbMtuJhg8gNP2/PqRQAJt3gHTXd2VqhgBAh+db9Un+cq5WazfZuHy4WM6RfGVbU7XV87tlW1bwDbxf6RlU7V4ll01zLNoSi9qGu6jfxBtpPfNV9EU5cKFRZrGRbQUGydpkqBJIbSFWZY+ipfN0lh86jKcI6XhfhLGausf0bR4oK2WaTYn3qFo/kAf7UN6YhGyi2lD/hBO00euybm7cm6yNC2qT4v1DYoJeAyX6r43W87WL5ahpDjkhm/5z+jH7fJv387/caP1w+T9/1+PHLfq5lcYr+g3pm9bbBgEWbpKpoj0Yl05148PUYHul+GEnH3Eg47bHopFTE/nRZb+RDdpnGbl3Y4VmOYb/E7XsyiOufY35R9uV78H/Wq/UFagNddEv9dblC5QkW3wJfSsHVCMGclMWB0/NkPm+PSaB2606mEMKU3mdd8NkvgDBVMPrDv69uPd15l3E73P8+9m9vP7fTaCoGVgZ2lSUPGwgA5o07wB5ZkWAPU9AwqIWoGKaGBrEAVuC4jqqWppEHXjgmCxDBMBWvfvFRGr60kFz2t8MpuPw1f43fA//HxT++k38pEAaBK0R7NwEcWb6vZFmqR5OTjCJXk5IuQCc7lunos/zav/oawbIf7KpLUU/PqIQQBLEHDLLflMXgySrwkxcvuutepr2dif1I3ddFMhXZ9ZplFS5M3pCu76NEqmr4nCLVsmcZjn0YR8rkhMGq3ykLGetJhlC1pHxbfq2PBg3fRduuR2LTdsuIbmvdB0zr3WDljqUzUijSRARvX6atigyBivPZehOCyiX/pXCPOmec49THiLTwTo8vJ1czVwA8MDTU8b7hT/eP4JebrKJqjuTmWA/kmeadj6JznelicVYTZHxdYnlYcCvOIJykS+UZQP1oEsSJX8Y31SqQAmda1asCC4uWnLUlmWqFcdjV7VWiobdGWpAqdDS2XrAL3DcAKzHUAlyw80ZopB3o/hB37XHlWbfITmAXwEGgC746Nq5u+jxTKOZpsdOJr7cWwDLUdiGwBG4KqM0/lFnfENKnhl6DHDUOQKXsQy3tPDNCse0nmahPFd03otItpc8yFNlxTHv1BRbKh8h6siFVGubDm15MyOV71RG84dbNhBgpGo7vJdjzWU9xlBELCG5ubySLj7E8oiDCjKaOPW0a5s4g5AqbiWXsQuTtR2Xgg5NcNLb6XGkXHJMy1DFj4X0wkGzZ/Yp2BjJdbU73U6kWyFR1/QZJXlpStT2dlxxkzsl4piF5dI17GlSAXoTECfAqma09/DDVHeCoh3a+y0TC+OoecMDEE1dP6C5li6VQTfJzOEv/nk8kT0PQVEwwSXxVHN7XwMoyQmqvzScFm2pPpslXOur/E7OgNLddvu1kUWToooTS4Ol8wuHVy9UotlcTm4PsWreUTSMO8TbIZn4QCEUvZubUuFzXJ6xU2XFqy0WsSU2jLNo4ILbaMmrnXDBUEpGefkvyVF/MIoA19E2dOAbPYKsuoSKyDV2SrnNkkT4vpOw/yhjsk4hEj7p7DAnE7KFtt06qiMTQnYiuu8Fde9fiUHG9SgxtrOdD9hIA4aO2Q9CKkjm5tVkPpxnd39dO20espQhzF5vSIcx6oC4kadZSiFsRbHkMUyLK6pAhIW1uwLZcQwBu4JYrbyZW+8Qq18BfR+AzcQ/vkS/4BzIgEDIJlG/zAGYh6EG+4ylt1un6OaiQu0Xmaa8PwkdpqGzUfa1oH0pHfVDO2Mn/6B/ASD4qcHWuKnF5zGz9bYp3pqk3QxjhIyBSPHU4SXrdHytASQJ9DS6oyW4EmqzWdDS6BXiueSr+GR5XvH6LfjkohDYQOEhuWJ4+ieSggIjCBQko9yTqgveqhaC5XZMqK1noN+GgiDfHNL7u9Y+sgdKTzsmjBq2vVFnxzLBhfahuuZ9Z/Vjmoh3e6hWcfsgLqMQOX8kNlqgSKshkeq77F8XYHPO5SNI8Qla6ruttQhFGhd7JrcpZkIvlKONoVxNCfphwlKSjpdk/RMNAnj1/TEIppOyxk8Xb5HJLVcSVYe05e0t1L0mBoHcZbU1uV2NSR2OsuDH1DhcJxekEscGqNyuE3ZivShEdVQlIbsSZqnRvK2yJueU0mumppNV8VyRd6QmJJX+W8qa/AQfAjHKBbJcri0ZghrmDJVVZGCZiFw5/D6Ct5qqKbSZjfnZbGtS6XpU6/4amSdOJsGsFzRyWQ1GmcyZyTaF1+8P53NctTNSKvWYOsAv7gL28cPQvw9d7gLTXHMsaoAQlEV8IU2fakDdUIwJ3VI6JkkSAbCIdfcP9IH+5lSXzoGdswaz1RYc0c+hwOolbGgaKihq/pl9bqbXibqPDXKz9DfK5QXamqylL0F/vahdkb+TP+NU9zQFeTLMJ19MqZV3pxL6AtybpjA3i3r+KC9crZDp4fYjP5A9AJUCkQkEh5sSoBoluyeQ0+vx+DDr48F6vbEtIExSLYGysAfbFYsybGxe2aQJjBZoiwsUjKHeKOqymwVoy1n0BJHHEyJ6guEhxnPeK3FMyPTwDGrSI3zCMfiVfGG7uIXTy166EylnOSi9jSFNzCFAyX/yj41EQKlmpp60VD7CueP2Y/5/eR9YK7fWh/tD9efN5OvI6bvOH5hpyxT11/0oC4OVQ9MJFpRD740AKym++x8h2iRRr1lPHxVY3zKVsnlYxLbk8O//gpbtauM1dTQhxQzl+jGS2Mlx28Xx0ol1X1IorSLI+X4+5HqrCRVC5WaTGq/TPGohNLpVpfpkoFYXUdKFcJTK1kdxxc66nAGW0uRQEeRs4sEW6/3218wNSx+2Gx987mz2ECKJ6FcetUxPzRLLs4kx2Fe/+4UwlaeDGX4pbqU4MQ0ktxPh0kA/eiri7mipJmc1Eb7ONbHzu800idML+G77yZ2K757YLXjrOsjgFZddT0aWjswODMwEPG2PCiVFp2s3y11BWevEs4S3NzAxzj02JKou6CHOJChl0X05NJF3NE+DnU99KppR3h0s5dh3z/s8FR5V4cddFcDrx92TR3Ky7Bvic4sYLQ08I514WFXXblJmp9t4p/lqAOzpTEH5qWFXU0BvRSoH638/WBHgboypAebAtztHuXSNTtUrz9fjdsliOMHPEFGpBLlOZJEceRPpQUJLhx325Io6DoGMBUu9kQYzbLOo1c0AN2Kht+11VdPcIVDmysa5FBDt79wRysa9KOvqwDgR18ctfPWuHyIxlmYRaSkZAsJXtiya07TY9O+/OwT0NBFTim2RhfN4rjBbZ1MT43Dyc95OT4j8Q1e2WRnTfo4GwTNZ0ge/qx3XkbVTlTlpsn0Cnnz5Tqbq9lxuRKWclvmSlxIoygw5CQVmXKP5jq322ywXG//XD4SEoThbXmmnkcoH2lL2zFTwdGhxad3NZApaNa3OtoNm7mHwKD09zVbGLsediG5P++wzZk1uxl3vGlxz7uBeI4QPRimWRdG97PvpmZ+8cf8f4/Jn7++/7WJ3iSfv3z87+v/rEbDcjZxoGCIi6OADwzAOYZsgf65a2C87uYbV2/M1S/z82Ix+/PHne2i2edZrNk9UB+ODGYeCbS45M1id7a7xA1KQ9jdNBJQi4bP1DD8bLEvKo/jliRxmaqqo2ZlRLm1Wgf16rsUyf6VEcNSOAAYLtiWAvGc9pZPQa8zhaMdD1XhVAvudKnR4SgdJmdtTF5DCMQapHMX2vagZw7Y7v5lrrpyDCw5B316LZJUSdzhXLW+Qly1Lk+9CqUmchuCbPrWmZLb4Zp4/ddXE9Dcjogv01Ki+MHqt3h2SeDBouxWv7azSy10nEtmqBwkzfVLDEnD8z6c/ivawyKQYgpOnqQApmtI6ekOI8Wd4PIb9kf4QKHJpdcB1MBcbB0AVDOxVbZTlbQiW5GfHxuQ9uUjqichZaqaPrmAQKOmO6wg0Dtd27P4503wfM1JTvjJTdn0uIUZ265sD2/bmO/blargDfR8fnH1Ku/R0Kt61eKkC0bbmBR/ixKy4F7zCzRPUG5alBMvkOVEFZSuJsb1gqK6ssrva4yjJMw2ZLs33U9snCNTwk9ItACvLf3eXJ0/vpiAaZaGb8HXsYePr+P2h+8VnR3kXIJmXtC5+xc=</diagram></mxfile>"
  },
  {
    "path": "infra/diagrams/1.6/herbie-system.drawio",
    "content": "<mxfile host=\"Electron\" modified=\"2022-05-23T20:05:01.528Z\" agent=\"5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/18.0.6 Chrome/100.0.4896.143 Electron/18.2.3 Safari/537.36\" etag=\"7mkmWcSHHO1kdvKKE_hv\" version=\"18.0.6\" type=\"device\"><diagram id=\"PBjobV1qK8d18Rz6RHWu\" name=\"Page-1\">7V1bj5u6Fv41I3U/TGQuhvDYufQitVLbac9u+3LEJE6GUwIpkE6yf/3GYAO2FwlDgDBzMqrUYMDAWp/X3faFcb3avo3c9cPHcE78Cx3NtxfGzYWuaxiZ6X+0ZZe32Jg1LCNvzi4qG+68fwhrRKx1481JLFyYhKGfeGuxcRYGAZklQpsbReGjeNki9MWnrt0lURruZq6vtv7tzZMH1qohVJ54R7zlA3v0FLMTK5dfzBriB3cePlaajNsL4zoKwyT/tdpeE58Sj9Mlv+9NzdnixSISJE1u+B7/8n7erH9P9fgfy9s+zN7/5/WlYeXd/HH9Dfti9rbJjpMgCjfBnNBetAvj6vHBS8jd2p3Rs48p09O2h2Tls9NxEoW/yHXoh1F2t6E5CL1J3+lq4fl+pf1N9pe2q9/BPu0PiRKyrTSx73pLwhVJol16CTurO4zGHGQI58ePJctMm13zUOFWwUaXwWRZ9F1SMv3BiAkT1rr8/vPdt4V97b2P4x8o+vXjLrrkMO+MsIswSNjw0EyI0Ahdm9mZDggq0VNzVHo6OkBP0+qAnjBQNYCelp9QSqzdQCCs9XtDB9XVLCfO6/RktLx3X6Xvlv5Ln4/AX3/Rn5R8iNL6cuGuPH+X374KgzDOWCNcEmf8oBeg9bZ8bvprmf+PZcmI00+mrdmwL444CXBGhLTlhv6mL4bpZ+KUcoeu1YprOedbdaOX3eSULs6sQy9I4vJ0Tu7iNAnmr6m4zVpmvhvH3oz+ziFMG7XskGOetqCshWy95Ht+PLFx0fRDuuRmKzfsKg3le5H5svJae8hSnCooUo4DzKFeXI1LKnLEg+ci4ruJ9wd+BTcum5eVhwlv8YkSOrt8W15tWs7ENsuedpVT1cdXnxCHm2hGiu5UBMBPstFEh59k2DVPStxoSZLaJ2WHAnnFEwyJ1UZxfPAO5IGUj/9UnuQigI+6TvWX41xfd6WnNA0LctUA5KoxBeSqbvalpxyjRz2lQwS9Tclpol70lAmoKU7yYdS+Oe3bnuoSjxg1wCMGCNgfHlU1f+et1r632O2hIzpMxy6oJY1ebAFwg4yi3sCGFWJF5DFK6RArxKJq8Y4dhlHyEC7DwPVvy9YrkZzlNR/CcM2I+D+SJDs2uN1NEookzhU5U+Nciee9MQVeOdixg1q+5Nprz9ezgZXp+33cKzSy4BoCvGC3MjXGuW4jXZQxUyx2ISg/iaPFa7Rnsq7w+AuZbaI4szFyBXgfcd33JWf/yYeKZYxsqKha7qu7ozJVIeHtNrUl5ienoI1HRkHVn/1Clt4KAOH7YEHSL5+dHoZTWySiCRkIQxJRFdif3GSWuhnoq3vvn55gsoqDCGYYQ1JMjU99dL3Apzrp1MTSdMl60lViWXhIYqnG5+02idxZ4oXBycklD0aIXIMORh5iBkJKHpdl917gRjvLrPiaXuloWu6K0im4j+l/a3+z9E5PZ8MS6WyrZC78n2HorJownxip0PsgIdHCHYGukH0hXQPoNqjo0yDXHMSnoT8jfBYG9GjwCYXqJTqvw9hLnhGRZQP89ERWTR+FSEUM2bgJwoD6pHM3figiJRUK0fbUckplR5C16MgoYiU8TacrPm0tXQ/6kBWyQQqdtx3pamJHZJojeZpCQLfkh9KPzHy5n749VpXV8eaebNfRPo7znIHAZ5F/KduiXR5hMKYOb8hiDBOk8eMyzpAd7apHn0iUuiwpbA4hIifRYUt+JMixTEPgeGEDPBU6WK9xAIbCjq1gx/WTjCGQf/RE/LAAFQ9W5cjhsSo4PlViTsQbPgC3WmQdjGtZDRE4HRUCp5LsMo2WCHRMyU1oGG9LceDuKpfxfGVtXE92R9hzS0DnPXYKbyCLTeUiEK5tBWw00auRV60hstldBbh7g/a0IbTNUUHbNjuCtu20g3Zn6FMdsVm4Sl0Imo+Xo3hd6Os2CYEKLG0BlocUfHtYms9S4r4YWJqwUDwWfCWOtKn9FPn2NEtxLGiw8USzRUDIfGwMCNucONU/oVss25Z9w0OVWiTL0VCp9RLk00gQNJVMf4XPTeEjdzR0xtRU42ZnefJUNFiYyhNU/GndiBarLq05EDawGpvgpg8tXBIAwss5pVJPbQrVer4j0b1HKhHCvLuakrSEbJOLPXU+LPxVLZlmTa7vLWnMa0aCDExXNCbozVz/NTux8ubzrJ4DCjKKkJZLirNj9pJ6LUCfUu4mlmfpUIIMgLDRVxDSalDs9jSpIFe7lSpliBKYcRmklmxHorYhAF3EzcDxS0vNB4SbZL2hb0gVyav4LxU1KQs+uPfEF8HSfLRGJJUwWYwrBwULX6Sd46sLfANATYXNfszLw7aYM8OeelGdlgINZzQxNUs0MXm53pHIuRS1y1S8P1wsYtIPp1VtUMvgs7FQzz9s9GIs4LoqsqEEgVpPEdNiVPJCAiNjQc+0I8dD7mhox4PPMKvW39Df7ggqMrUG9YTFpMtBMsK26tdH5PeGxIkajMxG3Sr9ehcsZTrSZqsIa2wJI2uCjFZ5xXKAW5olZJvQgaB8etBY+neWSuIVOmMRCEphnYTBxgLBFDWRPnA20x7Q35gWxwJyB0LayBBkIbSf8Y3jFZqIoKJocSgEAb7ImkRuEtKk4bUqKaONT2rOkHXqZHAZCs8QGacLY3fmwlyiSeqmitA4DnDcRRVv6M9lsaEAVl/q8Elm5rChDy5wDus2NCrJJOs2vW2QBEv1C4WBN5RkUit1etNtrZykgZLHzYFojAuIuCsgSl661p+K/Hvxc3k3e++g7Vvto/7h6vNu9u2Sa+gKEFMvIlLniw6g4JoqND52OlFoU4kBfLJbW4AMoMQazJI+KzGgRH0kssOSAvStZYdsp/coO+AEiqrEPkWb4PThGt0WCTPkzEVw/Z365Xca501NKG/6lgTUnQGmkT7DXGqHuVNZq5rAklbQbKQucqcgAFRHdE2nrkJLDbSMhVuGcbpQ2bjq+W3dFLkvs7VxKZfUkTIxoDsBC6JG9VY/hOkAo0Lh1CJWjoifXMSquujOpXHvk1PKkPMqAKV6m00Gkkq1H7ufJTLQMibcBBmJ5DGwaHjgtpPQDGN6UsnjQBA5Wll1PmficNH5uPChOx3NNDMl0x/L5es94wOYlX4kOJrFr/YbNbU4GQv7pVnyTku7RO6nx7wKzH11XREvKEu8wATKOiKzMJh7cAr6FMGl/cDuJLjkaEdGk7g/I7Cbh6g6DTXB1AD1wOjUwEiGt2bjiTQw28p3rW7tpYFGOA9RVRjvp65HTe7zhBbiSFgvD1GFX41Fu34QQ32zXlXtJOVudGb7Yba3Lr5T2d5j+R3MdqCa98z2Gu9MMycdMd6Q14wbmu2qKTcL46NV/Ivkuok64rmJTj3Y1RDQeZLfk4X/1JlY3dft024Hq9yH0aFa/X0vQZQ6S8h8iSBRDPm2sKDOhWHVTys3JiZSsDgQYIClMbrJb34F69n/v3Ob8sKpJ89tGlAtW5X7IteOmyn8wbuP3MijidMaEJzRsq8UwuYVndXskwnARQ4pdpcKBxYsWS4Vdpx68WbbUIeVDm2H0VuaDliJYXSbNrFT9+7s1zLj2KX4Bq90uqcHe5xuOuVvTB/+ovd8Ivnq0dl2TewKedunIuwN7PWUS5VsQ6hcrtBGUbLQk0y2ZLtDFUHwcmunYuOp7JGYUhjfZGeKhEv2SF3aCIoNHIha1Tg4QDKFmsWtBSHL0SfunoSdzDECNk+y7NTWrvzZzbaFAvZR6nm7pKcZxGO3XrFh7nFxrK6Knu3+spebN2jzB31erRb//XmrW2TxeeEDy+LDzs1oslJmh8sQaPzOUVQ4w5+rlssdOdCq2eWp6Ik+bTp4GdkyhCmD1IHtq+Rurxl1uPp5XBJlKlZA2LL51Lb4uZjRM5AMAdY9z5c3gIKn4xEk/K27SG+nnqg+elHS+WSJF5u+NjU5LN2+PElau6rH9DU8q0kdnM+9MKUAchcjF021I40Axtg+FhuCP1+NSZdrVJ8zVdLww/l+t/tGYOOhbOU72u4TC32XwavFKPWjuXiJMUn4qpEGf6I+LgApqqB13sJE1kQfzN3bS9zq7nteeqDA5NRTA6CY47BTA7Aac8zjeupIS6IN3eJ7RNL3oM80tlGmiunWNQWAmO6xqAA2uurj1cflfL7FNPr57LI4A64Ny9eBPYDbLlKAsDNcvzDwOVVxTlWcUxX6OVXRszK1sDVBjiQVW6+zbk34xgknSlEAU2zGk6PYrwNeXI4C/txeV3B6FjmKkYx8GxkTs3bDFdswJ47VTg7Qnh1RDigypW85oMav/7iR54KRr/HIgi6XaDptmuGCKd3K5aW6NW7/BQ==</diagram></mxfile>"
  },
  {
    "path": "infra/diagrams/1.6-changes/herbie-system.drawio",
    "content": "<mxfile host=\"Electron\" modified=\"2022-05-23T20:05:01.528Z\" agent=\"5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/18.0.6 Chrome/100.0.4896.143 Electron/18.2.3 Safari/537.36\" etag=\"7mkmWcSHHO1kdvKKE_hv\" version=\"18.0.6\" type=\"device\"><diagram id=\"PBjobV1qK8d18Rz6RHWu\" name=\"Page-1\">7V1bj5u6Fv41I3U/TGQuhvDYufQitVLbac9u+3LEJE6GUwIpkE6yf/3GYAO2FwlDgDBzMqrUYMDAWp/X3faFcb3avo3c9cPHcE78Cx3NtxfGzYWuaxiZ6X+0ZZe32Jg1LCNvzi4qG+68fwhrRKx1481JLFyYhKGfeGuxcRYGAZklQpsbReGjeNki9MWnrt0lURruZq6vtv7tzZMH1qohVJ54R7zlA3v0FLMTK5dfzBriB3cePlaajNsL4zoKwyT/tdpeE58Sj9Mlv+9NzdnixSISJE1u+B7/8n7erH9P9fgfy9s+zN7/5/WlYeXd/HH9Dfti9rbJjpMgCjfBnNBetAvj6vHBS8jd2p3Rs48p09O2h2Tls9NxEoW/yHXoh1F2t6E5CL1J3+lq4fl+pf1N9pe2q9/BPu0PiRKyrTSx73pLwhVJol16CTurO4zGHGQI58ePJctMm13zUOFWwUaXwWRZ9F1SMv3BiAkT1rr8/vPdt4V97b2P4x8o+vXjLrrkMO+MsIswSNjw0EyI0Ahdm9mZDggq0VNzVHo6OkBP0+qAnjBQNYCelp9QSqzdQCCs9XtDB9XVLCfO6/RktLx3X6Xvlv5Ln4/AX3/Rn5R8iNL6cuGuPH+X374KgzDOWCNcEmf8oBeg9bZ8bvprmf+PZcmI00+mrdmwL444CXBGhLTlhv6mL4bpZ+KUcoeu1YprOedbdaOX3eSULs6sQy9I4vJ0Tu7iNAnmr6m4zVpmvhvH3oz+ziFMG7XskGOetqCshWy95Ht+PLFx0fRDuuRmKzfsKg3le5H5svJae8hSnCooUo4DzKFeXI1LKnLEg+ci4ruJ9wd+BTcum5eVhwlv8YkSOrt8W15tWs7ENsuedpVT1cdXnxCHm2hGiu5UBMBPstFEh59k2DVPStxoSZLaJ2WHAnnFEwyJ1UZxfPAO5IGUj/9UnuQigI+6TvWX41xfd6WnNA0LctUA5KoxBeSqbvalpxyjRz2lQwS9Tclpol70lAmoKU7yYdS+Oe3bnuoSjxg1wCMGCNgfHlU1f+et1r632O2hIzpMxy6oJY1ebAFwg4yi3sCGFWJF5DFK6RArxKJq8Y4dhlHyEC7DwPVvy9YrkZzlNR/CcM2I+D+SJDs2uN1NEookzhU5U+Nciee9MQVeOdixg1q+5Nprz9ezgZXp+33cKzSy4BoCvGC3MjXGuW4jXZQxUyx2ISg/iaPFa7Rnsq7w+AuZbaI4szFyBXgfcd33JWf/yYeKZYxsqKha7qu7ozJVIeHtNrUl5ienoI1HRkHVn/1Clt4KAOH7YEHSL5+dHoZTWySiCRkIQxJRFdif3GSWuhnoq3vvn55gsoqDCGYYQ1JMjU99dL3Apzrp1MTSdMl60lViWXhIYqnG5+02idxZ4oXBycklD0aIXIMORh5iBkJKHpdl917gRjvLrPiaXuloWu6K0im4j+l/a3+z9E5PZ8MS6WyrZC78n2HorJownxip0PsgIdHCHYGukH0hXQPoNqjo0yDXHMSnoT8jfBYG9GjwCYXqJTqvw9hLnhGRZQP89ERWTR+FSEUM2bgJwoD6pHM3figiJRUK0fbUckplR5C16MgoYiU8TacrPm0tXQ/6kBWyQQqdtx3pamJHZJojeZpCQLfkh9KPzHy5n749VpXV8eaebNfRPo7znIHAZ5F/KduiXR5hMKYOb8hiDBOk8eMyzpAd7apHn0iUuiwpbA4hIifRYUt+JMixTEPgeGEDPBU6WK9xAIbCjq1gx/WTjCGQf/RE/LAAFQ9W5cjhsSo4PlViTsQbPgC3WmQdjGtZDRE4HRUCp5LsMo2WCHRMyU1oGG9LceDuKpfxfGVtXE92R9hzS0DnPXYKbyCLTeUiEK5tBWw00auRV60hstldBbh7g/a0IbTNUUHbNjuCtu20g3Zn6FMdsVm4Sl0Imo+Xo3hd6Os2CYEKLG0BlocUfHtYms9S4r4YWJqwUDwWfCWOtKn9FPn2NEtxLGiw8USzRUDIfGwMCNucONU/oVss25Z9w0OVWiTL0VCp9RLk00gQNJVMf4XPTeEjdzR0xtRU42ZnefJUNFiYyhNU/GndiBarLq05EDawGpvgpg8tXBIAwss5pVJPbQrVer4j0b1HKhHCvLuakrSEbJOLPXU+LPxVLZlmTa7vLWnMa0aCDExXNCbozVz/NTux8ubzrJ4DCjKKkJZLirNj9pJ6LUCfUu4mlmfpUIIMgLDRVxDSalDs9jSpIFe7lSpliBKYcRmklmxHorYhAF3EzcDxS0vNB4SbZL2hb0gVyav4LxU1KQs+uPfEF8HSfLRGJJUwWYwrBwULX6Sd46sLfANATYXNfszLw7aYM8OeelGdlgINZzQxNUs0MXm53pHIuRS1y1S8P1wsYtIPp1VtUMvgs7FQzz9s9GIs4LoqsqEEgVpPEdNiVPJCAiNjQc+0I8dD7mhox4PPMKvW39Df7ggqMrUG9YTFpMtBMsK26tdH5PeGxIkajMxG3Sr9ehcsZTrSZqsIa2wJI2uCjFZ5xXKAW5olZJvQgaB8etBY+neWSuIVOmMRCEphnYTBxgLBFDWRPnA20x7Q35gWxwJyB0LayBBkIbSf8Y3jFZqIoKJocSgEAb7ImkRuEtKk4bUqKaONT2rOkHXqZHAZCs8QGacLY3fmwlyiSeqmitA4DnDcRRVv6M9lsaEAVl/q8Elm5rChDy5wDus2NCrJJOs2vW2QBEv1C4WBN5RkUit1etNtrZykgZLHzYFojAuIuCsgSl661p+K/Hvxc3k3e++g7Vvto/7h6vNu9u2Sa+gKEFMvIlLniw6g4JoqND52OlFoU4kBfLJbW4AMoMQazJI+KzGgRH0kssOSAvStZYdsp/coO+AEiqrEPkWb4PThGt0WCTPkzEVw/Z365Xca501NKG/6lgTUnQGmkT7DXGqHuVNZq5rAklbQbKQucqcgAFRHdE2nrkJLDbSMhVuGcbpQ2bjq+W3dFLkvs7VxKZfUkTIxoDsBC6JG9VY/hOkAo0Lh1CJWjoifXMSquujOpXHvk1PKkPMqAKV6m00Gkkq1H7ufJTLQMibcBBmJ5DGwaHjgtpPQDGN6UsnjQBA5Wll1PmficNH5uPChOx3NNDMl0x/L5es94wOYlX4kOJrFr/YbNbU4GQv7pVnyTku7RO6nx7wKzH11XREvKEu8wATKOiKzMJh7cAr6FMGl/cDuJLjkaEdGk7g/I7Cbh6g6DTXB1AD1wOjUwEiGt2bjiTQw28p3rW7tpYFGOA9RVRjvp65HTe7zhBbiSFgvD1GFX41Fu34QQ32zXlXtJOVudGb7Yba3Lr5T2d5j+R3MdqCa98z2Gu9MMycdMd6Q14wbmu2qKTcL46NV/Ivkuok64rmJTj3Y1RDQeZLfk4X/1JlY3dft024Hq9yH0aFa/X0vQZQ6S8h8iSBRDPm2sKDOhWHVTys3JiZSsDgQYIClMbrJb34F69n/v3Ob8sKpJ89tGlAtW5X7IteOmyn8wbuP3MijidMaEJzRsq8UwuYVndXskwnARQ4pdpcKBxYsWS4Vdpx68WbbUIeVDm2H0VuaDliJYXSbNrFT9+7s1zLj2KX4Bq90uqcHe5xuOuVvTB/+ovd8Ivnq0dl2TewKedunIuwN7PWUS5VsQ6hcrtBGUbLQk0y2ZLtDFUHwcmunYuOp7JGYUhjfZGeKhEv2SF3aCIoNHIha1Tg4QDKFmsWtBSHL0SfunoSdzDECNk+y7NTWrvzZzbaFAvZR6nm7pKcZxGO3XrFh7nFxrK6Knu3+spebN2jzB31erRb//XmrW2TxeeEDy+LDzs1oslJmh8sQaPzOUVQ4w5+rlssdOdCq2eWp6Ik+bTp4GdkyhCmD1IHtq+Rurxl1uPp5XBJlKlZA2LL51Lb4uZjRM5AMAdY9z5c3gIKn4xEk/K27SG+nnqg+elHS+WSJF5u+NjU5LN2+PElau6rH9DU8q0kdnM+9MKUAchcjF021I40Axtg+FhuCP1+NSZdrVJ8zVdLww/l+t/tGYOOhbOU72u4TC32XwavFKPWjuXiJMUn4qpEGf6I+LgApqqB13sJE1kQfzN3bS9zq7nteeqDA5NRTA6CY47BTA7Aac8zjeupIS6IN3eJ7RNL3oM80tlGmiunWNQWAmO6xqAA2uurj1cflfL7FNPr57LI4A64Ny9eBPYDbLlKAsDNcvzDwOVVxTlWcUxX6OVXRszK1sDVBjiQVW6+zbk34xgknSlEAU2zGk6PYrwNeXI4C/txeV3B6FjmKkYx8GxkTs3bDFdswJ47VTg7Qnh1RDigypW85oMav/7iR54KRr/HIgi6XaDptmuGCKd3K5aW6NW7/BQ==</diagram></mxfile>"
  },
  {
    "path": "infra/diagrams/2.1/herbie-system.drawio",
    "content": "<mxfile host=\"app.diagrams.net\" modified=\"2024-07-16T16:49:51.138Z\" agent=\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36\" etag=\"JZZjkU-f3wO5w5lEnaF_\" version=\"24.6.5\" type=\"device\">\n  <diagram id=\"PBjobV1qK8d18Rz6RHWu\" name=\"Page-1\">\n    <mxGraphModel dx=\"963\" dy=\"753\" grid=\"1\" gridSize=\"10\" guides=\"1\" tooltips=\"1\" connect=\"1\" arrows=\"1\" fold=\"1\" page=\"1\" pageScale=\"1\" pageWidth=\"1100\" pageHeight=\"850\" math=\"0\" shadow=\"0\">\n      <root>\n        <mxCell id=\"0\" />\n        <mxCell id=\"1\" parent=\"0\" />\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-36\" value=\"\" style=\"rounded=1;whiteSpace=wrap;html=1;strokeColor=#1900FF;fillColor=#FFFFFF;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"90\" y=\"705\" width=\"760\" height=\"100\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-54\" value=\"\" style=\"rounded=1;whiteSpace=wrap;html=1;fontSize=14;strokeColor=#00C414;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"90\" y=\"195\" width=\"860\" height=\"460\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-31\" value=\"&lt;span style=&quot;color: rgba(0 , 0 , 0 , 0) ; font-family: monospace ; font-size: 0px&quot;&gt;%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22points%22%20style%3D%22endArrow%3Dclassic%3Bhtml%3D1%3Brounded%3D0%3BexitX%3D0.75%3BexitY%3D0%3BexitDx%3D0%3BexitDy%3D0%3B%22%20edge%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20width%3D%2250%22%20height%3D%2250%22%20relative%3D%221%22%20as%3D%22geometry%22%3E%3CmxPoint%20x%3D%22469.74%22%20y%3D%22450%22%20as%3D%22sourcePoint%22%2F%3E%3CmxPoint%20x%3D%22470.24%22%20y%3D%22370%22%20as%3D%22targetPoint%22%2F%3E%3C%2FmxGeometry%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E&lt;/span&gt;\" style=\"rounded=1;whiteSpace=wrap;html=1;strokeColor=#99CCFF;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"230\" y=\"395\" width=\"271.98\" height=\"245\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-93\" value=\"\" style=\"rounded=1;whiteSpace=wrap;html=1;fontSize=12;strokeColor=#ECFF40;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"90\" y=\"45\" width=\"860\" height=\"100\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-48\" value=\"\" style=\"rounded=1;whiteSpace=wrap;html=1;strokeColor=#99CCFF;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"505\" y=\"395\" width=\"305\" height=\"240\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-1\" value=\"Simplify\" style=\"rounded=0;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"706\" y=\"565\" width=\"90\" height=\"40\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-45\" value=\"rewrites\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=0;exitDx=0;exitDy=0;entryX=0.22;entryY=0.971;entryDx=0;entryDy=0;entryPerimeter=0;\" parent=\"1\" source=\"6-XZHUf7CiIssY0rkYSr-2\" edge=\"1\" target=\"6-XZHUf7CiIssY0rkYSr-5\">\n          <mxGeometry relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"594.5\" y=\"485\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-2\" value=\"Recursive&lt;br&gt;Rewrite\" style=\"rounded=0;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"515\" y=\"565\" width=\"90\" height=\"40\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-3\" value=\"Taylor&lt;br&gt;Expand\" style=\"rounded=0;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"610\" y=\"565\" width=\"90\" height=\"40\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-4\" value=\"Regime&lt;br&gt;Inference\" style=\"rounded=0;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"850\" y=\"445\" width=\"90\" height=\"40\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-5\" value=\"Patch Table\" style=\"rounded=0;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"515\" y=\"445\" width=\"285\" height=\"40\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-6\" value=\"Mainloop\" style=\"rounded=0;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"260\" y=\"325\" width=\"515\" height=\"40\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-8\" value=\"Extraction\" style=\"rounded=0;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"850\" y=\"325\" width=\"90\" height=\"40\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-10\" value=\"&lt;i&gt;binary64&lt;/i&gt;&amp;nbsp;plugin\" style=\"rounded=0;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"365\" y=\"75\" width=\"100\" height=\"40\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-12\" value=\"Plugin Interface\" style=\"rounded=0;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"505\" y=\"215\" width=\"130\" height=\"40\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-13\" value=\"&lt;i&gt;binary32&lt;/i&gt;&amp;nbsp;plugin\" style=\"rounded=0;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"485\" y=\"75\" width=\"100\" height=\"40\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-14\" value=\"&lt;i&gt;posit&lt;/i&gt;&amp;nbsp;plugin\" style=\"rounded=0;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"635\" y=\"75\" width=\"100\" height=\"40\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-15\" value=\"\" style=\"endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;\" parent=\"1\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"595\" y=\"95\" as=\"sourcePoint\" />\n            <mxPoint x=\"635\" y=\"95\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-25\" value=\"subexpr\" style=\"endArrow=classic;html=1;rounded=0;entryX=0.389;entryY=0.01;entryDx=0;entryDy=0;entryPerimeter=0;exitX=0.712;exitY=1;exitDx=0;exitDy=0;exitPerimeter=0;\" parent=\"1\" target=\"6-XZHUf7CiIssY0rkYSr-5\" edge=\"1\" source=\"6-XZHUf7CiIssY0rkYSr-6\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"643\" y=\"365\" as=\"sourcePoint\" />\n            <mxPoint x=\"525\" y=\"445\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-27\" value=\"alt table\" style=\"endArrow=classic;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;\" parent=\"1\" source=\"6-XZHUf7CiIssY0rkYSr-6\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"895\" y=\"435\" as=\"sourcePoint\" />\n            <mxPoint x=\"850\" y=\"345\" as=\"targetPoint\" />\n            <Array as=\"points\">\n              <mxPoint x=\"775\" y=\"345\" />\n            </Array>\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-31\" value=\"exprs\" style=\"endArrow=classic;html=1;rounded=0;exitX=0.25;exitY=1;exitDx=0;exitDy=0;entryX=0.25;entryY=0;entryDx=0;entryDy=0;\" parent=\"1\" source=\"6-XZHUf7CiIssY0rkYSr-8\" target=\"6-XZHUf7CiIssY0rkYSr-4\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"720\" y=\"435\" as=\"sourcePoint\" />\n            <mxPoint x=\"770\" y=\"385\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-32\" value=\"combined&lt;br&gt;expr\" style=\"endArrow=classic;html=1;rounded=0;exitX=0.75;exitY=0;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;\" parent=\"1\" source=\"6-XZHUf7CiIssY0rkYSr-4\" target=\"6-XZHUf7CiIssY0rkYSr-8\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"720\" y=\"435\" as=\"sourcePoint\" />\n            <mxPoint x=\"770\" y=\"385\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-41\" value=\"expr\" style=\"endArrow=classic;html=1;rounded=0;entryX=0.187;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;\" parent=\"1\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"630.17\" y=\"485\" as=\"sourcePoint\" />\n            <mxPoint x=\"629.9999999999999\" y=\"565\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-42\" value=\"expanded\" style=\"endArrow=classic;html=1;rounded=0;exitX=0.75;exitY=0;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;\" parent=\"1\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"680\" y=\"565\" as=\"sourcePoint\" />\n            <mxPoint x=\"680\" y=\"485\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-43\" value=\"expr\" style=\"endArrow=classic;html=1;rounded=0;entryX=0.187;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;\" parent=\"1\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"537.6700000000001\" y=\"485\" as=\"sourcePoint\" />\n            <mxPoint x=\"537.5\" y=\"565\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-55\" value=\"&lt;font style=&quot;font-size: 18px&quot;&gt;Herbie&lt;/font&gt;\" style=\"text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=14;fontStyle=2\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"250\" y=\"210\" width=\"60\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-63\" value=\"\" style=\"endArrow=classic;html=1;rounded=0;fontSize=12;exitX=0.5;exitY=0;exitDx=0;exitDy=0;\" parent=\"1\" source=\"6-XZHUf7CiIssY0rkYSr-8\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"670\" y=\"305\" as=\"sourcePoint\" />\n            <mxPoint x=\"895\" y=\"95\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-64\" value=\"output expr(s)\" style=\"edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=12;\" parent=\"6-XZHUf7CiIssY0rkYSr-63\" vertex=\"1\" connectable=\"0\">\n          <mxGeometry x=\"0.4167\" y=\"-1\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"-1\" y=\"8\" as=\"offset\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-65\" value=\"expr(s)\" style=\"endArrow=classic;html=1;rounded=0;entryX=0.187;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;\" parent=\"1\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"726.1700000000001\" y=\"485\" as=\"sourcePoint\" />\n            <mxPoint x=\"726\" y=\"565\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-68\" value=\"simpler\" style=\"endArrow=classic;html=1;rounded=0;exitX=0.75;exitY=0;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;\" parent=\"1\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"776\" y=\"565\" as=\"sourcePoint\" />\n            <mxPoint x=\"776\" y=\"485\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-70\" value=\"Evaluate\" style=\"rounded=0;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"250\" y=\"565\" width=\"90\" height=\"40\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-72\" value=\"request&lt;br&gt;implementation\" style=\"endArrow=classic;html=1;rounded=0;fontSize=12;entryX=0.156;entryY=1.031;entryDx=0;entryDy=0;entryPerimeter=0;exitX=0.516;exitY=0.019;exitDx=0;exitDy=0;exitPerimeter=0;\" parent=\"1\" source=\"6-XZHUf7CiIssY0rkYSr-6\" target=\"6-XZHUf7CiIssY0rkYSr-12\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"525\" y=\"320\" as=\"sourcePoint\" />\n            <mxPoint x=\"541\" y=\"245\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-73\" value=\"\" style=\"endArrow=classic;html=1;rounded=0;fontSize=12;exitX=0.812;exitY=1.031;exitDx=0;exitDy=0;exitPerimeter=0;\" parent=\"1\" source=\"6-XZHUf7CiIssY0rkYSr-12\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"600\" y=\"245\" as=\"sourcePoint\" />\n            <mxPoint x=\"611\" y=\"325\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-74\" value=\"operators,&lt;br&gt;rules,&lt;br&gt;representations\" style=\"edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=12;\" parent=\"6-XZHUf7CiIssY0rkYSr-73\" vertex=\"1\" connectable=\"0\">\n          <mxGeometry x=\"-0.269\" y=\"2\" relative=\"1\" as=\"geometry\">\n            <mxPoint y=\"9\" as=\"offset\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-75\" value=\"\" style=\"endArrow=classic;html=1;rounded=0;fontSize=12;entryX=0.5;entryY=1;entryDx=0;entryDy=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;\" parent=\"1\" source=\"6-XZHUf7CiIssY0rkYSr-12\" target=\"6-XZHUf7CiIssY0rkYSr-10\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"525\" y=\"205\" as=\"sourcePoint\" />\n            <mxPoint x=\"575\" y=\"155\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-77\" value=\"\" style=\"endArrow=classic;html=1;rounded=0;fontSize=12;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;\" parent=\"1\" source=\"6-XZHUf7CiIssY0rkYSr-12\" target=\"6-XZHUf7CiIssY0rkYSr-13\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"555\" y=\"205\" as=\"sourcePoint\" />\n            <mxPoint x=\"535\" y=\"125\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"WfZgScI90xG1M2LBQycU-11\" value=\"query\" style=\"edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];\" parent=\"6-XZHUf7CiIssY0rkYSr-77\" vertex=\"1\" connectable=\"0\">\n          <mxGeometry x=\"-0.2835\" y=\"-3\" relative=\"1\" as=\"geometry\">\n            <mxPoint as=\"offset\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-78\" value=\"\" style=\"endArrow=classic;html=1;rounded=0;fontSize=12;entryX=0.5;entryY=1;entryDx=0;entryDy=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;\" parent=\"1\" source=\"6-XZHUf7CiIssY0rkYSr-12\" target=\"6-XZHUf7CiIssY0rkYSr-14\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"620\" y=\"205\" as=\"sourcePoint\" />\n            <mxPoint x=\"600\" y=\"125\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"6-XZHUf7CiIssY0rkYSr-87\" value=\"Prune\" style=\"rounded=0;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"250\" y=\"445\" width=\"90\" height=\"40\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-1\" value=\"&lt;font style=&quot;font-size: 14px&quot;&gt;Generate&lt;br&gt;&lt;/font&gt;\" style=\"text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=2\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"535\" y=\"405\" width=\"30\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-4\" value=\"patches\" style=\"endArrow=classic;html=1;rounded=0;exitX=0.633;exitY=0.01;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.846;entryY=0.966;entryDx=0;entryDy=0;entryPerimeter=0;\" parent=\"1\" source=\"6-XZHUf7CiIssY0rkYSr-5\" edge=\"1\" target=\"6-XZHUf7CiIssY0rkYSr-6\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"724\" y=\"430\" as=\"sourcePoint\" />\n            <mxPoint x=\"724\" y=\"365\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-5\" value=\"Localize\" style=\"rounded=0;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"350\" y=\"445\" width=\"130\" height=\"40\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-7\" value=\"Sample\" style=\"rounded=0;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"100\" y=\"325\" width=\"100\" height=\"40\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-8\" value=\"alt table\" style=\"endArrow=classic;html=1;rounded=0;exitX=0.75;exitY=0;exitDx=0;exitDy=0;\" parent=\"1\" source=\"6-XZHUf7CiIssY0rkYSr-87\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"330\" y=\"595\" as=\"sourcePoint\" />\n            <mxPoint x=\"318\" y=\"365\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-9\" value=\"alts\" style=\"endArrow=classic;html=1;rounded=0;entryX=0.25;entryY=0;entryDx=0;entryDy=0;\" parent=\"1\" target=\"6-XZHUf7CiIssY0rkYSr-87\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"273\" y=\"365\" as=\"sourcePoint\" />\n            <mxPoint x=\"380\" y=\"535\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-12\" value=\"\" style=\"endArrow=classic;html=1;rounded=0;fontSize=12;exitX=0.5;exitY=1;exitDx=0;exitDy=0;\" parent=\"1\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"140\" y=\"90\" as=\"sourcePoint\" />\n            <mxPoint x=\"140\" y=\"325\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-16\" value=\"input expr,&lt;br&gt;precondition\" style=\"edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];\" parent=\"XskiZDpq82sz6ixhcIVA-12\" vertex=\"1\" connectable=\"0\">\n          <mxGeometry x=\"-0.2913\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"5\" y=\"-3\" as=\"offset\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-22\" value=\"error\" style=\"endArrow=classic;html=1;rounded=0;exitX=0.875;exitY=-0.01;exitDx=0;exitDy=0;exitPerimeter=0;\" parent=\"1\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"367.5\" y=\"734.6000000000001\" as=\"sourcePoint\" />\n            <mxPoint x=\"370.5\" y=\"485\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-25\" value=\"error\" style=\"endArrow=classic;html=1;rounded=0;exitX=0.75;exitY=0;exitDx=0;exitDy=0;\" parent=\"1\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"294.5\" y=\"565\" as=\"sourcePoint\" />\n            <mxPoint x=\"295\" y=\"485\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-26\" value=\"cost\" style=\"endArrow=classic;html=1;rounded=0;exitX=0.75;exitY=0;exitDx=0;exitDy=0;\" parent=\"1\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"320\" y=\"565\" as=\"sourcePoint\" />\n            <mxPoint x=\"320.5\" y=\"485\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-28\" value=\"expr\" style=\"endArrow=classic;html=1;rounded=0;entryX=0.187;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;\" parent=\"1\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"269.6700000000001\" y=\"485\" as=\"sourcePoint\" />\n            <mxPoint x=\"269.5\" y=\"565\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-32\" value=\"&lt;font style=&quot;font-size: 14px&quot;&gt;Test&lt;br&gt;&lt;/font&gt;\" style=\"text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=2\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"250\" y=\"610\" width=\"30\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-37\" value=\"&lt;font&gt;&lt;font style=&quot;font-size: 18px&quot;&gt;Libraries&lt;/font&gt;&lt;br&gt;&lt;/font&gt;\" style=\"text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontStyle=2\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"70\" y=\"776\" width=\"140\" height=\"25\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-41\" value=\"egg\" style=\"rounded=0;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"430\" y=\"735\" width=\"410\" height=\"40\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-43\" value=\"&lt;span style=&quot;color: rgba(0 , 0 , 0 , 0) ; font-family: monospace ; font-size: 0px ; background-color: rgb(248 , 249 , 250)&quot;&gt;%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22extracted%22%20style%3D%22edgeLabel%3Bhtml%3D1%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3Bresizable%3D0%3Bpoints%3D%5B%5D%3BfontSize%3D12%3B%22%20vertex%3D%221%22%20connectable%3D%220%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22590.5%22%20y%3D%22679.6666666666667%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E&lt;/span&gt;\" style=\"endArrow=classic;html=1;rounded=0;\" parent=\"1\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"725.6700000000001\" y=\"605\" as=\"sourcePoint\" />\n            <mxPoint x=\"726\" y=\"735\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"uF0uv0Qmmf_ZE26efQfl-6\" value=\"expr\" style=\"edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];\" parent=\"XskiZDpq82sz6ixhcIVA-43\" vertex=\"1\" connectable=\"0\">\n          <mxGeometry x=\"0.121\" relative=\"1\" as=\"geometry\">\n            <mxPoint as=\"offset\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-44\" value=\"\" style=\"endArrow=classic;html=1;rounded=0;fontSize=18;entryX=0.75;entryY=1;entryDx=0;entryDy=0;exitX=0.312;exitY=-0.001;exitDx=0;exitDy=0;exitPerimeter=0;\" parent=\"1\" target=\"6-XZHUf7CiIssY0rkYSr-1\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"773.0799999999999\" y=\"734.96\" as=\"sourcePoint\" />\n            <mxPoint x=\"791\" y=\"575\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"uF0uv0Qmmf_ZE26efQfl-14\" value=\"simplest\" style=\"edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];\" parent=\"XskiZDpq82sz6ixhcIVA-44\" vertex=\"1\" connectable=\"0\">\n          <mxGeometry x=\"-0.1252\" relative=\"1\" as=\"geometry\">\n            <mxPoint as=\"offset\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-49\" value=\"points\" style=\"endArrow=classic;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;\" parent=\"1\" edge=\"1\" target=\"6-XZHUf7CiIssY0rkYSr-6\" source=\"XskiZDpq82sz6ixhcIVA-7\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"194.74\" y=\"445\" as=\"sourcePoint\" />\n            <mxPoint x=\"195.24\" y=\"365\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-50\" value=\"expr,&lt;br&gt;point\" style=\"endArrow=classic;html=1;rounded=0;entryX=0.085;entryY=-0.001;entryDx=0;entryDy=0;entryPerimeter=0;\" parent=\"1\" target=\"XskiZDpq82sz6ixhcIVA-52\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"124.5\" y=\"365\" as=\"sourcePoint\" />\n            <mxPoint x=\"124\" y=\"615\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-52\" value=\"Rival\" style=\"rounded=0;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"100\" y=\"735\" width=\"310\" height=\"40\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"XskiZDpq82sz6ixhcIVA-53\" value=\"ground&lt;br&gt;truth\" style=\"endArrow=classic;html=1;rounded=0;exitX=0.24;exitY=-0.01;exitDx=0;exitDy=0;exitPerimeter=0;\" parent=\"1\" source=\"XskiZDpq82sz6ixhcIVA-52\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"174\" y=\"615\" as=\"sourcePoint\" />\n            <mxPoint x=\"174.24\" y=\"365\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"WfZgScI90xG1M2LBQycU-13\" value=\"&lt;font style=&quot;font-size: 18px&quot;&gt;User&lt;/font&gt;\" style=\"text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=14;fontStyle=2\" parent=\"1\" vertex=\"1\">\n          <mxGeometry x=\"110\" y=\"60\" width=\"50\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n        <mxCell id=\"uF0uv0Qmmf_ZE26efQfl-15\" value=\"&lt;span style=&quot;color: rgba(0 , 0 , 0 , 0) ; font-family: monospace ; font-size: 0px ; background-color: rgb(248 , 249 , 250)&quot;&gt;%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22extracted%22%20style%3D%22edgeLabel%3Bhtml%3D1%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3Bresizable%3D0%3Bpoints%3D%5B%5D%3BfontSize%3D12%3B%22%20vertex%3D%221%22%20connectable%3D%220%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22590.5%22%20y%3D%22679.6666666666667%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E&lt;/span&gt;\" style=\"endArrow=classic;html=1;rounded=0;\" parent=\"1\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"538.59\" y=\"605\" as=\"sourcePoint\" />\n            <mxPoint x=\"538.92\" y=\"735\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"uF0uv0Qmmf_ZE26efQfl-16\" value=\"expr\" style=\"edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];\" parent=\"uF0uv0Qmmf_ZE26efQfl-15\" vertex=\"1\" connectable=\"0\">\n          <mxGeometry x=\"0.121\" relative=\"1\" as=\"geometry\">\n            <mxPoint as=\"offset\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"uF0uv0Qmmf_ZE26efQfl-17\" value=\"\" style=\"endArrow=classic;html=1;rounded=0;fontSize=18;entryX=0.75;entryY=1;entryDx=0;entryDy=0;exitX=0.312;exitY=-0.001;exitDx=0;exitDy=0;exitPerimeter=0;\" parent=\"1\" edge=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"581.9999999999999\" y=\"734.96\" as=\"sourcePoint\" />\n            <mxPoint x=\"582.42\" y=\"605\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"uF0uv0Qmmf_ZE26efQfl-18\" value=\"variants\" style=\"edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];\" parent=\"uF0uv0Qmmf_ZE26efQfl-17\" vertex=\"1\" connectable=\"0\">\n          <mxGeometry x=\"-0.1252\" relative=\"1\" as=\"geometry\">\n            <mxPoint as=\"offset\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"3g5QUApUYGK8Pu6HczJZ-2\" value=\"alt\" style=\"endArrow=classic;html=1;rounded=0;entryX=0.25;entryY=0;entryDx=0;entryDy=0;\" edge=\"1\" parent=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"410.5\" y=\"365\" as=\"sourcePoint\" />\n            <mxPoint x=\"410\" y=\"445\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"3g5QUApUYGK8Pu6HczJZ-3\" value=\"locations\" style=\"endArrow=classic;html=1;rounded=0;exitX=0.75;exitY=0;exitDx=0;exitDy=0;\" edge=\"1\" parent=\"1\">\n          <mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"460\" y=\"445\" as=\"sourcePoint\" />\n            <mxPoint x=\"460.5\" y=\"365\" as=\"targetPoint\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"3g5QUApUYGK8Pu6HczJZ-4\" value=\"opportunity\" style=\"endArrow=classic;html=1;rounded=0;exitX=0.165;exitY=-0.06;exitDx=0;exitDy=0;exitPerimeter=0;\" edge=\"1\" parent=\"1\">\n          <mxGeometry x=\"-0.0097\" width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"470.9499999999998\" y=\"732.5999999999999\" as=\"sourcePoint\" />\n            <mxPoint x=\"470.5\" y=\"485\" as=\"targetPoint\" />\n            <mxPoint as=\"offset\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"3g5QUApUYGK8Pu6HczJZ-8\" value=\"\" style=\"endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.884;entryY=0.002;entryDx=0;entryDy=0;entryPerimeter=0;\" edge=\"1\" parent=\"1\">\n          <mxGeometry x=\"-0.004\" width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"416.6\" y=\"485\" as=\"sourcePoint\" />\n            <mxPoint x=\"390.0000000000001\" y=\"735.0800000000002\" as=\"targetPoint\" />\n            <mxPoint as=\"offset\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"3g5QUApUYGK8Pu6HczJZ-5\" value=\"subexpr\" style=\"endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;\" edge=\"1\" parent=\"1\">\n          <mxGeometry x=\"-0.0138\" y=\"-12\" width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\">\n            <mxPoint x=\"416.6\" y=\"485\" as=\"sourcePoint\" />\n            <mxPoint x=\"441.6\" y=\"736\" as=\"targetPoint\" />\n            <mxPoint as=\"offset\" />\n          </mxGeometry>\n        </mxCell>\n        <mxCell id=\"3g5QUApUYGK8Pu6HczJZ-11\" value=\"&lt;font style=&quot;font-size: 18px&quot;&gt;User&lt;/font&gt;\" style=\"text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=14;fontStyle=2\" vertex=\"1\" parent=\"1\">\n          <mxGeometry x=\"870\" y=\"60\" width=\"50\" height=\"30\" as=\"geometry\" />\n        </mxCell>\n      </root>\n    </mxGraphModel>\n  </diagram>\n</mxfile>\n"
  },
  {
    "path": "infra/diff.rkt",
    "content": "#lang racket\n\n(require \"../src/api/datafile.rkt\")\n\n(define (field-equal? access t1 t2)\n  (equal? (access t1) (access t2)))\n\n;; Only interested in output\n;; Only compare against runs with the same configuration\n(define (datafile-tests-equal? df1 df2)\n  (define tests1 (report-info-tests df1))\n  (define tests2 (report-info-tests df2))\n  (and (= (length tests1) (length tests2))\n       (andmap (λ (t1 t2)\n                 (and (field-equal? table-row-name t1 t2)\n                      (field-equal? table-row-identifier t1 t2)\n                      (field-equal? table-row-output t1 t2)\n                      (field-equal? table-row-cost-accuracy t1 t2)))\n               tests1\n               tests2)))\n\n(module+ main\n  (command-line #:args (outdir1 outdir2)\n                (define df1 (call-with-input-file (build-path outdir1 \"results.json\") read-datafile))\n                (define df2 (call-with-input-file (build-path outdir2 \"results.json\") read-datafile))\n                (cond\n                  [(datafile-tests-equal? df1 df2) (printf \"Matching output expressions\\n\")]\n                  [else\n                   (printf \"Output expressions do not match!!\\n\")\n                   (printf \" datafile1: ~a\\n\" df1)\n                   (printf \" datafile1: ~a\\n\" df2)\n                   (exit 1)])))\n"
  },
  {
    "path": "infra/fidget2core.py",
    "content": "vars = set()\nnodes = []\n\nop_parse = dict({\n            'div':'/',\n            'mul':'*',\n            'add':'+',\n            'sub':'-',\n            'square':'pow',\n            'sqrt':'sqrt',\n            'exp':'exp',\n            'ln':'log',\n            'abs':'fabs',\n            'max':'fmax',\n            'min':'fmin',\n            'neg':'-',\n            'cos':'cos',\n            'sin':'sin'})\n\ndef parse_node(node):\n    idx = int(node[0].replace('_', ''), 16)\n    op = node[1]\n    if 'var' in op:\n        vars.add(op.replace('var-', ''))\n        nodes.append([op.replace('var-', '')])\n    elif 'const' == op:\n        nodes.append([node[2]])\n    elif op == 'square':\n        nodes.append(['pow'] + [node[2]] + ['2'])\n    else:\n        op = op_parse[op]\n        nodes.append([op] + node[2:])\n           \n\nwith open(\"hi.vm\", \"r\") as file:\n    for line in file:\n        if line[0] != '#' and line[0] != '\\n':\n            node = line.replace('\\n', '').split(' ')\n            parse_node(node)\n          \ndef recurse_nodes(idx):\n    node = nodes[idx]\n    if len(node) == 2:\n        idx1 = int(node[1].replace('_', ''), 16)\n        return '(' + node[0] + ' ' + recurse_nodes(idx1) + ')'\n    elif len(node) == 3 and node[0] == 'pow' and node[2] == '2':\n        idx1 = int(node[1].replace('_', ''), 16)\n        return '(' + node[0] + ' ' + recurse_nodes(idx1) + ' ' + node[2] + ')'\n    elif len(node) == 3:\n        idx1 = int(node[1].replace('_', ''), 16)\n        idx2 = int(node[2].replace('_', ''), 16)\n        return '(' + node[0] + ' ' + recurse_nodes(idx1) + ' ' + recurse_nodes(idx2) + ')'\n    else:\n        return node[0]\n        \nprint(recurse_nodes(len(nodes)-1))\nprint(vars)\n\n            \n"
  },
  {
    "path": "infra/herbie-demo.service",
    "content": "[Unit]\nDescription=The Herbie web demo\nDocumentation=https://herbie.uwplse.org/demo/\nAfter=network.target\n\n[Service]\nExecStart=make start-server\nWorkingDirectory=/var/www/herbie\nUser=pavpan\n\n[Install]\nWantedBy=multi-user.target\n"
  },
  {
    "path": "infra/merge.rkt",
    "content": "#lang racket\n(require json)\n(require \"../src/utils/common.rkt\"\n         \"../src/utils/timeline.rkt\"\n         \"../src/utils/profile.rkt\"\n         \"../src/api/datafile.rkt\"\n         \"../src/reports/timeline.rkt\"\n         \"../src/reports/common.rkt\"\n         \"../src/syntax/platform.rkt\"\n         \"../src/syntax/load-platform.rkt\")\n\n(define (merge-timelines outdir . dirs)\n  (define tls\n    (filter (conjoin (negate eof-object?) identity)\n            (for/list ([dir (in-list dirs)])\n              (with-handlers ([exn? (const #f)])\n                (call-with-input-file (build-path outdir dir \"timeline.json\") read-json)))))\n  (define info (call-with-input-file (build-path outdir (first dirs) \"results.json\") read-datafile))\n  (define joint-tl (apply timeline-merge tls))\n  (call-with-output-file (build-path outdir \"timeline.json\")\n                         #:exists 'replace\n                         (curry write-json joint-tl))\n  (call-with-output-file (build-path outdir \"timeline.html\")\n                         #:exists 'replace\n                         (λ (out)\n                           (write-html (make-timeline \"Herbie run\" joint-tl #:info info) out))))\n\n(define (merge-profiles outdir . dirs)\n  (define pfs\n    (filter (conjoin (negate eof-object?) identity)\n            (for/list ([dir (in-list dirs)])\n              (with-handlers ([exn? (const #f)])\n                (call-with-input-file (build-path outdir dir \"profile.json\") read-json)))))\n  (define joint-pf (apply profile-merge (map json->profile pfs)))\n  (call-with-output-file (build-path outdir \"profile.json\")\n                         #:exists 'replace\n                         (curry write-json (profile->json joint-pf))))\n\n(define (merge-reports outdir . dirs)\n  (define rss\n    (filter (conjoin (negate eof-object?) identity)\n            (for/list ([dir (in-list dirs)])\n              (with-handlers ([exn? (const #f)])\n                (define df\n                  (call-with-input-file (build-path outdir dir \"results.json\") read-datafile))\n                (if (eof-object? df)\n                    eof\n                    (cons df dir))))))\n  (define dfs (map car rss))\n  (define joint-rs (merge-datafiles dfs #:dirs dirs))\n  (write-datafile (build-path outdir \"results.json\") joint-rs)\n  (copy-file (web-resource \"report.html\") (build-path outdir \"index.html\") #t))\n\n(module+ main\n  (command-line #:args (outdir . dirs)\n                (activate-platform! (*platform-name*))\n                (apply merge-reports outdir dirs)\n                (apply merge-timelines outdir dirs)\n                (apply merge-profiles outdir dirs)\n                (copy-file (web-resource \"report.js\") (build-path outdir \"report.js\") #t)\n                (copy-file (web-resource \"report-page.js\") (build-path outdir \"report-page.js\") #t)\n                (copy-file (web-resource \"report.css\") (build-path outdir \"report.css\") #t)\n                (copy-file (web-resource \"logo-car.png\") (build-path outdir \"logo-car.png\") #t)))\n"
  },
  {
    "path": "infra/nightly.sh",
    "content": "#!/bin/bash\n\n# exit immediately upon first error, log every command executed\nset -e -x\n\n# Ensure egglog is in the path\nexport PATH=\"$HOME/.cargo/bin/:$PATH\"\nrustup update\n\n# Keep nightly installs isolated and consistent across install/run steps.\nexport PLTADDONDIR=\"${PLTADDONDIR:-pltlibs}\"\nmake install\n\n# Seed is fixed for the whole day; this way two branches run the same seed\nSEED=$(date \"+%Y%j\")\nBRANCH=$(git rev-parse --abbrev-ref HEAD)\n\nBENCHDIR=\"$1\"; shift\nREPORTDIR=\"$1\"; shift\n\nif [[ \"$BRANCH\" == egglog-* ]]; then\n  set -- \"$@\" --enable generate:egglog\nfi\n\nif [[ \"$BRANCH\" == rival2-* || \"$BRANCH\" == \"rival2\" ]]; then\n  set -- \"$@\" --enable setup:rival2\nfi\n\nmkdir -p \"$REPORTDIR\"\nrm -rf \"reports\"/* || echo \"nothing to delete\"\n\n# run\ndirs=\"\"\nfor bench in \"$BENCHDIR\"/*; do\n  name=$(basename \"$bench\" .fpcore)\n  rm -rf \"$REPORTDIR\"/\"$name\"\n\n  racket -y \"src/main.rkt\" report \\\n         --seed \"$SEED\" \\\n         \"$@\" \\\n         \"$bench\" \"$REPORTDIR\"/\"$name\"\n  \n  dirs=\"$dirs $name\";\ndone\n\n# merge reports\nracket -y infra/merge.rkt \"$REPORTDIR\" $dirs\n"
  },
  {
    "path": "infra/softposit.rkt",
    "content": "#lang s-exp \"../src/syntax/platform-language.rkt\"\n\n;;; Softposit platform, using David Thien's softposit-rkt package for\n;;; bindings. Provides operations like real->posit16 or +.p16.\n\n(require math/bigfloat\n         math/flonum\n         softposit-rkt)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; utils ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define posit8-max  (ordinal->posit8  (- (expt 2 (- 8 1)) 1)))\n(define posit16-max (ordinal->posit16 (- (expt 2 (- 16 1)) 1)))\n(define posit32-max (ordinal->posit32 (- (expt 2 (- 32 1)) 1)))\n\n;; Max quire is difficult to compute:\n;;\n;; A quire is a 2s-complement signed fixed-point number with\n;;  - `000...000` representing 0,\n;;  - `100...000` representing NAR.\n;; Unlike traditional fixed-point numbers, quires are actually symmetric.\n;; For an `n`-bit posit, the associated quire has bitwidth `16 * n`\n;; with a scale of `2^(16 - 8*n)`.\n;;\n;;   posit   quire size         max value               nearest double w/ epsilon\n;;  -------|------------|----------------------|------------------------------------------|\n;;   8       128         (2^(127) - 1) * 2^-48   2^79 - 2^-48   (6.044629098073146e+23)\n;;   16      256         (2^(255) - 1) * 2^-112  2^143 - 2^-112  (1.1150372599265312e+43)\n;;   32      512         (2^(511) - 1) * 2^-240  2^270 - 2^-240  (3.794275180128377e+81)\n;;\n;; Unfortunately, we don't have a good way to convert doubles to quire.\n;; The libsoftposit library only has double to posit; the Racket shim\n;; incorrectly composes double-posit, posit-quire conversions.\n;;\n\n(define quire8-max   (quire8-fdp-add  (double->quire8 0.0)  posit8-max  posit8-max))\n(define quire8-nmax  (quire8-fdp-sub  (double->quire8 0.0)  posit8-max  posit8-max))\n(define quire16-max  (quire16-fdp-add (double->quire16 0.0) posit16-max posit16-max))\n(define quire16-nmax (quire16-fdp-sub (double->quire16 0.0) posit16-max posit16-max))\n\n; These crash\n; (define quire32-max (quire32-fdp-add (double->quire32 0.0) posit32-max posit32-max))\n; (define quire32-nmax (quire32-fdp-sub (double->quire32 0.0) posit32-max posit32-max))\n\n(define (bf-inf->nan x) (let ([y (bf x)]) (if (bfinfinite? y) +nan.bf y)))\n\n(define (double->posit8* x)\n  (let ([y (double->posit8 x)])\n    (if (posit8= y (posit8-nar))\n        (if (> x 0) posit8-max (posit8-neg posit8-max))\n        y)))\n(define (double->posit16* x)\n  (let ([y (double->posit16 x)])\n    (if (posit16= y (posit16-nar))\n        (if (> x 0) posit16-max (posit16-neg posit16-max))\n        y)))\n(define (double->posit32* x)\n  (let ([y (double->posit32 x)])\n    (if (posit32= y (posit32-nar))\n        (if (> x 0) posit32-max (posit32-neg posit32-max))\n        y)))\n(define (double->quire8* x)\n  (let ([y (double->quire8 x)])\n    (if (infinite? (quire8->double y))\n        (if (> x 0) quire8-max quire8-nmax)\n        y)))\n(define (double->quire16* x)\n  (let ([y (double->quire16 x)])\n    (if (infinite? (quire16->double y))\n        (if (> x 0) quire16-max quire16-nmax)\n        y)))\n#;(define (double->quire32* x)\n  (let ([y (double->quire32 x)])\n    (if (infinite? (quire32->double y))\n        (if (> x 0) quire32-max quire32-nmax)\n        y)))\n\n(define (and-fn . as)\n  (andmap identity as))\n(define (or-fn . as)\n  (ormap identity as))\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; EMPTY PLATFORM ;;;;;;;;;;;;;;;;;;;;;;;;\n\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; REPRESENTATIONS ;;;;;;;;;;;;;;;;;;;;;;;\n\n(define <posit8>\n  (make-representation #:name 'posit8\n                       #:bf->repr (compose double->posit8* bigfloat->flonum)\n                       #:repr->bf (compose bf-inf->nan posit8->double)\n                       #:ordinal->repr ordinal->posit8\n                       #:repr->ordinal posit8->ordinal\n                       #:total-bits 8\n                       #:special-value? (curry posit8= (posit8-nar))))\n\n(define <posit16>\n  (make-representation #:name 'posit16\n                       #:bf->repr (compose double->posit16* bigfloat->flonum)\n                       #:repr->bf (compose bf-inf->nan posit16->double)\n                       #:ordinal->repr ordinal->posit16\n                       #:repr->ordinal posit16->ordinal\n                       #:total-bits 16\n                       #:special-value? (curry posit16= (posit16-nar))))\n\n(define <posit32>\n  (make-representation #:name 'posit32\n                       #:bf->repr (compose double->posit32* bigfloat->flonum)\n                       #:repr->bf (compose bf-inf->nan posit32->double)\n                       #:ordinal->repr ordinal->posit32\n                       #:repr->ordinal posit32->ordinal\n                       #:total-bits 32\n                       #:special-value? (curry posit32= (posit32-nar))))\n\n(define <quire8>\n  (make-representation #:name 'quire8\n                       #:bf->repr (compose double->quire8* bigfloat->flonum)\n                       #:repr->bf (compose bf-inf->nan quire8->double)\n                       #:ordinal->repr (compose double->quire8 ordinal->flonum)\n                       #:repr->ordinal (compose flonum->ordinal quire8->double)\n                       #:total-bits 64\n                       #:special-value? (const #f)))\n\n(define <quire16>\n  (make-representation #:name 'quire16\n                       #:bf->repr (compose double->quire16* bigfloat->flonum)\n                       #:repr->bf (compose bf-inf->nan quire16->double)\n                       #:ordinal->repr (compose double->quire16 ordinal->flonum)\n                       #:repr->ordinal (compose flonum->ordinal quire16->double)\n                       #:total-bits 64\n                       #:special-value? (const #f)))\n\n(define <quire32>\n  (make-representation #:name 'quire32\n                       #:bf->repr (compose double->quire32 bigfloat->flonum) ; TODO: use double->quire32* when crash fixed\n                       #:repr->bf (compose bf-inf->nan quire32->double)\n                       #:ordinal->repr (compose double->quire32 ordinal->flonum)\n                       #:repr->ordinal (compose flonum->ordinal quire32->double)\n                       #:total-bits 64\n                       #:special-value? (const #f)))\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BOOLEAN IMPLS ;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <bool> #:cost 1)\n\n(define-operations () <bool>\n  [TRUE  #:spec (TRUE)  #:impl (const true)  #:fpcore TRUE  #:cost 1]\n  [FALSE #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost 1])\n\n(define-operations ([x <bool>] [y <bool>]) <bool>\n  [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost 1]\n  [or  #:spec (or x y)  #:impl (lambda v (ormap values v))  #:cost 1])\n\n(define-operation (not [x <bool>]) <bool>\n  #:spec (not x) #:impl not #:cost 1)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; POSIT IMPLS ;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <posit8>  #:cost 1)\n(define-operation (if.p8 [c <bool>] [t <posit8>] [f <posit8>]) <posit8>\n  #:spec (if c t f) #:impl if-impl\n  #:cost (if-cost 1))\n(define-representation <posit16> #:cost 1)\n(define-operation (if.p16 [c <bool>] [t <posit16>] [f <posit16>]) <posit16>\n  #:spec (if c t f) #:impl if-impl\n  #:cost (if-cost 1))\n(define-representation <posit32> #:cost 1)\n(define-operation (if.p32 [c <bool>] [t <posit32>] [f <posit32>]) <posit32>\n  #:spec (if c t f) #:impl if-impl\n  #:cost (if-cost 1))\n\n(define-operations ([x <posit8>] [y <posit8>]) <bool>\n  [==.p8 #:spec (== x y) #:impl posit8=  #:cost 1]\n  [<.p8  #:spec (< x y)  #:impl posit8<  #:cost 1]\n  [>.p8  #:spec (> x y)  #:impl posit8>  #:cost 1]\n  [<=.p8 #:spec (<= x y) #:impl posit8<= #:cost 1]\n  [>=.p8 #:spec (>= x y) #:impl posit8>= #:cost 1])\n\n(define-operations ([x <posit8>]) <posit8> #:fpcore (! :precision posit8 _)\n  [neg.p8  #:spec (neg x)  #:impl posit8-neg  #:fpcore (- x) #:cost 1]\n  [sqrt.p8 #:spec (sqrt x) #:impl posit8-sqrt #:cost 1])\n\n(define-operations ([x <posit8>] [y <posit8>]) <posit8> #:fpcore (! :precision posit8 _)\n  [+.p8 #:spec (+ x y) #:impl posit8-add #:cost 1]\n  [-.p8 #:spec (- x y) #:impl posit8-sub #:cost 1]\n  [*.p8 #:spec (* x y) #:impl posit8-mul #:cost 1]\n  [/.p8 #:spec (/ x y) #:impl posit8-div #:cost 1])\n\n(define-operations ([x <posit16>] [y <posit16>]) <bool>\n  [==.p16 #:spec (== x y) #:impl posit16=  #:cost 1]\n  [<.p16  #:spec (< x y)  #:impl posit16<  #:cost 1]\n  [>.p16  #:spec (> x y)  #:impl posit16>  #:cost 1]\n  [<=.p16 #:spec (<= x y) #:impl posit16<= #:cost 1]\n  [>=.p16 #:spec (>= x y) #:impl posit16>= #:cost 1])\n\n(define-operations ([x <posit16>]) <posit16> #:fpcore (! :precision posit16 _)\n  [neg.p16  #:spec (neg x)  #:impl posit16-neg  #:fpcore (- x) #:cost 1]\n  [sqrt.p16 #:spec (sqrt x) #:impl posit16-sqrt #:cost 1])\n\n(define-operations ([x <posit16>] [y <posit16>]) <posit16> #:fpcore (! :precision posit16 _)\n  [+.p16 #:spec (+ x y) #:impl posit16-add #:cost 1]\n  [-.p16 #:spec (- x y) #:impl posit16-sub #:cost 1]\n  [*.p16 #:spec (* x y) #:impl posit16-mul #:cost 1]\n  [/.p16 #:spec (/ x y) #:impl posit16-div #:cost 1])\n\n(define-operations ([x <posit32>] [y <posit32>]) <bool>\n  [==.p32 #:spec (== x y) #:impl posit32=  #:cost 1]\n  [<.p32  #:spec (< x y)  #:impl posit32<  #:cost 1]\n  [>.p32  #:spec (> x y)  #:impl posit32>  #:cost 1]\n  [<=.p32 #:spec (<= x y) #:impl posit32<= #:cost 1]\n  [>=.p32 #:spec (>= x y) #:impl posit32>= #:cost 1])\n\n(define-operations ([x <posit32>]) <posit32> #:fpcore (! :precision posit32 _)\n  [neg.p32  #:spec (neg x)  #:impl posit32-neg  #:fpcore (- x) #:cost 1]\n  [sqrt.p32 #:spec (sqrt x) #:impl posit32-sqrt #:cost 1])\n\n(define-operations ([x <posit32>] [y <posit32>]) <posit32> #:fpcore (! :precision posit32 _)\n  [+.p32 #:spec (+ x y) #:impl posit32-add #:cost 1]\n  [-.p32 #:spec (- x y) #:impl posit32-sub #:cost 1]\n  [*.p32 #:spec (* x y) #:impl posit32-mul #:cost 1]\n  [/.p32 #:spec (/ x y) #:impl posit32-div #:cost 1])\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; QUIRE OPERATIONS ;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <quire8>  #:cost 1)\n(define-representation <quire16> #:cost 1)\n(define-representation <quire32> #:cost 1)\n\n(define-operations ([x <quire8>] [y <posit8>] [z <posit8>]) <quire8> #:fpcore (! :precision quire8 _)\n  [quire8-mul-add #:spec (+ x (* y z)) #:impl quire8-fdp-add #:fpcore (fdp x y z) #:cost 1]\n  [quire8-mul-sub #:spec (- x (* y z)) #:impl quire8-fdp-sub #:fpcore (fds x y z) #:cost 1])\n\n(define-operations ([x <quire16>] [y <posit16>] [z <posit16>]) <quire16> #:fpcore (! :precision quire16 _)\n  [quire16-mul-add #:spec (+ x (* y z)) #:impl quire16-fdp-add #:fpcore (fdp x y z) #:cost 1]\n  [quire16-mul-sub #:spec (- x (* y z)) #:impl quire16-fdp-sub #:fpcore (fds x y z) #:cost 1])\n\n(define-operations ([x <quire32>] [y <posit32>] [z <posit32>]) <quire32> #:fpcore (! :precision quire32 _)\n  [quire32-mul-add #:spec (+ x (* y z)) #:impl quire32-fdp-add #:fpcore (fdp x y z) #:cost 1]\n  [quire32-mul-sub #:spec (- x (* y z)) #:impl quire32-fdp-sub #:fpcore (fds x y z) #:cost 1])\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CONVERTERS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <binary64> #:cost 1)\n\n(define-operation (binary64->posit8  [x <binary64>]) <posit8>\n  #:spec x #:impl double->posit8   #:fpcore (! :precision posit8 (cast x))   #:cost 1)\n(define-operation (binary64->posit16 [x <binary64>]) <posit16>\n  #:spec x #:impl double->posit16  #:fpcore (! :precision posit16 (cast x))  #:cost 1)\n(define-operation (binary64->posit32 [x <binary64>]) <posit32>\n  #:spec x #:impl double->posit32  #:fpcore (! :precision posit32 (cast x))  #:cost 1)\n(define-operation (posit8->binary64  [x <posit8>])   <binary64>\n  #:spec x #:impl posit8->double   #:fpcore (! :precision binary64 (cast x)) #:cost 1)\n(define-operation (posit16->binary64 [x <posit16>])  <binary64>\n  #:spec x #:impl posit16->double  #:fpcore (! :precision binary64 (cast x)) #:cost 1)\n(define-operation (posit32->binary64 [x <posit32>])  <binary64>\n  #:spec x #:impl posit32->double  #:fpcore (! :precision binary64 (cast x)) #:cost 1)\n\n(define-operation (binary64->quire8  [x <binary64>]) <quire8>\n  #:spec x #:impl double->quire8   #:fpcore (! :precision quire8 (cast x))   #:cost 1)\n(define-operation (binary64->quire16 [x <binary64>]) <quire16>\n  #:spec x #:impl double->quire16  #:fpcore (! :precision quire16 (cast x))  #:cost 1)\n(define-operation (binary64->quire32 [x <binary64>]) <quire32>\n  #:spec x #:impl double->quire32  #:fpcore (! :precision quire32 (cast x))  #:cost 1)\n(define-operation (quire8->binary64  [x <quire8>])   <binary64>\n  #:spec x #:impl quire8->double   #:fpcore (! :precision binary64 (cast x)) #:cost 1)\n(define-operation (quire16->binary64 [x <quire16>])  <binary64>\n  #:spec x #:impl quire16->double  #:fpcore (! :precision binary64 (cast x)) #:cost 1)\n(define-operation (quire32->binary64 [x <quire32>])  <binary64>\n  #:spec x #:impl quire32->double  #:fpcore (! :precision binary64 (cast x)) #:cost 1)\n\n(define-operation (quire8->posit8    [x <quire8>])   <posit8>\n  #:spec x #:impl quire8->posit8   #:fpcore (! :precision posit8 (cast x))   #:cost 1)\n(define-operation (quire16->posit16  [x <quire16>])  <posit16>\n  #:spec x #:impl quire16->posit16 #:fpcore (! :precision posit16 (cast x))  #:cost 1)\n(define-operation (quire32->posit32  [x <quire32>])  <posit32>\n  #:spec x #:impl quire32->posit32 #:fpcore (! :precision posit32 (cast x))  #:cost 1)\n(define-operation (posit8->quire8    [x <posit8>])   <quire8>\n  #:spec x #:impl posit8->quire8   #:fpcore (! :precision quire8 (cast x))   #:cost 1)\n(define-operation (posit16->quire16  [x <posit16>])  <quire16>\n  #:spec x #:impl posit16->quire16 #:fpcore (! :precision quire16 (cast x))  #:cost 1)\n(define-operation (posit32->quire32  [x <posit32>])  <quire32>\n  #:spec x #:impl posit32->quire32 #:fpcore (! :precision quire32 (cast x))  #:cost 1)\n"
  },
  {
    "path": "infra/sort-fpcore.rkt",
    "content": "#lang racket\n\n(define (read-lines port)\n  (define line (read port))\n  (if (equal? line eof)\n      empty\n      (cons line (read-lines port))))\n\n(define (fpcore-less-than fpcore fpcore2)\n  (string>? (~a (rest (rest fpcore))) (~a (rest (rest fpcore2)))))\n\n(define (sort-fpcores fpcores)\n  (sort fpcores fpcore-less-than))\n\n(define (no-casts expr)\n  (cond\n    [(list? expr) (andmap no-casts expr)]\n    [else (not (equal? expr '!))]))\n\n(module+ main\n  (command-line #:program \"sort\"\n                #:args (json-file output-file)\n                (define filtered\n                  (filter no-casts (sort-fpcores (read-lines (open-input-file json-file)))))\n                (unless (empty? filtered)\n                  (define output (open-output-file output-file #:exists 'replace))\n                  (for ([line filtered])\n                    (write line output)))))\n"
  },
  {
    "path": "infra/survey/.gitignore",
    "content": ".DS_Store\n.env\n"
  },
  {
    "path": "infra/survey/README.md",
    "content": "# Dependencies\n\n* [jq](https://stedolan.github.io/jq/)\n* [matplotlib](https://matplotlib.org/)\n* [numpy](https://numpy.org/)\n\n# Optional dependencies\n\n* [env_parallel](https://www.gnu.org/software/parallel/env_parallel.html)\n"
  },
  {
    "path": "infra/survey/seed-variance.sh",
    "content": "#!/usr/bin/env bash\n\n# exit immediately upon first error\nset -e\n\n# determine physical directory of this script\nsrc=\"${BASH_SOURCE[0]}\"\nwhile [ -L \"$src\" ]; do\n  dir=\"$(cd -P \"$(dirname \"$src\")\" && pwd)\"\n  src=\"$(readlink \"$src\")\"\n  [[ $src != /* ]] && src=\"$dir/$src\"\ndone\nMYDIR=\"$(cd -P \"$(dirname \"$src\")\" && pwd)\"\n\n# Herbie path\nHERBIE=\"$MYDIR/../..\"\n\n# handle inputs\nif [ \"$#\" -ne 3 ]; then\n    echo \"Usage: $0 NUM_SEEDS BENCH_PATH RESULT_PATH\"\n  exit 1\nelse\n    NSEEDS=\"$1\"; shift\n    BENCH=\"$1\"; shift\n    RESPATH=\"$1\"; shift\nfi\n\necho \"Running on benchmarks at $HERBIE/$BENCH\"\necho \"Writing results to $RESPATH\"\n\n# advise user of threads\nif [ -z \"$THREADS\" ]; then\n  THREADS=\"yes\"\n  echo \"Using maximum number of threads\"\nelse\n  # support for exporting bash environment to parallel\n  echo \"Using $THREADS threads for each run\"\nfi\n\n# advise user of execution plan\nif [ -z \"$PARALLEL_SEEDS\" ]; then\n  echo \"Using Herbie concurrency only.\"\nelse\n  # support for exporting bash environment to parallel\n  source $(which env_parallel.bash)\n  env_parallel --record-env\n\n  echo \"Using multiple concurrent Herbie runs in parallel.\"\n  echo \"Restricting to $PARALLEL_SEEDS parallel concurrent Herbie runs.\"\nfi\n\n#\n#   SAMPLE SEEDS\n#\n\n# allocate space for output\ntstamp=\"$(date \"+%Y-%m-%d_%H%M\")\"\noutput=\"$(pwd)/$RESPATH/$tstamp\"\nmkdir -p \"$output\"\n\nfunction do_seed {\n  seed=\"$1\"\n\n  seed_output=\"$output/$(printf \"%03d\" \"$seed\")\"\n  mkdir -p \"$seed_output\"\n\n  racket -y \"$HERBIE/src/main.rkt\" report \\\n    --threads $THREADS \\\n    --seed \"$seed\" \\\n    $HERBIE_FLAGS \\\n    \"$HERBIE/$BENCH\" \\\n    \"$seed_output\"\n}\n\n# sample herbie behavior\nif [ -z \"$PARALLEL_SEEDS\" ]; then\n  # by default, do not use parallel\n  for seed in $(seq \"$NSEEDS\"); do\n    do_seed \"$seed\"\n  done\nelse\n  # conditionally use parallel\n  #\n  # Note that Herbie can already use up to # of benchmarks cores,\n  # so this probably only makes sense if you have PARALLEL_SEEDS\n  # set to something less than # of cores divided by # of benchmarks,\n  # i.e., you have a lot of cores. We're not at all careful to get\n  # solid timing numbers, but going higher any than that will make\n  # any time measurements even less meaningful.\n  seq \"$NSEEDS\" \\\n    | env_parallel \\\n        --env _ \\\n        --jobs \"$PARALLEL_SEEDS\" \\\n        --halt now,fail=1 \\\n        do_seed\nfi\n\n\n#\n#   COLLECT OUTPUT\n#\n\npushd \"$output\"\n\necho \"[\" > all.json\nfirst=true\n\nfor rj in $(find . -name 'results.json' | sort); do\n  if $first; then\n    first=false\n  else\n    echo \",\" >> all.json\n  fi\n\n  seed=\"$(jq '.seed' \"$rj\")\"\n  npts=\"$(jq '.points' \"$rj\")\"\n  herbie_iters=\"$(jq '.iterations' \"$rj\")\"\n\n  # warn about errors and timeouts that will be filtered out\n\n  errors=\"$(jq '.tests | map(select(.status == \"error\"))' \"$rj\")\"\n  if [ \"$errors\" != \"[]\" ]; then\n    echo \"WARNING: filtering out errors in $rj on seed $seed\"\n    echo \"$errors\"\n    echo \"$seed\" >> errors.json\n    echo \"$errors\" >> errors.json\n  fi\n\n  timeouts=\"$(jq '.tests | map(select(.status == \"timeout\"))' \"$rj\")\"\n  if [ \"$timeouts\" != \"[]\" ]; then\n    echo \"WARNING: filtering out timeouts in $rj on seed $seed\"\n    echo \"$timeouts\"\n    echo \"$seed\" >> timeouts.json\n    echo \"$timeouts\" >> timeouts.json\n  fi\n\n  cat \"$rj\" \\\n    | jq --argjson SEED \"$seed\" \\\n         --argjson NPTS \"$npts\" \\\n         --argjson HERBIE_ITERS \"$herbie_iters\" \\\n      '.tests | map(\n         select(.status != \"error\") |\n         select(.status != \"timeout\") |\n         { \"test\" : .name\n         , \"input\" : .input\n         , \"output\" : .output\n         , \"output_parens\" : (.output | [match(\"[(]\"; \"g\")] | length)\n         , \"avg_bits_err_input\": .start\n         , \"avg_bits_err_output\": .end\n         , \"avg_bits_err_improve\": (.start - .end)\n         , \"time_improve\": .time\n         , \"seed\": $SEED\n         , \"npts\": $NPTS\n         , \"herbie_iters\": $HERBIE_ITERS\n         })' \\\n    >> all.json\ndone\necho \"]\" >> all.json\n\n# flatten array of array of results to an array\njq 'flatten' all.json > all.json.tmp\nmv all.json.tmp all.json\n\npopd\n\n#\n#   PLOT RESULTS\n#\n\n$MYDIR/src/plot-results.sh \"$output\"\n"
  },
  {
    "path": "infra/survey/src/plot-results.sh",
    "content": "#!/usr/bin/env bash\n\n# determine physical directory of this script\nsrc=\"${BASH_SOURCE[0]}\"\nwhile [ -L \"$src\" ]; do\n  dir=\"$(cd -P \"$(dirname \"$src\")\" && pwd)\"\n  src=\"$(readlink \"$src\")\"\n  [[ $src != /* ]] && src=\"$dir/$src\"\ndone\nMYDIR=\"$(cd -P \"$(dirname \"$src\")\" && pwd)\"\n\n# caller should pass path to output from sampler\ncd \"$1\"\n\nif [ ! -f \"all.json\" ]; then\n  echo \"ERROR: no 'all.json' in '$1'\"\n  exit 1\nfi\n\n# munge and plot results\njq 'group_by(.seed)' all.json > by-seed.json\njq 'group_by(.test)' all.json > by-test.json\n\nfunction plot-seed-field {\n  field=\"$1\"\n\n  cat by-seed.json \\\n    | jq --arg FIELD \"$field\" \\\n        'map({ \"seed\": .[0].seed\n             , \"data\": map(.[$FIELD]) | add\n             })' \\\n    > \"by-seed-${field}.json\"\n\n  python3 \"$MYDIR/seed-violin-plot.py\" \\\n    \"by-seed-${field}.json\" \\\n    \"$field\"\n\n  python3 \"$MYDIR/seed-bar-chart.py\" \\\n    \"by-seed-${field}.json\" \\\n    \"$field\"\n}\n\nfunction plot-test-field {\n  field=\"$1\"\n\n  cat by-test.json \\\n    | jq --arg FIELD \"$field\" \\\n        'map({ \"test\": .[0].test\n             , \"data\": map(.[$FIELD])\n             })' \\\n    > \"by-test-${field}.json\"\n\n  python3 \"$MYDIR/test-violin-plot.py\" \\\n    \"by-test-${field}.json\" \\\n    \"$field\"\n}\n\nfunction plot-test-versus {\n  x=\"$1\"\n  y=\"$2\"\n\n  cat by-test.json \\\n    | jq --arg X \"$x\" --arg Y \"$y\" \\\n        'map({ \"test\": .[0].test\n             , \"x\": map(.[$X])\n             , \"y\": map(.[$Y])\n             })' \\\n    > \"by-test-${x}-versus-${y}.json\"\n\n  python3 \"$MYDIR/test-versus-plot.py\" \\\n    \"by-test-${x}-versus-${y}.json\" \\\n    \"$x\" \"$y\"\n}\n\n\nfields=\"\n  output_parens\n  avg_bits_err_input\n  avg_bits_err_output\n  avg_bits_err_improve\n  time_improve\"\n\nfor f in $fields; do\n  plot-seed-field \"$f\"\ndone\n\nfor f in $fields; do\n  plot-test-field \"$f\"\ndone\n\nmkdir \"versus-plots\"\nplot-test-versus \"time_improve\"  \"avg_bits_err_output\"\nplot-test-versus \"time_improve\"  \"output_parens\"\nplot-test-versus \"output_parens\" \"avg_bits_err_output\"\n## plot-test-versus \"time_improve\"  \"avg_bits_err_improve\"\n## plot-test-versus \"output_parens\" \"avg_bits_err_improve\"\n"
  },
  {
    "path": "infra/survey/src/seed-bar-chart.py",
    "content": "import sys\nimport json\nimport matplotlib.pyplot as plt\nimport numpy as np\n\njsonp = sys.argv[1]\nfield = sys.argv[2]\n\nwith open(jsonp, 'r') as f:\n    ss = json.load(f)\n\nlabs = [s['seed'] for s in ss]\ndata = [s['data'] for s in ss]\n\nfig, ax = plt.subplots(figsize=(30, 10))\nx = np.arange(len(data))\nax.bar(x, data)\n\nax.set_xlabel('seed')\nax.set_xticks(x)\nax.set_xticklabels(range(1, len(labs) + 1))\nax.set_xticklabels(labs, rotation=45, ha='right')\n\nax.set_ylabel('sum({})'.format(field))\n\nplt.tight_layout()\nplt.savefig('by-seed-{}-bar.pdf'.format(field))\n"
  },
  {
    "path": "infra/survey/src/seed-violin-plot.py",
    "content": "import sys\nimport json\nimport matplotlib.pyplot as plt\nimport numpy as np\n\njsonp = sys.argv[1]\nfield = sys.argv[2]\n\nwith open(jsonp, 'r') as f:\n    ss = json.load(f)\n\nlabs = [s['seed'] for s in ss]\ndata = [s['data'] for s in ss]\n\nfig, ax = plt.subplots()\nax.violinplot(data)\nax.set_xlabel('{} seeds'.format(len(data)))\n\nax.set_ylabel('sum({})'.format(field))\n\nplt.tight_layout()\nplt.savefig('by-seed-{}-violin.pdf'.format(field))\n"
  },
  {
    "path": "infra/survey/src/test-versus-plot.py",
    "content": "import sys\nimport json\nimport matplotlib.pyplot as plt\nimport numpy as np\n\njsonp = sys.argv[1]\nx_field = sys.argv[2]\ny_field = sys.argv[3]\n\nwith open(jsonp, 'r') as f:\n    ts = json.load(f)\n\nfor t in ts:\n    fig, ax = plt.subplots(figsize=(10,10))\n    ax.scatter(t['x'], t['y'])\n\n    ax.set_title('{}: {} vs. {}'.format(t['test'], x_field, y_field))\n    ax.set_xlabel(x_field)\n    ax.set_ylabel(y_field)\n\n    plt.tight_layout()\n    p = 'versus-plots/by-test-{}-{}-versus-{}.pdf'.format(\n            t['test'], x_field, y_field)\n    plt.savefig(p)\n    plt.close(fig)\n"
  },
  {
    "path": "infra/survey/src/test-violin-plot.py",
    "content": "import sys\nimport json\nimport matplotlib.pyplot as plt\nimport numpy as np\n\njsonp = sys.argv[1]\nfield = sys.argv[2]\n\nwith open(jsonp, 'r') as f:\n    ts = json.load(f)\n\nlabs = [t['test'] for t in ts]\ndata = [t['data'] for t in ts]\n\nfig, ax = plt.subplots(figsize=(30,10))\nax.violinplot(data)\n\nax.set_xlabel('test')\nax.set_xticks(np.arange(1, len(labs) + 1))\nax.set_xticklabels(labs, rotation=45, ha='right')\n\nax.set_ylabel(field)\nax.set_yticks(np.arange(0, 64, step=4))\n\nplt.tight_layout()\nplt.savefig('by-test-{}-violin.pdf'.format(field))\n"
  },
  {
    "path": "infra/survey.rkt",
    "content": "#lang racket\n(require json\n         xml)\n(require \"../src/api/datafile.rkt\")\n\n(define metrics\n  (list `(start . ,table-row-start) `(end . ,table-row-result) `(time . ,table-row-time)))\n\n(define (merge-results . dirs)\n  (define results\n    (filter (conjoin (negate eof-object?) identity)\n            (for/list ([dir (in-list dirs)])\n              (with-handlers ([exn? (const #f)])\n                (call-with-input-file (build-path dir \"results.json\") read-datafile)))))\n  (for/hash ([group (group-by table-row-name (append-map report-info-tests results))])\n    (values (table-row-name (first group))\n            (for/hash ([(name metric) (in-dict metrics)])\n              (values name (map metric group))))))\n\n(define style\n  \"\nsection { overflow: auto; }\nh2 { font-size: 100%; font-family: sans-serif; margin: 3em 0 0; }\nh3 { text-transform: uppercase; font-size: 80%; color: steelblue}\nsection > div { width: 500; float: left; margin-right: 20px; }\n\")\n\n(define (results->html results out)\n  (fprintf out \"<!doctype html>\\n\")\n  (write-xexpr\n   `(html\n     (head (meta ([charset \"utf-8\"]))\n           (title \"Seed survey results\")\n           (style ,(make-cdata #f #f style))\n           (script ([src \"report.js\"])))\n     (body\n      (h1 ,(format \"Seed survey for ~a benchmarks\" (hash-count results)))\n      ,@\n      (for/list ([(name metrics) (in-dict results)]\n                 [n (in-naturals)])\n        `(section\n          (h2 ,(~a name))\n          ,@\n          (for/list ([(name values) (in-dict metrics)])\n            `(div\n              (h3 ,(~a name))\n              (canvas\n               ([id ,(format \"~a-~a\" name n)]\n                [title\n                 \"Weighted histogram; height corresponds to percentage of runtime in that bucket.\"]))\n              (script \"histogram(\\\"\"\n                      ,(format \"~a-~a\" name n)\n                      \"\\\", \"\n                      ,(jsexpr->string values)\n                      \", \"\n                      ,(jsexpr->string (hash 'width\n                                             400\n                                             'proportional\n                                             #f\n                                             'buckets\n                                             32.0\n                                             'max\n                                             (if (equal? name 'time)\n                                                 (json-null)\n                                                 64.0)))\n                      \")\")))))))\n   out))\n\n(module+ main\n  (command-line #:args (outdir . dirs)\n                (define data (apply merge-results dirs))\n                (printf \"Read in data on ~a items\\n\" (hash-count data))\n                (call-with-output-file (build-path outdir \"survey.html\")\n                                       #:exists 'replace\n                                       (λ (p) (results->html data p)))))\n"
  },
  {
    "path": "infra/test-api.mjs",
    "content": "// -*- mode: js -*-\n\nimport { strict as assert } from 'node:assert';  // use strict equality everywhere \nimport { spawn } from 'child_process';\nimport net from 'net';\n\n/* Step 1: we start the Herbie server for testing */\n\nfunction getFreePort() {\n    return new Promise((resolve, reject) => {\n        const server = net.createServer();\n        server.listen(0, () => {\n            const { port } = server.address();\n            server.close(() => resolve(port));\n        });\n        server.on('error', reject);\n    });\n}\n\nconst PORT = await getFreePort();\n\nconsole.log(\"Spawning server on port \" + PORT)\nconst child = spawn('racket', ['-y', 'src/main.rkt', 'web', '--threads', '2', '--quiet', '--port', \"\"+PORT]);\n\nchild.stdout.on('data', (data) => {\n    console.log(\"\"+data);\n});\n\nchild.stderr.on('data', (data) => {\n    console.error(\"\"+data);\n});\n\nchild.on('close', (code) => {\n    if (code) console.log(\"Server crashed with code \" + code);\n});\n\nprocess.on('exit', () => {\n  child.kill('SIGTERM'); // or any appropriate signal\n});\n\nfunction waitForPort(port) {\n  return new Promise(resolve => {\n    const attempt = () => {\n      const socket = net.connect(port, 'localhost', () => {\n        socket.end();\n        resolve();\n      });\n      socket.on('error', () => setTimeout(attempt, 500));\n    };\n    attempt();\n  });\n}\n\nawait waitForPort(PORT)\nconsole.log(\"Server up and responding on port \" + PORT)\n\nfunction makeURL(endpoint) {\n  return new URL(`http://127.0.0.1:${PORT}${endpoint}`)\n}\n\n/* Step 2: Test the formal API */\n\n// Reusable testing data\nconst SAMPLE_SIZE = 8256\n\nconst FPCoreFormula = '(FPCore (x) (- (sqrt (+ x 1)) (sqrt x)))'\nconst FPCoreFormula2 = '(FPCore (x) (- (sqrt (+ x 1))))'\nconst FPCoreFormula3 = '(FPCore (x) (if (<= (- (sqrt (+ x 1.0)) (sqrt x)) 0.05) (* 0.5 (sqrt (/ 1.0 x))) (fma (fma (- 0.125) x 0.5) x (- 1.0 (sqrt x)))))'\nconst eval_sample = [[[1], -1.4142135623730951]]\n\nasync function testAPI(url, body, cb) {\n    console.log(\"Testing endpoint \" + url)\n\n    let sync_start = Date.now()\n    const sync_resp = await fetch(makeURL(url), {\n        method: 'POST',\n        body: JSON.stringify(body),\n    });\n    assert.ok(sync_resp.headers.get(\"x-herbie-job-id\"));\n    const sync_json = await sync_resp.json();\n    assert.equal(sync_json.job.length > 0, true)\n    assert.equal(sync_json.path.includes(\".\"), true)\n\n    console.log(\"  Synchronous response in \" + Math.round(Date.now() - sync_start) + \"ms\")\n    cb(sync_json);\n\n    let async_start = Date.now()\n    let start_resp = await fetch(makeURL(url.replace(\"/api\", \"/api/start\")), {\n        method: 'POST',\n        body: JSON.stringify(body),\n    })\n    let jobid = (await start_resp.json()).job;\n\n    // This loop is a sort of 10 second timeout for the test.\n    for (let i = 0; i < 100; i++) {\n        let status_resp = await fetch(makeURL(\"/check-status/\" + jobid));\n        if (status_resp.status == 201) break;\n        await new Promise(r => setTimeout(r, 100)); // Wait 100ms\n    }\n    let async_resp = await fetch(makeURL(\"/api/result/\" + jobid));\n    let async_json = await async_resp.json();\n\n    console.log(\"  Asynchronous response in \" + Math.round(Date.now() - async_start) + \"ms\")\n    cb(async_json);\n}\n\nlet POINTS = null;\n\n// Sample endpoint\nawait testAPI(\"/api/sample\", {\n    formula: FPCoreFormula2,\n    seed: 5,\n}, (body) => {\n    assert.ok(body.points);\n    assert.equal(body.points.length, SAMPLE_SIZE);\n    if (!POINTS) {\n        POINTS = body.points;\n    } else {\n        // Test reproducibility between sync and async call\n        assert.deepEqual(POINTS, body.points);\n    }\n});\n\n// Explanations endpoint\nawait testAPI(\"/api/explanations\", {\n  formula: FPCoreFormula,\n  sample: POINTS\n}, (body) => {\n  assert.equal(body.explanation.length > 0, true, 'explanation should not be empty');\n});\n\n// Analyze endpoint\nawait testAPI(\"/api/analyze\", {\n  formula: FPCoreFormula,\n  sample: [[[14.97651307489794], 0.12711304680349078]]\n}, (body) => {\n  assert.deepEqual(body.points, [[[14.97651307489794], \"2.3\"]]);\n});\n\n// Local error endpoint\nawait testAPI(\"/api/localerror\", {\n  formula: FPCoreFormula,\n  sample: eval_sample\n}, (body) => {\n  assert.ok(body.tree['avg-error'] > 0);\n});\n\nconst localError1 = await (await fetch(makeURL(\"/api/localerror\"), {\n  method: 'POST', body: JSON.stringify({\n    formula: FPCoreFormula, sample: [[[2.852044568544089e-150], 1e+308]], seed: 5\n  })\n})).json()\nconst localError2 = await (await fetch(makeURL(\"/api/localerror\"), {\n  method: 'POST', body: JSON.stringify({\n    formula: FPCoreFormula, sample: [[[1.5223342548065899e-15], 1e+308]], seed: 5\n  })\n})).json()\n// Test that different sample points produce different job ids ensuring that different results are served for these inputs.\nassert.notEqual(localError1.job, localError2.job)\n// Assert local error works for default example.\nconst ignoredValue = 1e+308\n'(FPCore (1e-100) (- (sqrt (+ x 1)) (sqrt x)))'\nconst localError5 = await (await fetch(makeURL(\"/api/localerror\"), {\n  method: 'POST', body: JSON.stringify({\n    formula: FPCoreFormula, sample: [[[1e-100], ignoredValue]], seed: 5\n  })\n})).json()\n\n// avg_error, actual_value, exact_value, absolute_difference, ulps_error\n// root node\ncheckLocalErrorNode(localError5.tree, [],\n  '-', '0.0', '1.0', '1.0', '1e-50', '0.0')\n// left sqrt\ncheckLocalErrorNode(localError5.tree, [0],\n  'sqrt', '0.0', '1.0', '1.0', '5e-101', '0.0')\n// right sqrt \ncheckLocalErrorNode(localError5.tree, [1],\n  'sqrt', '0.0', '1e-50', '1e-50', '2.379726195519099e-68', '0.0')\n// plus \ncheckLocalErrorNode(localError5.tree, [0, 0],\n  '+', '0.0', '1.0', '1.0', '1e-100', '0.0')\n// var x\ncheckLocalErrorNode(localError5.tree, [0, 0, 0],\n  'x', '0.0', '1e-100', '1e-100', 'equal', '0.0')\n// literal 1\ncheckLocalErrorNode(localError5.tree, [0, 0, 1],\n  '1.0', '0.0', '1.0', '1.0', 'equal', '0.0')\n\n// '(FPCore (1e100) (- (sqrt (+ x 1)) (sqrt x)))'\nconst localError6 = await (await fetch(makeURL(\"/api/localerror\"), {\n  method: 'POST', body: JSON.stringify({\n    formula: FPCoreFormula, sample: [[[1e100], ignoredValue]], seed: 5\n  })\n})).json()\n// avg_error, actual_value, exact_value, absolute_error, ulps_error\n// root node\ncheckLocalErrorNode(localError6.tree, [],\n  '-', '61.7', '0.0', '5e-51', '5e-51', '61.74124908607812')\n// left sqrt\ncheckLocalErrorNode(localError6.tree, [0],\n  'sqrt', '0.0', '1e+50', '1e+50', '6.834625285603891e+33', '0.0')\n// right sqrt \ncheckLocalErrorNode(localError6.tree, [1],\n  'sqrt', '0.0', '1e+50', '1e+50', '6.834625285603891e+33', '0.0')\n// plus \ncheckLocalErrorNode(localError6.tree, [0, 0],\n  '+', '0.0', '1e+100', '1e+100', '1.0', '0.0')\n// var x\ncheckLocalErrorNode(localError6.tree, [0, 0, 0],\n  'x', '0.0', '1e+100', '1e+100', 'equal', '0.0')\n// literal 1\ncheckLocalErrorNode(localError6.tree, [0, 0, 1],\n  '1.0', '0.0', '1.0', '1.0', 'equal', '0.0')\n\n// Test a large number `2e269` to trigger NaNs in local error\nconst localError7 = await (await fetch(makeURL(\"/api/localerror\"), {\n  method: 'POST', body: JSON.stringify({\n    formula: FPCoreFormula3, sample: [[[2e269], ignoredValue]], seed: 5\n  })\n})).json()\n// Test against conditionals expressions\ncheckLocalErrorNode(localError7.tree, [0],\n  '<=', '0.0', 'true', 'true', 'equal', '0.0')\ncheckLocalErrorNode(localError7.tree, [0, 0],\n  '-', '61.2', '0.0', '1.1180339887498948e-135', '1.1180339887498948e-135', '61.16647760559045')\ncheckLocalErrorNode(localError7.tree, [0, 1],\n  '0.05', '0.0', '0.05', '0.05', 'equal', '0.0')\ncheckLocalErrorNode(localError7.tree, [2],\n  'fma', '0.0', '-inf.0', '-inf.0', '+inf.0', '0.0')\n\n/// root: The root node of the local error tree.\n/// path: the path to get to the node you want to test.\n/// name: Name of the node you are testing\n/// avg_error: Average Error\n/// actual_value: Value of the node\n/// exact_value: The correct evaluation of the expression\n/// absolute_difference: The ABS of the error at the node |approx - exact|\n/// ulps_error: ulps of error at this node.\nfunction checkLocalErrorNode(root, path, name,\n  avg_error, actual_value, exact_value, absolute_difference, ulps_error) {\n  const node = getNodeFromPath(root, path)\n  // console.log(node) // Helpful for seeing which node is failing a test\n  assert.equal(node['e'], name)\n  assert.equal(node['avg-error'], avg_error)\n  assert.equal(node['actual-value'], actual_value)\n  assert.equal(node['exact-value'], exact_value)\n  assert.equal(node['abs-error-difference'], absolute_difference)\n  assert.equal(node['ulps-error'], ulps_error)\n}\n\nfunction getNodeFromPath(node, path) {\n  if (path.length > 0) {\n    const index = path.shift()\n    const child = node['children'][index]\n    return getNodeFromPath(child, path)\n  } else {\n    return node\n  }\n}\n\n// Alternatives endpoint\nawait testAPI(\"/api/alternatives\", {\n  formula: FPCoreFormula,\n  sample: [[[14.97651307489794], 0.12711304680349078]]\n}, (body) => {\n  assert.ok(Array.isArray(body.alternatives));\n});\n\n// Cost endpoint\nawait testAPI(\"/api/cost\", {\n  formula: FPCoreFormula2,\n  sample: eval_sample\n}, (body) => {\n  assert.ok(body.cost > 0);\n});\n\n// MathJS endpoint\nconst mathjs = await (await fetch(makeURL(\"/api/mathjs\"), {\n  method: 'POST', body: JSON.stringify({ formula: FPCoreFormula })\n})).json()\nassert.equal(mathjs.mathjs, \"sqrt(x + 1.0) - sqrt(x)\")\n\nconsole.log(\"Testing translation API\");\n\nasync function testTranslate(language, result) {\n    let start = Date.now()\n    const resp = await fetch(makeURL(\"/api/translate\"), {\n        method: 'POST',\n        body: JSON.stringify({\n            formula: FPCoreFormula,\n            language: language,\n        }),\n    });\n    const json = await resp.json();\n\n    console.log(\"  Translation to \" + language + \" in \" + Math.round(Date.now() - start) + \"ms\")\n    assert.equal(json.result.trim().replace(\"\\t\", \"    \"), result.trim());\n}\n\nawait testTranslate(\"python\", `\ndef expr(x):\n    return math.sqrt((x + 1.0)) - math.sqrt(x)`);\n\nawait testTranslate(\"c\", `\ndouble expr(double x) {\n    return sqrt((x + 1.0)) - sqrt(x);\n}`);\n\nawait testTranslate(\"fortran\", `\nreal(8) function expr(x)\nuse fmin_fmax_functions\n    real(8), intent (in) :: x\n    expr = sqrt((x + 1.0d0)) - sqrt(x)\nend function`);\n\nawait testTranslate(\"java\", `\npublic static double expr(double x) {\n    return Math.sqrt((x + 1.0)) - Math.sqrt(x);\n}`);\n\nawait testTranslate(\"julia\", `\nfunction expr(x)\n    return Float64(sqrt(Float64(x + 1.0)) - sqrt(x))\nend`);\n\nawait testTranslate(\"matlab\", `\nfunction tmp = expr(x)\n    tmp = sqrt((x + 1.0)) - sqrt(x);\nend`);\n\nawait testTranslate(\"wls\", 'expr[x_] := N[(N[Sqrt[N[(x + 1), $MachinePrecision]], $MachinePrecision] - N[Sqrt[x], $MachinePrecision]), $MachinePrecision]')\n\nawait testTranslate(\"tex\", '\\\\mathsf{expr}\\\\left(x\\\\right) = \\\\sqrt{x + 1} - \\\\sqrt{x}')\n\n/* Step 3: Test the legacy HTTP endpoints */\n\nconsole.log(\"Testing legacy endpoints\")\n\n// improve endpoint\nconst improveResponse = await fetch(makeURL(`/improve?formula=${encodeURIComponent(FPCoreFormula2)}`), { method: 'GET' })\nassert.equal(improveResponse.status, 200)\nlet redirect = improveResponse.url.split(\"/\")\nconst jobID = redirect[3].split(\".\")[0]\n// This test is a little flaky as the character count of the response is not consistent.\n// const improveHTML = await improveResponse.text()\n// const improveHTMLexpectedCount = 25871\n// assert.equal(improveHTML.length, improveHTMLexpectedCount, `HTML response character count should be ${improveHTMLexpectedCount} unless HTML changes.`)\n\n// timeline\nconst timelineRSP = await fetch(makeURL(`/timeline/${jobID}`), { method: 'GET' })\nassert.equal(timelineRSP.status, 201)\nconst timeline = await timelineRSP.json()\nassert.equal(timeline.length > 0, true)\n\n// Test with a likely missing job-id\nconst badTimelineRSP = await fetch(makeURL(\"/timeline/42069\"), { method: 'GET' })\nassert.equal(badTimelineRSP.status, 404)\nconst check_missing_job = await fetch(makeURL(`/check-status/42069`), { method: 'GET' })\nassert.equal(check_missing_job.status, 202)\n\n// improve-start endpoint\nconst URIencodedBody = \"formula=\" + encodeURIComponent(FPCoreFormula)\nconst startResponse = await fetch(makeURL(\"/api/start/improve\"), {\n  method: 'POST',\n  headers: {\n    'Content-Type': 'application/x-www-form-urlencoded',\n  },\n  body: URIencodedBody\n})\nconst testResult = (startResponse.status == 201 || startResponse.status == 202)\nassert.equal(testResult, true)\nconst improveResultPath = startResponse.headers.get(\"location\")\nlet counter = 0\nlet cap = 100\n// Check status endpoint\nlet checkStatus = await fetch(makeURL(improveResultPath), { method: 'GET' })\n/*\nThis is testing if the /api/start/improve test at the beginning has been completed. The cap and counter is a sort of timeout for the test. Ends up being 10 seconds max.\n*/\nwhile (checkStatus.status != 201 && counter < cap) {\n  counter += 1\n  checkStatus = await fetch(makeURL(improveResultPath), { method: 'GET' })\n  await new Promise(r => setTimeout(r, 100)); // ms\n}\nassert.equal(checkStatus.statusText, 'Job complete')\n\n// up endpoint\nconst up = await fetch(makeURL(\"/up\"), { method: 'GET' })\nassert.equal('Up', up.statusText) // Herbie runs single thread on CI.\n\n// Results.json endpoint\nconst jsonResults = await (await fetch(makeURL(\"/results.json\"), { method: 'GET' })).json()\n\n// Basic test that checks that there are the two results after the above test.\n// TODO add a way to reset the results.json file?\nassert.equal(jsonResults.tests.length, 2)\n\n\nchild.kill('SIGINT');\n"
  },
  {
    "path": "src/api/datafile.rkt",
    "content": "#lang racket\n\n(require json\n         racket/date)\n(require \"../syntax/platform.rkt\"\n         \"../syntax/types.rkt\"\n         \"../utils/common.rkt\"\n         \"../reports/data.rkt\")\n\n(provide (struct-out table-row)\n         (struct-out report-info)\n         make-report-info\n         read-datafile\n         write-datafile\n         merge-datafiles)\n\n(define (make-report-info tests #:seed [seed #f])\n  (report-info (current-date)\n               *herbie-commit*\n               *herbie-branch*\n               (or seed (get-seed))\n               (*flags*)\n               (*num-points*)\n               (*num-iterations*)\n               tests))\n\n(define (write-datafile file info)\n  (define (simplify-test test)\n    (match-define (table-row name\n                             identifier\n                             status\n                             pre\n                             prec\n                             conversions\n                             vars\n                             warnings\n                             input\n                             output\n                             spec\n                             target-prog\n                             start-bits\n                             end-bits\n                             target-bits\n                             time\n                             link\n                             cost-accuracy)\n      test)\n    (define bits (representation-total-bits (get-representation prec)))\n    (make-hash `((name . ,name) (identifier . ,(~s identifier))\n                                (pre . ,(~s pre))\n                                (prec . ,(~s prec))\n                                (bits . ,(representation-total-bits (get-representation prec)))\n                                (conversions . ,(map (curry map ~s) conversions))\n                                (status . ,status)\n                                (start . ,start-bits)\n                                (end . ,end-bits)\n                                (target . ,target-bits)\n                                (vars . ,(and vars (map symbol->string vars)))\n                                (warnings . ,warnings)\n                                (input . ,(~s input))\n                                (output . ,(~s output))\n                                (spec . ,(if (equal? spec input)\n                                             #f\n                                             (~s spec)))\n                                (target-prog . ,(~s target-prog))\n                                (time . ,time)\n                                (link . ,(~a link))\n                                (cost-accuracy . ,cost-accuracy))))\n\n  (define data\n    (match info\n      [(report-info date commit branch seed flags points iterations tests)\n       (make-hash `((date . ,(date->seconds date)) (commit . ,commit)\n                                                   (branch . ,branch)\n                                                   (seed . ,(~a seed))\n                                                   (flags . ,(flags->list flags))\n                                                   (points . ,points)\n                                                   (iterations . ,iterations)\n                                                   (tests . ,(map simplify-test tests))))]))\n\n  (if (port? file)\n      (write-json data file)\n      (call-with-atomic-output-file file (λ (p name) (write-json data p)))))\n\n(define (flags->list flags)\n  (for*/list ([rec (hash->list flags)]\n              [fl (cdr rec)])\n    (format \"~a:~a\" (car rec) fl)))\n\n(define (list->flags list)\n  (make-hash (for/list ([part (group-by car\n                                        (map (compose (curry map string->symbol)\n                                                      (curryr string-split \":\"))\n                                             list))])\n               (cons (car (first part)) (map cadr part)))))\n\n(define (read-datafile port)\n  (define (parse-string s)\n    (and s (call-with-input-string s read)))\n\n  (define json (read-json port))\n  (define (get field)\n    (hash-ref json field))\n  (report-info (seconds->date (get 'date))\n               (get 'commit)\n               (get 'branch)\n               (parse-string (get 'seed))\n               (list->flags (get 'flags))\n               (get 'points)\n               (get 'iterations)\n               (for/list ([test (get 'tests)]\n                          #:when (hash-has-key? test 'vars))\n                 (let ([get (λ (field) (hash-ref test field))])\n                   (define vars\n                     (match (hash-ref test 'vars)\n                       [(list names ...) (map string->symbol names)]\n                       [string-lst (parse-string string-lst)]))\n                   (define cost-accuracy (hash-ref test 'cost-accuracy '()))\n                   (table-row (get 'name)\n                              (parse-string (hash-ref test 'identifier \"#f\"))\n                              (get 'status)\n                              (parse-string (hash-ref test 'pre \"TRUE\"))\n                              (parse-string (hash-ref test 'prec \"binary64\"))\n                              (let ([cs (hash-ref test 'conversions \"()\")])\n                                (if (string? cs)\n                                    (parse-string cs)\n                                    (map (curry map parse-string) cs)))\n                              vars\n                              (hash-ref test 'warnings '())\n                              (parse-string (get 'input))\n                              (parse-string (get 'output))\n                              (or (parse-string (hash-ref test 'spec \"#f\"))\n                                  (parse-string (get 'input)))\n                              (parse-string (hash-ref test 'target-prog \"#f\"))\n                              (get 'start)\n                              (get 'end)\n                              (get 'target)\n                              (get 'time)\n                              (get 'link)\n                              cost-accuracy)))))\n\n(define (merge-datafiles dfs #:dirs [dirs #f])\n  (when (null? dfs)\n    (error 'merge-datafiles \"Cannot merge no datafiles\"))\n  (for ([f (in-list (list report-info-commit\n                          report-info-seed\n                          report-info-flags\n                          report-info-points\n                          report-info-iterations))]\n        #:unless (<= (set-count (list->set (map f dfs))) 1))\n    (error 'merge-datafiles \"Cannot merge datafiles at different ~a\" f))\n  (unless dirs\n    (set! dirs (map (const #f) dfs)))\n  (define tests\n    (for/list ([df (in-list dfs)]\n               [dir (in-list dirs)]\n               #:when true\n               [test (in-list (report-info-tests df))])\n      (struct-copy table-row\n                   test\n                   (link (if dir\n                             (format \"~a/~a\" dir (table-row-link test))\n                             (table-row-link test))))))\n\n  (report-info (last (sort (map report-info-date dfs) < #:key date->seconds))\n               (report-info-commit (first dfs))\n               (first (filter values (map report-info-branch dfs)))\n               (report-info-seed (first dfs))\n               (report-info-flags (first dfs))\n               (report-info-points (first dfs))\n               (report-info-iterations (first dfs))\n               tests))\n"
  },
  {
    "path": "src/api/demo.rkt",
    "content": "#lang racket\n\n(require json)\n(require racket/exn)\n(require openssl/sha1\n         (rename-in xml [location? xml-location?]))\n(require web-server/configuration/responders\n         web-server/dispatch\n         web-server/dispatch/extend\n         web-server/dispatchers/dispatch\n         web-server/http/bindings\n         web-server/managers/none\n         web-server/safety-limits\n         web-server/servlet\n         web-server/servlet-env)\n\n(require \"../config.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/read.rkt\"\n         \"../syntax/sugar.rkt\"\n         \"../syntax/platform.rkt\"\n         \"../syntax/load-platform.rkt\"\n         \"../utils/common.rkt\"\n         \"../utils/errors.rkt\"\n         \"../syntax/float.rkt\"\n         \"../core/points.rkt\"\n         \"../reports/common.rkt\"\n         \"../reports/core2mathjs.rkt\"\n         \"../reports/pages.rkt\"\n         \"datafile.rkt\"\n         \"sandbox.rkt\"\n         \"server.rkt\")\n\n(provide run-demo)\n\n(define *demo?* (make-parameter false))\n(define *demo-prefix* (make-parameter \"/\"))\n(define *demo-log* (make-parameter false))\n(define *demo-output* (make-parameter false))\n\n(define (add-prefix url)\n  (string-replace (string-append (*demo-prefix*) url) \"//\" \"/\"))\n\n(define-coercion-match-expander\n hash-arg/m\n (λ (x)\n   (and (not (and (*demo-output*) ; If we've already saved to disk, skip this job\n                  (directory-exists? (build-path (*demo-output*) x))))\n        (let ([m (regexp-match #rx\"^([0-9a-f]+)\\\\.[0-9a-f.]+\" x)]) (and m (job-status (second m))))))\n (λ (x)\n   (let ([m (regexp-match #rx\"^([0-9a-f]+)\\\\.[0-9a-f.]+\" x)])\n     (job-status (if m\n                     (second m)\n                     x)))))\n\n(define-bidi-match-expander hash-arg hash-arg/m hash-arg/m)\n\n(define-values (dispatch url*)\n  (dispatch-rules [(\"\") main]\n                  [(\"check-status\" (string-arg)) check-status]\n                  [(\"timeline\" (string-arg)) get-timeline]\n                  [(\"up\") check-up]\n                  [((hash-arg) (string-arg)) generate-page]\n                  [(\"results.json\") generate-report]\n                  [(\"improve\") #:method (or \"post\" \"get\" \"put\") improve]\n                  [(\"api\" \"result\" (string-arg)) get-result]\n                  [(\"api\" \"mathjs\") #:method \"post\" ->mathjs-endpoint]\n                  [(\"api\" \"translate\") #:method \"post\" translate-endpoint]\n                  [(\"api\" \"start\" \"improve\") #:method \"post\" improve-start]))\n\n(define (write-results-to-disk result-hash path)\n  (make-directory (build-path (*demo-output*) path))\n  (for ([page (all-pages result-hash)])\n    (call-with-output-file\n     (build-path (*demo-output*) path page)\n     (λ (out)\n       (with-handlers ([exn:fail? (page-error-handler result-hash page out)])\n         (make-page-timeout page out result-hash (*demo-output*) #f #:timeout 10000)))))\n  (define link (path-element->string (last (explode-path path))))\n  (define data (get-table-data-from-hash result-hash link))\n  (define data-file (build-path (*demo-output*) \"results.json\"))\n  (define html-file (build-path (*demo-output*) \"index.html\"))\n  (define info\n    (if (file-exists? data-file)\n        (let ([info (call-with-input-file data-file read-datafile)])\n          (struct-copy report-info info [tests (cons data (report-info-tests info))]))\n        (make-report-info (list data) #:seed (get-seed))))\n  (define tmp-file (build-path (*demo-output*) \"results.tmp\"))\n  (write-datafile tmp-file info)\n  (rename-file-or-directory tmp-file data-file #t)\n  (copy-file (web-resource \"report.html\") html-file #t))\n\n(define (generate-page req job-id page)\n  (define path (first (string-split (url->string (request-uri req)) \"/\")))\n  (define result-hash (job-results job-id))\n  (cond\n    [(set-member? (all-pages result-hash) page)\n     ;; Write page contents to disk\n     (when (*demo-output*)\n       (write-results-to-disk result-hash path))\n     (response 200\n               #\"OK\"\n               (current-seconds)\n               #\"text\"\n               (list (header #\"X-Job-Count\" (string->bytes/utf-8 (~a (server-count)))))\n               (λ (out)\n                 (with-handlers ([exn:fail? (page-error-handler result-hash page out)])\n                   (make-page-timeout page out result-hash (*demo-output*) #f #:timeout 1000))))]\n    [else (next-dispatcher)]))\n\n(define (generate-report req)\n  (cond\n    [(and (*demo-output*) (file-exists? (build-path (*demo-output*) \"results.json\")))\n     (next-dispatcher)]\n    [else\n     (define table-data\n       (for/list ([result (in-list (server-improve-results))])\n         (get-table-data-from-hash result (hash-ref result 'path))))\n     (define info (make-report-info table-data #:seed (get-seed)))\n     (response 200\n               #\"OK\"\n               (current-seconds)\n               #\"text\"\n               (list (header #\"X-Job-Count\" (string->bytes/utf-8 (~a (server-count)))))\n               (λ (out) (write-datafile out info)))]))\n\n(define url (compose add-prefix url*))\n\n(define (function-list . fn-classes)\n  (define (fn->html fn)\n    `(code ,(~a fn)))\n\n  (define (fn-class class)\n    (match-define (list fns description ...) class)\n    `((dt () ,@(add-between (map fn->html fns) \", \")) (dd () ,@description)))\n\n  `(dl ((class \"function-list\")) ,@(append-map fn-class fn-classes)))\n\n(define (herbie-page #:title title #:show-title [title? true] #:scripts [scripts '()] . body)\n  `(html (head (meta ([charset \"utf-8\"]))\n               (title ,title)\n               ,@(for/list ([script scripts])\n                   `(script ([src ,script] [type \"text/javascript\"])))\n               (link ([rel \"stylesheet\"] [type \"text/css\"] [href \"main.css\"])))\n         (body (header (img ((class \"logo\") [src \"/logo.png\"]))\n                       ,@(if title?\n                             `((h1 ,title))\n                             '()))\n               ,@body)))\n\n(define (main req)\n  (when (and (*demo-output*) (not (directory-exists? (*demo-output*))))\n    (make-directory (*demo-output*)))\n\n  (response/xexpr\n   #:preamble (list #\"<!doctype html>\")\n   #:headers (list (header #\"X-Job-Count\" (string->bytes/utf-8 (~a (server-count)))))\n   (herbie-page\n    #:title (if (*demo?*) \"Herbie web demo\" \"Herbie\")\n    #:show-title (*demo?*)\n    #:scripts '(\"//cdnjs.cloudflare.com/ajax/libs/mathjs/1.6.0/math.min.js\" \"demo.js\")\n    `(p\n      \"Write a formula below, and Herbie will try to improve it. Enter approximate ranges for inputs.\")\n    `(p ([id \"options\"])\n        (a ([id \"show-example\"]) \"Show an example\")\n        \" | \"\n        (a ([id \"use-fpcore\"]) \"Use FPCore\"))\n    (cond\n      [(server-up?)\n       `(form\n         ([action ,(url improve)] [method \"post\"] [id \"formula\"] [data-progress ,(url improve-start)])\n         (textarea ([name \"formula\"] [autofocus \"true\"]\n                                     [placeholder \"e.g. (FPCore (x) (- (sqrt (+ x 1)) (sqrt x)))\"]))\n         (input ([name \"formula-math\"] [placeholder \"e.g. sqrt(x + 1) - sqrt(x)\"]))\n         (table ([id \"input-ranges\"]))\n         (ul ([id \"errors\"]))\n         (ul ([id \"warnings\"]))\n         (button ([id \"run_herbie\"] [type \"submit\"] [tabindex \"-1\"]) \"Improve with Herbie\")\n         (pre ([id \"progress\"] [style \"display: none;\"])))]\n      [(*demo?*)\n       `(p ([id \"crashed\"])\n           \"Unfortunately, the online Herbie demo has crashed. The maintainers \"\n           \"have been notified and will restart Herbie when they've got a moment, \"\n           \"but if it's been a few days, it can help to \"\n           (a ([href \"https://github.com/herbie-fp/herbie/issues/new\"]\n               [title \"File a Herbie issue on Github\"])\n              \"file an issue\")\n           \".\")]\n      [else\n       `(p ([id \"crashed\"])\n           \"Unfortunately Herbie has crashed. You'll need to restart Herbie to \"\n           \"continue using it. Please also \"\n           (a ([href \"https://github.com/herbie-fp/herbie/issues/new\"]\n               [title \"File a Herbie issue on Github\"])\n              \"file a bug report\")\n           \" with any error messages you find in your terminal.\")])\n    (if (*demo?*)\n        `(p \"To handle the high volume of requests, web requests are queued; \"\n            \"there are \"\n            (span ([id \"num-jobs\"]) ,(~a (server-count)))\n            \" jobs in the queue right now. \"\n            \"Web demo requests may also time out and cap the number of improvement iterations. \"\n            \"To avoid these limitations, \"\n            (a ([href \"/doc/latest/installing.html\"]) \"install Herbie\")\n            \" on your own computer.\")\n        \"\")\n    `(p ([id \"lisp-instructions\"])\n        \"Please enter formulas as \"\n        (a ([href \"https://fpbench.org/spec/fpcore-1.0.html\"]) \"FPCore\")\n        \" expressions, including the top-level \"\n        (code \"FPCore\")\n        \" form, \"\n        \"using only the following supported functions:\")\n    `(p ([id \"mathjs-instructions\"] [style \"display: none;\"])\n        \"Use ordinary mathematical syntax (parsed by \"\n        (a ([href \"https://mathjs.org\"]) \"math.js\")\n        \")\"\n        \" and \"\n        (a ([href ,(format \"https://herbie.uwplse.org/doc/~a/input.html\" *herbie-version*)])\n           \"standard functions\")\n        \" like:\")\n    (function-list '((+ - * / abs) \"The usual arithmetic functions\")\n                   '((and or) \"Logical connectives (for preconditions)\")\n                   '((pow) \"Raising a value to a power\")\n                   '((exp log) \"Natural exponent and natural log\")\n                   '((sin cos tan) \"The trigonometric functions\")\n                   '((asin acos atan) \"The inverse trigonometric functions\")\n                   '((sqrt cbrt) \"Square and cube roots\")\n                   '((PI E) \"The mathematical constants\"))\n    `(p (em \"Note\")\n        \": \"\n        ,@(cond\n            [(not (*demo-output*)) '(\"formulas submitted here are not logged.\")]\n            [(*demo?*)\n             `(\"all formulas submitted here are logged and made public.\"\n               (a ([href \"./index.html\"]) \" See what formulas other users submitted.\"))]\n            [else `(\"all formulas submitted here are \" (a ([href \"./index.html\"]) \"logged\") \".\")])))))\n\n(define ((post-with-json-response fn) req)\n  (define post-body (request-post-data/raw req))\n  (define post-data\n    (cond\n      [post-body (bytes->jsexpr post-body)]\n      [#t #f]))\n  (define resp\n    (with-handlers ([exn:fail? (λ (e) (hash 'error (exn->string e)))])\n      (fn post-data)))\n  (when (hash-has-key? resp 'error)\n    (eprintf \"Error handling request: ~a\\n\" (hash-ref resp 'error)))\n  (if (hash-has-key? resp 'error)\n      (response 500\n                #\"Bad Request\"\n                (current-seconds)\n                APPLICATION/JSON-MIME-TYPE\n                (list (header #\"Access-Control-Allow-Origin\" (string->bytes/utf-8 \"*\")))\n                (λ (op) (write-json resp op)))\n      (response 200\n                #\"OK\"\n                (current-seconds)\n                APPLICATION/JSON-MIME-TYPE\n                (filter values\n                        (list (header #\"Access-Control-Allow-Origin\" (string->bytes/utf-8 \"*\"))\n                              (and (hash-has-key? resp 'job)\n                                   (header #\"X-Herbie-Job-ID\"\n                                           (string->bytes/utf-8 (hash-ref resp 'job))))))\n                (λ (op) (write-json resp op)))))\n\n(define (response/error title body)\n  (response/xexpr #:code 400\n                  #:message #\"Bad Request\"\n                  #:preamble (list #\"<!doctype html>\")\n                  (herbie-page #:title title body)))\n\n(define (get-result req job-id)\n  (match (job-results job-id)\n    [#f\n     (response 404\n               #\"Job Not Found\"\n               (current-seconds)\n               #\"text/plain\"\n               (list (header #\"X-Job-Count\" (string->bytes/utf-8 (~a (server-count))))\n                     (header #\"X-Herbie-Job-ID\" (string->bytes/utf-8 job-id))\n                     (header #\"Access-Control-Allow-Origin\" (string->bytes/utf-8 \"*\")))\n               void)]\n    [job-result\n     (response 201\n               #\"Job complete\"\n               (current-seconds)\n               #\"text/plain\"\n               (list (header #\"X-Job-Count\" (string->bytes/utf-8 (~a (server-count))))\n                     (header #\"X-Herbie-Job-ID\" (string->bytes/utf-8 job-id))\n                     (header #\"Access-Control-Allow-Origin\" (string->bytes/utf-8 \"*\")))\n               (curry write-json job-result))]))\n\n(define (improve-common req body go-back)\n  (match (extract-bindings 'formula (request-bindings req))\n    [(list formula-str)\n     (define formula\n       (with-handlers ([exn:fail? (λ (e) #f)])\n         (read-syntax 'web (open-input-string formula-str))))\n     (unless formula\n       (raise-herbie-error \"bad input: did you include special characters like `#`?\"))\n     (with-handlers ([exn:fail:user:herbie?\n                      (λ (e)\n                        (response/error\n                         \"Demo Error\"\n                         `(div\n                           (h1 \"Invalid formula\")\n                           (pre ,(herbie-error->string e))\n                           (p \"Formula must be a valid program using only the supported functions. \"\n                              \"Please \"\n                              (a ([href ,go-back]) \"go back\")\n                              \" and try again.\"))))])\n       (when (eof-object? formula)\n         (raise-herbie-error \"no formula specified\"))\n       (define test (parse-test formula))\n       (define job-id (job-start 'improve test #:seed (get-seed) #:profile? #f #:timeline? #t))\n       (body job-id))]\n    [_\n     (response/error \"Demo Error\"\n                     `(p \"You didn't specify a formula (or you specified several). \"\n                         \"Please \"\n                         (a ([href ,go-back]) \"go back\")\n                         \" and try again.\"))]))\n\n(define (improve-start req)\n  (improve-common\n   req\n   (λ (job-id)\n     (response/full 201\n                    #\"Job started\"\n                    (current-seconds)\n                    #\"text/plain\"\n                    (list (header #\"Location\" (string->bytes/utf-8 (url check-status job-id)))\n                          (header #\"X-Job-Count\" (string->bytes/utf-8 (~a (server-count))))\n                          (header #\"X-Herbie-Job-ID\" (string->bytes/utf-8 job-id)))\n                    '()))\n   (url main)))\n\n(define (check-status req job-id)\n  (match (job-timeline job-id)\n    [(? hash? result-hash)\n     (response/full 201\n                    #\"Job complete\"\n                    (current-seconds)\n                    #\"text/plain\"\n                    (list (header #\"Location\"\n                                  (string->bytes/utf-8\n                                   (add-prefix (format \"~a.~a/graph.html\" job-id *herbie-commit*))))\n                          (header #\"X-Job-Count\" (string->bytes/utf-8 (~a (server-count))))\n                          (header #\"X-Herbie-Job-ID\" (string->bytes/utf-8 job-id))\n                          (header #\"Access-Control-Allow-Origin\" (string->bytes/utf-8 \"*\")))\n                    '())]\n    [timeline\n     (response 202\n               #\"Job in progress\"\n               (current-seconds)\n               #\"text/plain\"\n               (list (header #\"X-Job-Count\" (string->bytes/utf-8 (~a (server-count))))\n                     (header #\"Access-Control-Allow-Origin\" (string->bytes/utf-8 \"*\")))\n               (λ (out)\n                 (when timeline\n                   (for ([entry timeline])\n                     (fprintf out \"Doing ~a\\n\" (hash-ref entry 'type))))))]))\n\n(define (check-up req)\n  (response/full (if (server-up?) 200 500)\n                 (if (server-up?) #\"Up\" #\"Down\")\n                 (current-seconds)\n                 #\"text/plain\"\n                 (list (header #\"X-Job-Count\" (string->bytes/utf-8 (~a (server-count))))\n                       (header #\"Access-Control-Allow-Origin\" (string->bytes/utf-8 \"*\")))\n                 '()))\n\n(define (improve req)\n  (improve-common req\n                  (λ (job-id)\n                    (job-wait job-id)\n                    (redirect-to (add-prefix (format \"~a.~a/graph.html\" job-id *herbie-commit*))\n                                 see-other))\n                  (url main)))\n\n(define (get-timeline req job-id)\n  (match (job-results job-id)\n    [#f\n     (response 404\n               #\"Job Not Found\"\n               (current-seconds)\n               #\"text/plain\"\n               (list (header #\"X-Job-Count\" (string->bytes/utf-8 (~a (server-count))))\n                     (header #\"X-Herbie-Job-ID\" (string->bytes/utf-8 job-id))\n                     (header #\"Access-Control-Allow-Origin\" (string->bytes/utf-8 \"*\")))\n               void)]\n    [job-result\n     (response 201\n               #\"Job complete\"\n               (current-seconds)\n               #\"text/plain\"\n               (list (header #\"X-Job-Count\" (string->bytes/utf-8 (~a (server-count))))\n                     (header #\"X-Herbie-Job-ID\" (string->bytes/utf-8 job-id))\n                     (header #\"Access-Control-Allow-Origin\" (string->bytes/utf-8 \"*\")))\n               (curry write-json (hash-ref job-result 'timeline)))]))\n\n(define-syntax-rule (define-api-endpoint (name post-data)\n                      body ...)\n  (begin\n    (define (function post-data)\n      body ...)\n    (define sync-fn\n      (post-with-json-response (lambda (post-data)\n                                 (define job-id (function post-data))\n                                 (job-wait job-id))))\n    (define async-fn\n      (post-with-json-response (lambda (post-data)\n                                 (define job-id (function post-data))\n                                 (hasheq 'job job-id 'path (job-path job-id)))))\n    (define-values (new-dispatch new-url)\n      (let ([old-dispatch dispatch])\n        (dispatch-rules [(\"api\" name) #:method \"post\" sync-fn]\n                        [(\"api\" \"start\" name) #:method \"post\" async-fn]\n                        [else old-dispatch])))\n    (set! dispatch new-dispatch)))\n\n(define (get-test post-data)\n  (define formula-str (hash-ref post-data 'formula))\n  (define formula (read-syntax 'web (open-input-string formula-str)))\n  (parse-test formula))\n\n; The name get-seed is taken.\n(define (parse-seed post-data)\n  (hash-ref post-data 'seed #f))\n\n(define (json->pcontext json ctx)\n  (define output-repr (context-repr ctx))\n  (define var-reprs (context-var-reprs ctx))\n  (define-values (pts exs)\n    (for/lists (pts exs)\n               ([entry (in-list json)])\n               (match-define (list pt ex) entry)\n               (unless (and (list? pt) (= (length pt) (length var-reprs)))\n                 (raise-arguments-error 'json->pcontext \"Invalid point\" \"pt\" pt))\n               (values (list->vector (map json->value pt var-reprs)) (json->value ex output-repr))))\n  (mk-pcontext pts exs))\n\n(define (get-pcontext post-data)\n  (define test (get-test post-data))\n  (define sample (hash-ref post-data 'sample))\n  (json->pcontext sample (test-context test)))\n\n(define-api-endpoint (\"sample\" post-data)\n  (define test (get-test post-data))\n  (define seed (parse-seed post-data))\n  (job-start 'sample test #:seed seed))\n\n(define-api-endpoint (\"explanations\" post-data)\n  (define test (get-test post-data))\n  (define seed (parse-seed post-data))\n  (define pcontext (get-pcontext post-data))\n  (job-start 'explanations test #:seed seed #:pcontext pcontext))\n\n(define-api-endpoint (\"analyze\" post-data)\n  (define test (get-test post-data))\n  (define seed (parse-seed post-data))\n  (define pcontext (get-pcontext post-data))\n  (job-start 'errors test #:seed seed #:pcontext pcontext))\n\n(define-api-endpoint (\"localerror\" post-data)\n  (define test (get-test post-data))\n  (define seed (parse-seed post-data))\n  (define pcontext (get-pcontext post-data))\n  (job-start 'local-error test #:seed seed #:pcontext pcontext))\n\n(define-api-endpoint (\"alternatives\" post-data)\n  (define test (get-test post-data))\n  (define seed (parse-seed post-data))\n  (define pcontext (get-pcontext post-data))\n  (job-start 'alternatives test #:seed seed #:pcontext pcontext))\n\n(define-api-endpoint (\"cost\" post-data)\n  (job-start 'cost (get-test post-data) #:seed #f))\n\n(define ->mathjs-endpoint\n  (post-with-json-response (lambda (post-data)\n                             (define formula\n                               (read-syntax 'web (open-input-string (hash-ref post-data 'formula))))\n\n                             (define result (core->mathjs (syntax->datum formula)))\n                             (hasheq 'mathjs result))))\n\n(define (get-converter target-lang)\n  (case target-lang\n    [(\"python\") core->python]\n    [(\"c\") core->c]\n    [(\"fortran\") core->fortran]\n    [(\"java\") core->java]\n    [(\"julia\") core->julia]\n    [(\"matlab\") core->matlab]\n    [(\"wls\") core->wls]\n    [(\"reflow\") core->reflow]\n    [(\"tex\") core->tex]\n    [(\"js\") core->js]\n    [else (error \"Unsupported target language:\" target-lang)]))\n\n(define translate-endpoint\n  (post-with-json-response (lambda (post-data)\n                             ; FPCore formula and target language\n                             (define formula (read (open-input-string (hash-ref post-data 'formula))))\n                             (define target-lang (hash-ref post-data 'language))\n                             (define converted ((get-converter target-lang) formula \"expr\"))\n                             (hasheq 'result converted 'language target-lang))))\n\n(define (run-demo #:quiet [quiet? #f]\n                  #:threads [threads #f]\n                  #:browser [browser? #t]\n                  #:output output\n                  #:demo? demo?\n                  #:prefix prefix\n                  #:log log\n                  #:port port\n                  #:public? public)\n  (*demo?* demo?)\n  (*demo-output* output)\n  (*demo-prefix* prefix)\n  (*demo-log* log)\n  (activate-platform! (*platform-name*))\n  (server-start threads)\n\n  (serve/servlet dispatch\n                 #:listen-ip (if public #f \"127.0.0.1\")\n                 #:port port\n                 #:safety-limits\n                 (make-safety-limits #:max-request-body-length\n                                     (* 5 1024 1024)) ; 5 mb body size for det44 bench mark.\n                 #:servlet-current-directory (current-directory)\n                 #:manager (create-none-manager #f)\n                 #:command-line? true\n                 #:launch-browser? (and browser? (not quiet?))\n                 #:banner? (not quiet?)\n                 #:servlets-root (web-resource)\n                 #:server-root-path (web-resource)\n                 #:servlet-path \"/\"\n                 #:servlet-regexp #rx\"\"\n                 #:extra-files-paths (filter identity (list (web-resource) (*demo-output*)))\n                 #:log-file (*demo-log*)\n                 #:file-not-found-responder (gen-file-not-found-responder (web-resource \"404.html\"))))\n"
  },
  {
    "path": "src/api/run.rkt",
    "content": "#lang racket\n\n(require json\n         math/flonum)\n(require \"../reports/common.rkt\"\n         \"../reports/pages.rkt\"\n         \"../reports/timeline.rkt\"\n         \"../syntax/read.rkt\"\n         \"../syntax/sugar.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/platform.rkt\"\n         \"../syntax/load-platform.rkt\"\n         \"../utils/common.rkt\"\n         \"../utils/profile.rkt\"\n         \"../utils/timeline.rkt\"\n         \"../core/points.rkt\"\n         \"datafile.rkt\"\n         \"sandbox.rkt\"\n         \"server.rkt\")\n\n(provide make-report\n         rerun-report)\n\n(define (extract-test row)\n  (define vars (table-row-vars row))\n  (define repr (get-representation (table-row-precision row)))\n  (define var-reprs (map (curryr cons repr) vars))\n  (define ctx (context vars repr (map (const repr) vars)))\n  (test (table-row-name row)\n        (table-row-identifier row)\n        (table-row-vars row)\n        (fpcore->prog (table-row-input row) ctx)\n        (fpcore->prog (table-row-output row) ctx)\n        (table-row-target-prog row)\n        (fpcore->prog (table-row-spec row) ctx)\n        (fpcore->prog (table-row-pre row) ctx)\n        (representation-name repr)\n        (for/list ([(k v) (in-dict var-reprs)])\n          (cons k (representation-name v)))\n        (table-row-conversions row)))\n\n(define (make-report bench-dirs #:dir dir #:threads threads)\n  (activate-platform! (*platform-name*))\n  (define tests (sort (append-map load-tests bench-dirs) string-ci<? #:key test-name))\n  (run-tests tests #:dir dir #:threads threads))\n\n(define (rerun-report json-file #:dir dir #:threads threads)\n  (define data (call-with-input-file json-file read-datafile))\n  (define tests (map extract-test (report-info-tests data)))\n  (activate-platform! (*platform-name*))\n  (*flags* (report-info-flags data))\n  (set-seed! (report-info-seed data))\n  (*num-points* (report-info-points data))\n  (*num-iterations* (report-info-iterations data))\n  (run-tests tests #:dir dir #:threads threads))\n\n(define (read-json-files info dir name)\n  (filter identity\n          (for/list ([res (report-info-tests info)])\n            (define out\n              (with-handlers ([exn? (const #f)])\n                (call-with-input-file (build-path dir (table-row-link res) name) read-json)))\n            (and out (not (eof-object? out)) out))))\n\n(define (merge-profile-jsons ps)\n  (profile->json (apply profile-merge (map json->profile ps))))\n\n(define (generate-bench-report result bench-name test-number dir total-tests)\n  (define report-path (bench-folder-path bench-name test-number))\n  (define report-directory (build-path dir report-path))\n  (unless (directory-exists? report-directory)\n    (make-directory report-directory))\n\n  (for ([page (all-pages result)])\n    (call-with-output-file (build-path report-directory page)\n                           #:exists 'replace\n                           (λ (out)\n                             (with-handlers ([exn:fail? (page-error-handler result page out)])\n                               (make-page-timeout page out result #t #f #:timeout 10000)))))\n\n  (get-table-data-from-hash result report-path))\n\n(define (run-tests tests #:dir dir #:threads threads)\n  (define seed (get-seed))\n  (unless (directory-exists? dir)\n    (make-directory dir))\n\n  (server-start threads)\n  (define job-ids\n    (for/list ([test (in-list tests)])\n      (job-start 'improve test #:seed seed #:pcontext #f #:profile? #t #:timeline? #t)))\n\n  (define total-tests (length tests))\n  (define results\n    (for/list ([job-id (in-list job-ids)]\n               [test (in-list tests)]\n               [test-number (in-naturals)])\n      (define result (job-wait job-id))\n      (print-test-result (+ test-number 1) total-tests test result)\n      (begin0 (generate-bench-report result (test-name test) test-number dir total-tests)\n        (job-forget job-id))))\n\n  (define info (make-report-info results #:seed seed))\n  (write-datafile (build-path dir \"results.json\") info)\n  (copy-file (web-resource \"report-page.js\") (build-path dir \"report-page.js\") #t)\n  (copy-file (web-resource \"report.js\") (build-path dir \"report.js\") #t)\n  (copy-file (web-resource \"report.css\") (build-path dir \"report.css\") #t)\n  (copy-file (web-resource \"logo-car.png\") (build-path dir \"logo-car.png\") #t)\n  (copy-file (web-resource \"report.html\") (build-path dir \"index.html\") #t)\n  (define timeline (apply timeline-merge (read-json-files info dir \"timeline.json\")))\n  (call-with-output-file (build-path dir \"timeline.json\")\n                         (curry write-json timeline)\n                         #:exists 'replace)\n  (define profile (merge-profile-jsons (read-json-files info dir \"profile.json\")))\n  (call-with-output-file (build-path dir \"profile.json\") (curry write-json profile) #:exists 'replace)\n\n  (call-with-output-file\n   (build-path dir \"timeline.html\")\n   #:exists 'replace\n   (λ (out) (write-html (make-timeline \"Herbie run\" timeline #:info info #:path \".\") out)))\n\n  ; Delete old files\n  (define expected-dirs\n    (map string->path (filter identity (map table-row-link (report-info-tests info)))))\n  (define actual-dirs\n    (filter (λ (name) (directory-exists? (build-path dir name))) (directory-list dir)))\n  (define extra-dirs (filter (λ (name) (not (member name expected-dirs))) actual-dirs))\n  (for ([subdir extra-dirs])\n    (with-handlers ([exn:fail:filesystem? (const true)])\n      (delete-directory/files (build-path dir subdir)))))\n\n;; Generate a path for a given benchmark name\n(define (bench-folder-path bench-name index)\n  (define replaced (string-replace bench-name #px\"\\\\W+\" \"\"))\n  (format \"~a-~a\" index (substring replaced 0 (min (string-length replaced) 50))))\n\n(define (hash-ref-path hash . path)\n  (match path\n    ['() hash]\n    [(cons (? symbol? key) rest) (apply hash-ref-path (hash-ref hash key) rest)]\n    [(cons (? integer? key) rest) (apply hash-ref-path (list-ref hash key) rest)]))\n\n(define (print-test-result i n test result-hash)\n  (eprintf \"~a/~a\\t\" (~a i #:min-width 3 #:align 'right) n)\n  (define name (test-name test))\n  (match (hash-ref-path result-hash 'status)\n    [\"failure\"\n     (match-define (list 'exn type msg url locs tb) (hash-ref-path result-hash 'backend))\n     (if type\n         (eprintf \"[ ERROR ]\\t\\t~a\\n\" name)\n         (eprintf \"[ CRASH ]\\t\\t~a\\n\" name))]\n    [\"timeout\" (eprintf \"[TIMEOUT]\\t\\t~a\\n\" name)]\n    [_\n     (define bits (representation-total-bits (test-output-repr test)))\n     (define time (hash-ref-path result-hash 'time))\n     (define start-score\n       (errors-score (list->flvector (hash-ref-path result-hash 'backend 'start 'errors))))\n     (define end-score\n       (errors-score (list->flvector (hash-ref-path result-hash 'backend 'end 0 'errors))))\n     (eprintf \"[~as]  ~a% → ~a%\\t~a\\n\"\n              (~r (/ time 1000) #:min-width 6 #:precision '(= 1))\n              (~r (* 100 (- 1 (/ start-score bits))) #:min-width 3 #:precision 0)\n              (~r (* 100 (- 1 (/ end-score bits))) #:min-width 3 #:precision 0)\n              name)]))\n"
  },
  {
    "path": "src/api/sandbox.rkt",
    "content": "#lang racket\n\n(require racket/engine\n         math/flonum\n         json)\n\n(require \"../syntax/read.rkt\"\n         \"../syntax/syntax.rkt\"\n         \"../syntax/sugar.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/load-platform.rkt\"\n         \"../syntax/batch.rkt\"\n         \"../core/localize.rkt\"\n         \"../core/alternative.rkt\"\n         \"../core/compiler.rkt\"\n         \"../utils/common.rkt\"\n         \"datafile.rkt\"\n         \"../utils/errors.rkt\"\n         \"../syntax/float.rkt\"\n         \"../core/sampling.rkt\"\n         \"../core/mainloop.rkt\"\n         \"../syntax/platform.rkt\"\n         \"../core/programs.rkt\"\n         \"../core/points.rkt\"\n         \"../core/explain.rkt\"\n         \"../utils/profile.rkt\"\n         \"../utils/timeline.rkt\"\n         (submod \"../utils/timeline.rkt\" debug))\n\n(provide run-herbie\n         get-table-data-from-hash\n         *reeval-pts*\n         (struct-out job-result)\n         (struct-out improve-result)\n         (struct-out alt-analysis))\n\n(struct job-result (command test status time timeline profile warnings backend))\n(struct improve-result (pcontext start target end))\n(struct alt-analysis (alt errors) #:prefab)\n\n;; API users can supply their own, weird set of points, in which case\n;; the first 256 are training points and everything is test points.\n;; For backwards compatibility, exactly 8256 points are split as\n;; Herbie expects (first 256 training, rest are test).\n\n(define (partition-pcontext joint-pcontext)\n  (define num-points (pcontext-length joint-pcontext))\n  (cond\n    [(= num-points (+ (*num-points*) (*reeval-pts*)))\n     (split-pcontext joint-pcontext (*num-points*) (*reeval-pts*))]\n    [else\n     ; the training set will just be up to the first (*num-points*)\n     ; the testing set will just be the entire set\n     (define training-count (min (*num-points*) num-points))\n     (define testing-count (- num-points training-count))\n     (define-values (train-pcontext _) (split-pcontext joint-pcontext training-count testing-count))\n     (values train-pcontext joint-pcontext)]))\n\n;; API Functions\n\n;; The main Herbie function\n(define (get-alternatives test joint-pcontext)\n  (unless joint-pcontext\n    (error 'get-alternatives \"cannnot run without a pcontext\"))\n\n  (define-values (train-pcontext test-pcontext) (partition-pcontext joint-pcontext))\n  (define alternatives (run-improve! (test-input test) (test-spec test) (*context*) train-pcontext))\n\n  ;; compute error/cost for input expression\n  (define start-expr (test-input test))\n  (define start-alt (make-alt start-expr))\n  (define start-errs (errors start-expr test-pcontext (*context*)))\n  (define start-alt-data (alt-analysis start-alt start-errs))\n\n  ;; optionally compute error/cost for input expression\n  (define target-alt-data\n    ;; When in platform, evaluate error\n    (for/list ([(expr is-valid?) (in-dict (test-output test))]\n               #:when is-valid?)\n      (define target-expr (fpcore->prog expr (*context*)))\n      (define target-errs (errors target-expr test-pcontext (*context*)))\n      (alt-analysis (make-alt target-expr) target-errs)))\n\n  ;; compute error/cost for output expression\n  ;; and sort alternatives by accuracy + cost on testing subset\n  (define test-errs (exprs-errors (map alt-expr alternatives) test-pcontext (*context*)))\n  (define sorted-end-exprs (sort-alts alternatives test-errs))\n  (define end-exprs (map (compose alt-expr car) sorted-end-exprs))\n  (define end-errs (map cdr sorted-end-exprs))\n  (define end-data (map alt-analysis alternatives end-errs))\n\n  (improve-result test-pcontext start-alt-data target-alt-data end-data))\n\n(define (get-cost test)\n  (define cost-proc (platform-cost-proc (*active-platform*)))\n  (define output-repr (context-repr (*context*)))\n  (cost-proc (test-input test) output-repr))\n\n(define (get-errors test pcontext)\n  (unless pcontext\n    (error 'get-errors \"cannnot run without a pcontext\"))\n\n  (define-values (_ test-pcontext) (partition-pcontext pcontext))\n  (define errs (errors (test-input test) test-pcontext (*context*)))\n  (for/list ([(pt _) (in-pcontext test-pcontext)]\n             [err (in-flvector errs)])\n    (cons pt err)))\n\n(define (get-explanations test pcontext)\n  (unless pcontext\n    (error 'explain \"cannot run without a pcontext\"))\n\n  (define-values (fperrors\n                  sorted-explanations-table\n                  confusion-matrix\n                  maybe-confusion-matrix\n                  total-confusion-matrix\n                  freqs)\n    (explain (test-input test) (*context*) pcontext))\n\n  sorted-explanations-table)\n\n;; Given a test and a sample of points, computes the local error at every node in the expression\n;; returning a tree of errors that mirrors the structure of the expression.\n;; If the sample contains the expected number of points, i.e., `(*num-points*) + (*reeval-pts*)`,\n;; then the first `*num-points*` will be discarded and the rest will be used for evaluation,\n;; otherwise the entire set is used.\n(define (get-local-error test pcontext)\n  (unless pcontext\n    (error 'get-local-error \"cannnot run without a pcontext\"))\n\n  (local-error-as-tree (test-input test) (*context*) pcontext))\n\n(define (get-sample test)\n  (random) ;; Tick the random number generator, for backwards compatibility\n  (define specification (prog->spec (or (test-spec test) (test-input test))))\n  (define precondition (prog->spec (test-pre test)))\n  (define-values (batch brfs) (progs->batch (list specification)))\n  (define sample\n    (parameterize ([*num-points* (+ (*num-points*) (*reeval-pts*))])\n      (sample-points precondition batch brfs (list (*context*)))))\n  (apply mk-pcontext sample))\n\n;;\n;;  Public interface\n;;\n\n(define (run-herbie command\n                    test\n                    #:seed [seed #f]\n                    #:pcontext [pcontext #f]\n                    #:profile? [profile? #f]\n                    #:timeline? [timeline? #f])\n  (define timeline #f)\n  (define profile #f)\n\n  (define (on-exception start-time e)\n    (parameterize ([*timeline-disabled* (not timeline?)])\n      (timeline-event! 'end)\n      (define time (- (current-inexact-milliseconds) start-time))\n      (match command\n        ['improve (job-result command test 'failure time (timeline-extract) #f (warning-log) e)]\n        [_ (raise e)])))\n\n  (define (on-timeout)\n    (parameterize ([*timeline-disabled* (not timeline?)])\n      (timeline-load! timeline)\n      (timeline-event! 'end)\n      (match command\n        ['improve\n         (job-result command test 'timeout (*timeout*) (timeline-extract) #f (warning-log) #f)]\n        [_ (raise-arguments-error 'run-herbie \"command timed out\" \"command\" command)])))\n\n  (define (compute-result)\n    (parameterize ([*timeline-disabled* (not timeline?)])\n      (define start-time (current-inexact-milliseconds))\n      (reset!)\n      (*context* (test-context test))\n      (activate-platform! (*platform-name*))\n      (set! timeline (*timeline*))\n      (when seed\n        (set-seed! seed))\n      (with-handlers ([exn? (curry on-exception start-time)])\n        (timeline-event! 'start) ; Prevents the timeline from being empty.\n        (define result\n          (match command\n            ['alternatives (get-alternatives test pcontext)]\n            ['cost (get-cost test)]\n            ['errors (get-errors test pcontext)]\n            ['explanations (get-explanations test pcontext)]\n            ['improve (get-alternatives test (get-sample test))]\n            ['local-error (get-local-error test pcontext)]\n            ['sample (get-sample test)]\n            [_ (raise-arguments-error 'compute-result \"unknown command\" \"command\" command)]))\n        (timeline-event! 'end)\n        (define time (- (current-inexact-milliseconds) start-time))\n        (job-result command test 'success time (timeline-extract) #f (warning-log) result))))\n\n  (define (in-engine _)\n    (cond\n      [profile?\n       (define result (profile-thunk compute-result (λ (p) (set! profile (profile->json p)))))\n       (struct-copy job-result result [profile profile])]\n      [else (compute-result)]))\n\n  (define run-custodian (make-custodian))\n  (begin0 (parameterize ([current-custodian run-custodian])\n            (define eng (engine in-engine))\n            (if (engine-run (*timeout*) eng)\n                (engine-result eng)\n                (on-timeout)))\n    (custodian-shutdown-all run-custodian)))\n\n(define (dummy-table-row-from-hash result-hash status link)\n  (define test (car (load-tests (open-input-string (hash-ref result-hash 'test)))))\n  (define repr (test-output-repr test))\n  (table-row (test-name test)\n             (test-identifier test)\n             status\n             (prog->fpcore (test-pre test) (test-context test))\n             (representation-name repr)\n             '() ; TODO: eliminate field\n             (test-vars test)\n             (map car (hash-ref result-hash 'warnings))\n             (prog->fpcore (test-input test) (test-context test))\n             #f\n             (prog->fpcore (test-spec test) (test-context test))\n             (test-output test)\n             #f\n             #f\n             #f\n             (hash-ref result-hash 'time)\n             link\n             '()))\n\n(define (get-table-data-from-hash result-hash link)\n  (define test (car (load-tests (open-input-string (hash-ref result-hash 'test)))))\n  (define backend (hash-ref result-hash 'backend))\n  (define status (hash-ref result-hash 'status))\n  (match status\n    [\"success\"\n     (define start (hash-ref backend 'start))\n     (define targets (hash-ref backend 'target))\n     (define end (hash-ref backend 'end))\n     (define expr-cost (platform-cost-proc (*active-platform*)))\n     (define repr (test-output-repr test))\n\n     ; starting expr analysis\n     (define start-expr (read (open-input-string (hash-ref start 'expr))))\n     (define start-score (errors-score (list->flvector (hash-ref start 'errors))))\n     (define start-cost (hash-ref start 'cost))\n\n     (define target-cost-score\n       (for/list ([target targets])\n         (define target-expr (read (open-input-string (hash-ref target 'expr))))\n         (define tar-cost (hash-ref target 'cost))\n         (define tar-score (errors-score (list->flvector (hash-ref target 'errors))))\n\n         (list tar-cost tar-score)))\n\n     ; Important to calculate value of status\n     (define best-score\n       (if (null? target-cost-score)\n           target-cost-score\n           (apply min (map second target-cost-score))))\n\n     (define end-exprs\n       (for/list ([end-analysis (in-list end)])\n         (read (open-input-string (hash-ref end-analysis 'expr)))))\n     (define end-scores\n       (for/list ([end-analysis (in-list end)])\n         (errors-score (list->flvector (hash-ref end-analysis 'errors)))))\n     (define end-costs (map (curryr hash-ref 'cost) end))\n\n     ; terribly formatted pareto-optimal frontier\n     (define (round3 x)\n       (/ (round (* x 1000)) 1000.0))\n     (define cost&accuracy\n       (list (list (round3 start-cost) (round3 start-score))\n             (list (round3 (car end-costs)) (round3 (car end-scores)))\n             (map (λ (c s) (list (round3 c) (round3 s))) (cdr end-costs) (cdr end-scores))))\n\n     (define fuzz 0.1)\n     (define end-score (car end-scores))\n     (define status\n       (cond\n         [(not (null? best-score))\n          (cond\n            [(< end-score (- best-score fuzz)) \"gt-target\"]\n            [(< end-score (+ best-score fuzz)) \"eq-target\"]\n            [(> end-score (+ start-score fuzz)) \"lt-start\"]\n            [(> end-score (- start-score fuzz)) \"eq-start\"]\n            [(> end-score (+ best-score fuzz)) \"lt-target\"])]\n\n         [(and (< start-score 1) (< end-score (+ start-score 1))) \"ex-start\"]\n         [(< end-score (- start-score 1)) \"imp-start\"]\n         [(< end-score (+ start-score fuzz)) \"apx-start\"]\n         [else \"uni-start\"]))\n\n     (struct-copy table-row\n                  (dummy-table-row-from-hash result-hash status link)\n                  [start start-score]\n                  [target target-cost-score]\n                  [result end-score]\n                  [output (car end-exprs)]\n                  [cost-accuracy cost&accuracy])]\n    [\"failure\"\n     (match-define (list 'exn type _ ...) backend)\n     (define status (if type \"error\" \"crash\"))\n     (dummy-table-row-from-hash result-hash status link)]\n    [\"timeout\" (dummy-table-row-from-hash result-hash \"timeout\" link)]))\n"
  },
  {
    "path": "src/api/server.rkt",
    "content": "#lang racket\n\n(require openssl/sha1)\n(require (only-in xml write-xexpr))\n(require json)\n(require data/queue)\n(require math/flonum)\n\n(require \"../syntax/read.rkt\"\n         \"../syntax/sugar.rkt\"\n         \"../syntax/syntax.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/platform.rkt\"\n         \"../syntax/load-platform.rkt\"\n         \"../core/alternative.rkt\"\n         \"../utils/common.rkt\"\n         \"../utils/errors.rkt\"\n         \"../syntax/float.rkt\"\n         \"../core/points.rkt\"\n         \"../reports/common.rkt\"\n         \"../reports/history.rkt\"\n         \"../reports/pages.rkt\"\n         \"../reports/plot.rkt\"\n         \"../config.rkt\"\n         \"datafile.rkt\"\n         \"sandbox.rkt\"\n         (submod \"../utils/timeline.rkt\" debug))\n\n(provide job-path\n         job-start\n         job-status\n         job-forget\n         job-wait\n         job-results\n         job-timeline\n         server-start\n         server-improve-results\n         server-count\n         server-up?)\n\n(define (log msg . args)\n  (when false\n    (apply eprintf msg args)))\n\n;; Tracing support\n\n(define (current-timestamp)\n  (exact-floor (* 1000 (current-inexact-milliseconds))))\n\n(define *gc-logger* #f)\n\n(define (trace-start)\n  (when (flag-set? 'dump 'trace)\n    (set! *gc-logger* (make-log-receiver (current-logger) 'debug 'GC))\n    (call-with-output-file\n     \"dump-trace.json\"\n     #:exists 'truncate\n     (λ (out)\n       (fprintf out \"{\\\"traceEvents\\\":[\")\n       (write-json (hash 'name \"process_name\" 'ph \"M\" 'ts 0 'pid 0 'tid 0 'args (hash 'name \"herbie\"))\n                   out)\n       (fprintf out \",\")\n       (write-json (hash 'name\n                         \"thread_name\"\n                         'ph\n                         \"M\"\n                         'ts\n                         0\n                         'pid\n                         0\n                         'tid\n                         (equal-hash-code 'gc)\n                         'args\n                         (hash 'name \"GC\"))\n                   out)))))\n\n(define (trace-sync)\n  (when *gc-logger*\n    (let drain ()\n      (match (sync/timeout 0 *gc-logger*)\n        [#f (void)]\n        [(vector _lvl _msg (app struct->vector data) _topic)\n         (define mode (~a (vector-ref data 1)))\n         (define start (exact-floor (* 1000 (vector-ref data 9))))\n         (define end (exact-floor (* 1000 (vector-ref data 10))))\n         (define post-amount (vector-ref data 5))\n         (define post-admin-amount (vector-ref data 6))\n         (call-with-output-file \"dump-trace.json\"\n                                #:exists 'append\n                                (λ (out)\n                                  (fprintf out \",\")\n                                  (write-json (hash 'name\n                                                    mode\n                                                    'ph\n                                                    \"X\"\n                                                    'ts\n                                                    start\n                                                    'dur\n                                                    (- end start)\n                                                    'pid\n                                                    0\n                                                    'tid\n                                                    (equal-hash-code 'gc)\n                                                    'args\n                                                    (hash))\n                                              out)\n                                  (fprintf out \",\")\n                                  (write-json (hash 'name\n                                                    \"Memory\"\n                                                    'ph\n                                                    \"C\"\n                                                    'ts\n                                                    end\n                                                    'pid\n                                                    0\n                                                    'tid\n                                                    (equal-hash-code 'gc)\n                                                    'args\n                                                    (hash 'live post-amount 'admin post-admin-amount))\n                                              out)))\n         (drain)]))))\n\n(define (trace worker-id name phase [args (hash)])\n  (when (flag-set? 'dump 'trace)\n    (trace-sync)\n    (call-with-output-file\n     \"dump-trace.json\"\n     #:exists 'append\n     (λ (out)\n       (fprintf out \",\")\n       (write-json\n        (hash 'name (~a name) 'ph (~a phase) 'ts (current-timestamp) 'pid 0 'tid worker-id 'args args)\n        out)))))\n\n(define (trace-end)\n  (when (flag-set? 'dump 'trace)\n    (trace-sync)\n    (call-with-output-file \"dump-trace.json\" #:exists 'append (λ (out) (fprintf out \"]}\\n\")))))\n\n(define old-exit (exit-handler))\n(exit-handler (λ (v)\n                (trace-end)\n                (old-exit v)))\n\n;; Job-specific public API\n(define (job-path id)\n  (format \"~a.~a\" id *herbie-commit*))\n\n(define (job-start command\n                   test\n                   #:seed [seed #f]\n                   #:pcontext [pcontext #f]\n                   #:profile? [profile? #f]\n                   #:timeline? [timeline? #f])\n  (define job-id (manager-ask 'start manager command test seed pcontext profile? timeline?))\n  (log \"Job ~a, Qed up for program: ~a\\n\" job-id (test-name test))\n  job-id)\n\n(define (job-status job-id)\n  (log \"Checking on: ~a.\\n\" job-id)\n  (manager-ask 'check job-id))\n\n(define (job-forget job-id)\n  (log \"Forgetting job: ~a.\\n\" job-id)\n  (manager-ask 'forget job-id))\n\n(define (job-wait job-id)\n  (define finished-result (manager-ask 'wait manager job-id))\n  (log \"Done waiting for: ~a\\n\" job-id)\n  finished-result)\n\n(define (job-results job-id)\n  (log \"Getting result for job: ~a.\\n\" job-id)\n  (manager-ask 'result job-id))\n\n(define (job-timeline job-id)\n  (log \"Getting timeline for job: ~a.\\n\" job-id)\n  (manager-ask 'timeline job-id))\n\n;; Whole-server public methods\n\n(define (server-start threads)\n  (trace-start)\n  (cond\n    [threads\n     (eprintf \"Starting Herbie ~a with ~a workers and seed ~a...\\n\"\n              *herbie-version*\n              threads\n              (get-seed))]\n    [else (eprintf \"Starting Herbie ~a with seed ~a...\\n\" *herbie-version* (get-seed))])\n\n  (set! manager\n        (if threads\n            (make-manager threads)\n            'basic)))\n\n(define (server-improve-results)\n  (log \"Getting improve results.\\n\")\n  (manager-ask 'improve))\n\n(define (server-count)\n  (manager-ask 'count))\n\n(define (server-up?)\n  (match manager\n    [(? place? x) (not (sync/timeout 0 (place-dead-evt x)))]\n    ['basic #t]))\n\n;; Interface for two manager types (threaded and basic)\n\n(define manager #f)\n\n(define (manager-ask msg . args)\n  (log \"Asking manager: ~a.\\n\" msg)\n  (trace-sync)\n  (match manager\n    [(? place? x) (apply manager-ask-threaded x msg args)]\n    ['basic (apply manager-ask-basic msg args)]))\n\n(define (manager-ask-threaded manager msg . args)\n  (define-values (a b) (place-channel))\n  (place-channel-put manager (list* msg b args))\n  (place-channel-get a))\n\n(define (manager-ask-basic msg . args)\n  (match (list* msg args) ; public commands\n    [(list 'start 'basic command test seed pcontext profile? timeline?)\n     (define job (herbie-command command test seed pcontext profile? timeline?))\n     (define job-id (compute-job-id job))\n     (hash-set! queued-jobs job-id job)\n     job-id]\n    [(list 'wait 'basic job-id)\n     (define command (hash-ref queued-jobs job-id #f))\n     (define result (and command (herbie-do-server-job 0 command job-id)))\n     (when command\n       (hash-remove! queued-jobs job-id)\n       (hash-set! completed-jobs job-id result))\n     result]\n    [(list 'result job-id) (hash-ref completed-jobs job-id #f)]\n    [(list 'timeline job-id)\n     (define command (hash-ref queued-jobs job-id #f))\n     (define result (and command (herbie-do-server-job 0 command job-id)))\n     (when command\n       (hash-remove! queued-jobs job-id)\n       (hash-set! completed-jobs job-id result))\n     result]\n    [(list 'check job-id)\n     (define command (hash-ref queued-jobs job-id #f))\n     (define result (and command (herbie-do-server-job 0 command job-id)))\n     (when command\n       (hash-remove! queued-jobs job-id)\n       (hash-set! completed-jobs job-id result))\n     job-id]\n    [(list 'count) (hash-count queued-jobs)]\n    [(list 'improve)\n     (for/list ([result (in-hash-values completed-jobs)]\n                #:when (equal? (hash-ref result 'command) \"improve\"))\n       result)]\n    [(list 'forget job-id)\n     (hash-remove! completed-jobs job-id)\n     (void)]))\n\n;; Implementation of threaded manager\n\n(struct herbie-command (command test seed pcontext profile? timeline?) #:prefab)\n\n(define queued-jobs (make-hash))\n(define completed-jobs (make-hash))\n\n(define (compute-job-id job-info)\n  (sha1 (open-input-string (~s job-info))))\n\n(define-syntax (place/context* stx)\n  (syntax-case stx ()\n    [(_ name #:parameters (params ...) body ...)\n     (with-syntax ([(fresh ...) (generate-temporaries #'(params ...))])\n       #'(let ([fresh (params)] ...)\n           (place/context name\n                          (parameterize ([params fresh] ...)\n                            body ...))))]))\n\n(define (make-manager worker-count)\n  (place/context*\n   ch\n   #:parameters (*flags* *num-iterations*\n                         *num-points*\n                         *timeout*\n                         *reeval-pts*\n                         *node-limit*\n                         *max-find-range-depth*\n                         *platform-name*\n                         *functions*)\n   (activate-platform! (*platform-name*))\n   ; not sure if the above code is actaully needed.\n   (define busy-workers (make-hash))\n   (define waiting-workers (make-hash))\n   (define current-jobs (make-hash))\n   (define queued-job-ids (make-queue))\n   (when (eq? worker-count #t)\n     (set! worker-count (processor-count)))\n   (for ([i (in-range worker-count)])\n     (hash-set! waiting-workers i (make-worker i)))\n   (define dead-worker-evts (map place-dead-evt (hash-values waiting-workers)))\n   (log \"~a workers ready.\\n\" (hash-count waiting-workers))\n   (define waiting (make-hash))\n   (log \"Manager waiting to assign work.\\n\")\n   (for ([i (in-naturals)])\n     (match (apply sync ch dead-worker-evts)\n       [(? evt?) (error 'make-manager \"worker place died\")]\n\n       ;; Private API\n       [(list 'assign self)\n        (define reassigned '())\n        (for ([(wid worker) (in-hash waiting-workers)]\n              #:when (not (queue-empty? queued-job-ids)))\n          (define jid (dequeue! queued-job-ids))\n          (define command (hash-ref queued-jobs jid))\n          (log \"Starting worker [~a] on [~a].\\n\" jid (test-name (herbie-command-test command)))\n          (place-channel-put worker (list 'apply self command jid))\n          (hash-set! current-jobs jid wid)\n          (hash-set! busy-workers wid worker)\n          (set! reassigned (cons wid reassigned))\n          (hash-remove! queued-jobs jid))\n        (for ([wid reassigned])\n          (hash-remove! waiting-workers wid))]\n       ; Job is finished save work and free worker. Move work to 'send state.\n       [(list 'finished self wid job-id result)\n        (log \"Job ~a finished, saving result.\\n\" job-id)\n        (hash-set! completed-jobs job-id result)\n        ; move worker to waiting list\n        (hash-remove! current-jobs job-id)\n        (hash-set! waiting-workers wid (hash-ref busy-workers wid))\n        (hash-remove! busy-workers wid)\n        (log \"waiting job ~a completed\\n\" job-id)\n        (place-channel-put self (list 'send job-id result))\n        (place-channel-put self (list 'assign self))]\n       [(list 'send job-id result)\n        (log \"Sending result for ~a.\\n\" job-id)\n        (for ([handle (hash-ref waiting job-id '())])\n          (place-channel-put handle result))\n        (hash-remove! waiting job-id)]\n\n       ;; Public API\n       [(list 'start handler self command test seed pcontext profile? timeline?)\n        (define job (herbie-command command test seed pcontext profile? timeline?))\n        (define job-id (compute-job-id job))\n        (place-channel-put handler job-id)\n        ; Check if the work has been completed already if not assign the work.\n        (cond\n          [(hash-has-key? completed-jobs job-id)\n           (place-channel-put self (list 'send job-id (hash-ref completed-jobs job-id)))]\n          [else\n           (hash-set! queued-jobs job-id job)\n           (enqueue! queued-job-ids job-id)\n           (place-channel-put self (list 'assign self))])]\n       [(list 'wait handler self job-id)\n        (log \"Waiting for job: ~a\\n\" job-id)\n        ; first we add the handler to the wait list.\n        (hash-update! waiting job-id (curry append (list handler)) '())\n        (define result (hash-ref completed-jobs job-id #f))\n        ; check if the job is completed or not.\n        (unless (false? result)\n          (log \"Done waiting for job: ~a\\n\" job-id)\n          ; we have a result to send.\n          (place-channel-put self (list 'send job-id result)))]\n       ; Get the result for the given id, return false if no work found.\n       [(list 'result handler job-id) (place-channel-put handler (hash-ref completed-jobs job-id #f))]\n       [(list 'timeline handler job-id)\n        (define wid (hash-ref current-jobs job-id #f))\n        (cond\n          [wid\n           (log \"Worker[~a] working on ~a.\\n\" wid job-id)\n           (define-values (a b) (place-channel))\n           (place-channel-put (hash-ref busy-workers wid) (list 'timeline b))\n           (define requested-timeline (place-channel-get a))\n           (place-channel-put handler requested-timeline)]\n          [else\n           (log \"Job complete, no timeline, send result.\\n\")\n           (place-channel-put handler (hash-ref completed-jobs job-id #f))])]\n       [(list 'check handler job-id)\n        (place-channel-put handler (and (hash-has-key? completed-jobs job-id) job-id))]\n       ; Returns the current count of working workers.\n       [(list 'count handler)\n        (define total (+ (hash-count busy-workers) (hash-count queued-jobs)))\n        (log \"Currently ~a jobs total.\\n\" total)\n        (place-channel-put handler total)]\n       ; Retrieve the improve results for results.json\n       [(list 'improve handler)\n        (define improved-list\n          (for/list ([result (in-hash-values completed-jobs)]\n                     #:when (equal? (hash-ref result 'command) \"improve\"))\n            result))\n        (place-channel-put handler improved-list)]\n       ; Forget a completed job result\n       [(list 'forget handler job-id)\n        (hash-remove! completed-jobs job-id)\n        (place-channel-put handler (void))]))))\n\n;; Implementation of threaded worker\n\n(define (warn-single-threaded-mpfr)\n  (local-require ffi/unsafe)\n  (local-require math/private/bigfloat/mpfr)\n  (unless ((get-ffi-obj 'mpfr_buildopt_tls_p mpfr-lib (_fun -> _bool)))\n    (warn 'mpfr-threads \"Your MPFR is single-threaded. Herbie will work but be slower than normal.\")))\n\n(define (make-worker worker-id)\n  (warn-single-threaded-mpfr)\n\n  (place/context*\n   ch\n   #:parameters (*flags* *num-iterations*\n                         *num-points*\n                         *timeout*\n                         *reeval-pts*\n                         *node-limit*\n                         *max-find-range-depth*\n                         *platform-name*\n                         *functions*)\n   (activate-platform! (*platform-name*))\n   (define worker-thread\n     (thread (λ ()\n               (let loop ()\n                 (match-define (list manager worker-id job-id command) (thread-receive))\n                 (log \"run-job: ~a, ~a\\n\" worker-id job-id)\n                 (define out-result (herbie-do-server-job worker-id command job-id))\n                 (log \"Job: ~a finished, returning work to manager\\n\" job-id)\n                 (place-channel-put manager (list 'finished manager worker-id job-id out-result))\n                 (loop)))))\n   (define timeline #f)\n   (define current-job-id #f)\n   (for ([_ (in-naturals)])\n     (match (sync ch (thread-dead-evt worker-thread))\n       [(? evt?) (error 'make-worker \"worker thread died\")]\n       [(list 'apply manager command job-id)\n        (set! timeline (*timeline*))\n        (set! current-job-id job-id)\n        (log \"[~a] working on [~a].\\n\" job-id (test-name (herbie-command-test command)))\n        (thread-send worker-thread (list manager worker-id job-id command))]\n       [(list 'timeline handler)\n        (log \"Timeline requested from worker[~a] for job ~a\\n\" worker-id current-job-id)\n        (place-channel-put handler (reverse (unbox timeline)))]))))\n\n(define (herbie-do-server-job worker-id h-command job-id)\n  (match-define (herbie-command command test seed pcontext profile? timeline?) h-command)\n  (define metadata (hash 'job-id job-id 'command (~a command) 'name (test-name test)))\n  (trace worker-id 'herbie 'B metadata)\n  (define herbie-result\n    (run-herbie command\n                test\n                #:seed seed\n                #:pcontext pcontext\n                #:profile? profile?\n                #:timeline? timeline?))\n  (trace worker-id 'herbie 'E metadata)\n  (trace worker-id 'to-json 'B metadata)\n  (define basic-output ((get-json-converter command) herbie-result job-id))\n  (trace worker-id 'to-json 'E metadata)\n  ;; Add default fields that all commands have\n  (hash-set* basic-output\n             'job\n             job-id\n             'path\n             (job-path job-id)\n             'command\n             (~a command)\n             'name\n             (test-name test)\n             'status\n             (~a (job-result-status herbie-result))\n             'time\n             (job-result-time herbie-result)\n             'warnings\n             (job-result-warnings herbie-result)))\n\n;; JSON conversion stuff\n\n(define (get-json-converter command)\n  (match command\n    ['alternatives make-alternatives-result]\n    ['cost make-cost-result]\n    ['errors make-error-result]\n    ['explanations make-explanation-result]\n    ['improve make-alternatives-result]\n    ['local-error make-local-error-result]\n    ['sample make-sample-result]\n    [_ (error 'compute-result \"unknown command ~a\" command)]))\n\n(define (make-explanation-result herbie-result job-id)\n  (hasheq 'explanation (job-result-backend herbie-result)))\n\n(define (make-local-error-result herbie-result job-id)\n  (hasheq 'tree (job-result-backend herbie-result)))\n\n(define (make-sample-result herbie-result job-id)\n  (define test (job-result-test herbie-result))\n  (define pctx (job-result-backend herbie-result))\n  (define ctx (test-context test))\n  (hasheq 'points (pcontext->json pctx ctx)))\n\n(define (make-cost-result herbie-result job-id)\n  (hasheq 'cost (job-result-backend herbie-result)))\n\n(define (make-error-result herbie-result job-id)\n  (define test (job-result-test herbie-result))\n  (define errs\n    (for/list ([(pt err) (in-dict (job-result-backend herbie-result))])\n      (list (for/list ([val (in-vector pt)]\n                       [repr (in-list (context-var-reprs (test-context test)))])\n              (value->json val repr))\n            (format-bits err))))\n  (hasheq 'points errs))\n\n(define (make-alternatives-result herbie-result job-id)\n  (define test (job-result-test herbie-result))\n  (define backend (job-result-backend herbie-result))\n  (define timeline (job-result-timeline herbie-result))\n  (define profile (job-result-profile herbie-result))\n\n  (define ctx (test-context test))\n  (define-values (altns pcontext)\n    (cond\n      [(equal? (job-result-status herbie-result) 'success)\n       (define altns (map alt-analysis-alt (improve-result-end backend)))\n       (define pcontext (improve-result-pcontext backend))\n       (values altns pcontext)]\n      [else (values '() #f)]))\n\n  (define errcache\n    (cond\n      [(equal? (job-result-status herbie-result) 'success)\n       (define all-alts\n         (map alt-analysis-alt\n              (append (list (improve-result-start backend))\n                      (improve-result-target backend)\n                      (improve-result-end backend))))\n       (define exprs (remove-duplicates (append-map collect-expressions all-alts)))\n       (make-hash (map cons exprs (exprs-errors exprs pcontext ctx)))]\n      [else #f]))\n\n  (define test-fpcore (alt->fpcore test (make-alt (test-input test))))\n\n  (define fpcores\n    (if (equal? (job-result-status herbie-result) 'success)\n        (for/list ([altn (in-list altns)])\n          (~s (alt->fpcore test altn)))\n        (list (~s test-fpcore))))\n\n  (define backend-hash\n    (match (job-result-status herbie-result)\n      ['success (backend-improve-result-hash-table backend test errcache)]\n      ['timeout #f]\n      ['failure (exception->datum backend)]))\n\n  (define derivations\n    (for/list ([altn (in-list altns)]\n               [analysis (if (hash? backend-hash)\n                             (hash-ref backend-hash 'end)\n                             '())])\n      (hash-ref analysis 'history)))\n\n  (hasheq 'test\n          (~s test-fpcore)\n          'timeline\n          timeline\n          'profile\n          profile\n          'alternatives ; FIXME: currently used by Odyssey but should maybe be in 'backend?\n          fpcores\n          'derivations\n          derivations\n          'backend\n          backend-hash))\n\n(define (backend-improve-result-hash-table backend test errcache)\n  (define ctx (test-context test))\n  (define pcontext (improve-result-pcontext backend))\n  (hasheq 'pcontext\n          (pcontext->json pcontext ctx)\n          'start\n          (analysis->json (improve-result-start backend) pcontext test errcache)\n          'target\n          (map (curryr analysis->json pcontext test errcache) (improve-result-target backend))\n          'end\n          (map (curryr analysis->json pcontext test errcache) (improve-result-end backend))))\n\n(define (pcontext->json pcontext ctx)\n  (define var-reprs (context-var-reprs ctx))\n  (define out-repr (context-repr ctx))\n  (for/list ([(pt ex) (in-pcontext pcontext)])\n    (list (for/list ([val (in-vector pt)]\n                     [repr (in-list var-reprs)])\n            (value->json val repr))\n          (value->json ex out-repr))))\n\n(define (analysis->json analysis pcontext test errcache)\n  (define repr (context-repr (test-context test)))\n  (match-define (alt-analysis alt test-errors) analysis)\n  (define cost (alt-cost alt repr))\n\n  (define history-json (render-json alt pcontext (test-context test) errcache))\n\n  (define vars (test-vars test))\n  (define splitpoints\n    (for/list ([var (in-list vars)])\n      (if (equal? var (regime-var alt))\n          (for/list ([val (in-list (regime-splitpoints alt))])\n            (real->ordinal (repr->real val repr) repr))\n          '())))\n\n  (hasheq 'expr\n          (~s (alt-expr alt))\n          'history\n          history-json\n          'errors\n          (flvector->list test-errors)\n          'cost\n          cost\n          'splitpoints\n          splitpoints))\n\n(define (alt->fpcore test altn)\n  (define out-repr (test-output-repr test))\n  (define out-base-repr (array-representation-base out-repr))\n  `(FPCore ,@(filter identity (list (test-identifier test)))\n           ,(for/list ([var (in-list (test-vars test))]\n                       [repr (in-list (test-var-reprs test))])\n              (cond\n                [(array-representation? repr)\n                 (define dims (array-representation-shape repr))\n                 (define elem-repr (array-representation-base repr))\n                 (if (equal? elem-repr out-base-repr)\n                     (append (list var) dims)\n                     (append (list '! ':precision (representation-name elem-repr) var) dims))]\n                [else\n                 (if (equal? repr out-base-repr)\n                     var\n                     (list '! ':precision (representation-name repr) var))]))\n           :name\n           ,(test-name test)\n           :precision\n           ,(representation-name out-base-repr)\n           ,@(if (equal? (test-pre test) '(TRUE))\n                 '()\n                 `(:pre ,(prog->fpcore (test-pre test) (test-context test))))\n           ,@(if (equal? (test-spec test) empty)\n                 '()\n                 `(:spec ,(prog->fpcore (test-spec test) (test-context test))))\n           ,@(if (equal? (test-expected test) #t)\n                 '()\n                 `(:herbie-expected ,(test-expected test)))\n           ,@(apply append\n                    (for/list ([(target enabled?) (in-dict (test-output test))]\n                               #:when enabled?)\n                      `(:alt ,target)))\n           ,(prog->fpcore (alt-expr altn) (test-context test))))\n"
  },
  {
    "path": "src/api/shell.rkt",
    "content": "#lang racket\n\n(require \"../syntax/platform.rkt\"\n         \"../syntax/load-platform.rkt\"\n         \"../syntax/read.rkt\"\n         \"../utils/common.rkt\"\n         \"server.rkt\")\n(provide run-shell\n         run-improve)\n\n(define (get-shell-input)\n  (printf \"herbie> \")\n  (with-handlers ([(or/c exn:fail:user? exn:fail:read?) (λ (e)\n                                                          ((error-display-handler) (exn-message e) e)\n                                                          (get-shell-input))])\n    (define input\n      (parameterize ([read-decimal-as-inexact false])\n        (read-syntax \"stdin\" (current-input-port))))\n    (cond\n      [(eof-object? input)\n       (printf \"\\n\")\n       eof]\n      [else (parse-test input)])))\n\n(define (job-result->fpcore result)\n  (read (open-input-string (first (hash-ref result 'alternatives)))))\n\n(define (print-improve-outputs tests results p #:seed [seed #f])\n  (when seed\n    (fprintf p \";; seed: ~a\\n\\n\" seed))\n  (for ([res results]\n        [test tests]\n        #:when res)\n    (define name (hash-ref res 'name))\n    (match (hash-ref res 'status)\n      [\"failure\"\n       (match-define (list 'exn type msg url locs traceback) (hash-ref res 'backend))\n       (fprintf p \";; ~a in ~a\\n\" (if type \"Error\" \"Crash\") name)]\n      [\"timeout\" (fprintf p \";; ~a times out in ~as\\n\" (/ (*timeout*) 1000) name)]\n      [\"success\" (void)])\n    (displayln (fpcore->string (job-result->fpcore res)) p)\n    (newline)))\n\n(define (run-improve input output #:threads [threads #f])\n  (define seed (get-seed))\n  (activate-platform! (*platform-name*))\n  (define tests (load-tests input))\n  (server-start threads)\n  (define ids\n    (for/list ([test (in-list tests)])\n      (job-start 'improve test #:seed seed #:pcontext #f #:profile? #f #:timeline? #f)))\n  (define results\n    (for/list ([id ids])\n      (job-wait id)))\n\n  (if (equal? output \"-\")\n      (print-improve-outputs tests results (current-output-port) #:seed seed)\n      (call-with-output-file output\n                             #:exists 'replace\n                             (λ (p) (print-improve-outputs tests results p #:seed seed)))))\n\n(define (run-shell)\n  (define seed (get-seed))\n  (activate-platform! (*platform-name*))\n  (server-start #f)\n  (eprintf \"Find help on https://herbie.uwplse.org/, exit with ~a\\n\"\n           (match (system-type 'os)\n             ['windows \"Ctrl-Z Enter\"]\n             [_ \"Ctrl-D\"]))\n  (with-handlers ([exn:break? (λ (e) (exit 0))])\n    (for ([test (in-producer get-shell-input eof-object?)]\n          [idx (in-naturals)])\n      (define result (job-wait (job-start 'improve test #:seed seed)))\n      (match (hash-ref result 'status)\n        [\"success\" (displayln (fpcore->string (job-result->fpcore result)))]\n        [\"failure\"\n         (match-define (list 'exn type msg url locs traceback) (hash-ref result 'backend))\n         (printf \"; ~a\\n\" msg)\n         (for ([loc (in-list locs)])\n           (match-define (list msg file line col pos) loc)\n           (printf \";   ~a:~a~a: ~a\\n\" file line col msg))\n         (printf \"; See <https://herbie.uwplse.org/doc/~a/~a> for more.\\n\" *herbie-version* url)]\n        [\"timeout\"\n         (printf \"; Timeout in ~as (see --timeout option)\\n\" (/ (hash-ref result 'time) 1000))]))))\n"
  },
  {
    "path": "src/config.rkt",
    "content": "#lang racket\n\n(require racket/hash)\n\n(provide (all-defined-out))\n\n;;; Flags\n\n(define default-flags\n  #hash([precision . ()]\n        [setup . (search preprocess)]\n        [localize . ()]\n        [generate . (rr taylor proofs evaluate)]\n        [reduce . (regimes binary-search branch-expressions)]\n        [rules . (arithmetic polynomials fractions exponents trigonometry hyperbolic special)]\n        [dump . ()]))\n\n(define deprecated-flags\n  #hash([precision . (double fallback)]\n        [setup . (simplify)]\n        [localize . (costs errors)]\n        [generate . (better-rr simplify)]\n        [reduce . (avg-error simplify)]\n        [rules . (numerics special bools branches)]))\n\n(define debug-flags\n  #hash([generate . (egglog)] [dump . (egg rival egglog trace intermediates)] [setup . (rival2)]))\n\n(define all-flags (hash-union default-flags deprecated-flags debug-flags #:combine set-union))\n\n(define (flag-deprecated? category flag)\n  (set-member? (dict-ref deprecated-flags category '()) flag))\n\n; `hash-copy` returns a mutable hash, which makes `dict-update` invalid\n(define *flags* (make-parameter (make-immutable-hash (hash->list default-flags))))\n\n(define (flag-set? class flag)\n  (set-member? (dict-ref (*flags*) class) flag))\n\n(define (enable-flag! category flag)\n  (when (flag-deprecated? category flag)\n    (warn-flag-deprecated! category flag))\n  (define (update cat-flags)\n    (set-add cat-flags flag))\n  (*flags* (dict-update (*flags*) category update)))\n\n(define (disable-flag! category flag)\n  (when (flag-deprecated? category flag)\n    (warn-flag-deprecated! category flag))\n  (define (update cat-flags)\n    (set-remove cat-flags flag))\n  (*flags* (dict-update (*flags*) category update)))\n\n(define (warn-flag-deprecated! category flag)\n  (match* (category flag)\n    [('precision 'double)\n     (eprintf \"The precision:double option has been removed.\\n\")\n     (eprintf \"  The double-precision representation is specified with :precision binary64.\\n\")\n     (eprintf \"See <https://herbie.uwplse.org/doc/~a/input.html> for more.\\n\" *herbie-version*)]\n    [('precision 'fallback)\n     (eprintf \"The precision:fallback option has been removed.\\n\")\n     (eprintf \"  The fallback representation is specified with :precision racket.\\n\")\n     (eprintf \"See <https://herbie.uwplse.org/doc/~a/input.html> for more.\\n\" *herbie-version*)]\n    [('setup 'simplify)\n     (eprintf \"The setup:simplify option has been removed.\\n\")\n     (eprintf \"  Initial simplification is no longer needed.\\n\")\n     (eprintf \"See <https://herbie.uwplse.org/doc/~a/options.html> for more.\\n\" *herbie-version*)]\n    [('generate 'better-rr)\n     (eprintf \"The generate:better-rr option has been removed.\\n\")\n     (eprintf \"  The current recursive rewriter does not support the it.\\n\")\n     (eprintf \"See <https://herbie.uwplse.org/doc/~a/options.html> for more.\\n\" *herbie-version*)]\n    [('generate 'simplify)\n     (eprintf \"The generate:simplify option has been removed.\\n\")\n     (eprintf \"  Simplification is no longer performed as a separate step.\\n\")\n     (eprintf \"See <https://herbie.uwplse.org/doc/~a/options.html> for more.\\n\" *herbie-version*)]\n    [('reduce 'simplify)\n     (eprintf \"The reduce:simplify option has been removed.\\n\")\n     (eprintf \"  Final-simplification is no longer performed.\\n\")\n     (eprintf \"See <https://herbie.uwplse.org/doc/~a/options.html> for more.\\n\" *herbie-version*)]\n    [('reduce 'avg-error)\n     (eprintf \"The reduce:avg-error option has been removed.\\n\")\n     (eprintf \"  Herbie now always uses average error for pruning.\\n\")\n     (eprintf \"See <herbie://herbie.uwplse.org/doc/~a/options.html> for more.\\n\" *herbie-version*)]\n    [('localize 'costs)\n     (eprintf \"The localize:costs option has been removed.\\n\")\n     (eprintf \"  Herbie no longer performs localization.\\n\")\n     (eprintf \"See <herbie://herbie.uwplse.org/doc/~a/options.html> for more.\\n\" *herbie-version*)]\n    [('localize 'errors)\n     (eprintf \"The localize:errors option has been removed.\\n\")\n     (eprintf \"  Herbie no longer performs localization.\\n\")\n     (eprintf \"See <herbie://herbie.uwplse.org/doc/~a/options.html> for more.\\n\" *herbie-version*)]\n    [('rules _)\n     (eprintf \"The rules:~a ruleset has been removed.\\n\")\n     (eprintf \"  These rules are no longer used by Herbie.\\n\")\n     (eprintf \"See <herbie://herbie.uwplse.org/doc/~a/options.html> for more.\\n\" *herbie-version*)]\n    [(_ _) (void)]))\n\n(define (changed-flags)\n  (filter identity\n          (for*/list ([(class flags) all-flags]\n                      [flag flags])\n            (match* ((flag-set? class flag) (parameterize ([*flags* default-flags])\n                                              (flag-set? class flag)))\n              [(#t #t) #f]\n              [(#f #f) #f]\n              [(#t #f) (list 'enabled class flag)]\n              [(#f #t) (list 'disabled class flag)]))))\n\n;;; Herbie internal parameters\n\n;; Number of points to sample for evaluating program accuracy\n(define *num-points* (make-parameter 256))\n\n;; Number of iterations of the core loop for improving program accuracy\n(define *num-iterations* (make-parameter 4))\n\n;; The maximum depth for splitting the space when searching for valid areas of points.\n(define *max-find-range-depth* (make-parameter 12))\n\n;; The maximum number of consecutive skipped points for sampling valid points\n(define *max-skipped-points* (make-parameter 100))\n\n;; Maximum MPFR precision allowed during exact evaluation\n(define *max-mpfr-prec* (make-parameter 10000))\n\n;; The maximum size of an egraph\n(define *node-limit* (make-parameter 4000))\n(define *proof-max-length* (make-parameter 200))\n(define *proof-max-string-length* (make-parameter 10000))\n\n;; How long of a Taylor series to generate; too long and we time out\n(define *taylor-order-limit* (make-parameter 4))\n\n;; How accurate to make the binary search\n(define *binary-search-test-points* (make-parameter 16))\n(define *binary-search-accuracy* (make-parameter 48))\n\n;; If `:precision` is unspecified, which representation should we use?\n(define *default-precision* (make-parameter 'binary64))\n\n;; The platform that Herbie will evaluate with.\n(define *platform-name* (make-parameter (if (equal? (system-type 'os) 'windows) \"c-windows\" \"c\")))\n\n;; Sets the number of total points for Herbie to sample.\n(define *reeval-pts* (make-parameter 8000))\n\n;; Time out for a given run. 2.5 minutes currently.\n(define *timeout* (make-parameter (* 1000 60 5/2)))\n\n;; The number of variants extracted from egglog\n(define *egglog-variants-limit* (make-parameter 1000000))\n\n;; The number of iterations for the egglog search\n(define *default-egglog-iter-limit* (make-parameter 50))\n\n;;; The random seed\n\n(define the-seed #f)\n\n(define (get-seed)\n  (or the-seed (error \"Seed is not set yet!\")))\n\n(define (set-seed! seed)\n  \"Reset the random number generator to a new seed\"\n  (set! the-seed seed)\n  (if (vector? seed)\n      (current-pseudo-random-generator (vector->pseudo-random-generator seed))\n      (random-seed seed)))\n\n;;; About Herbie:\n\n(define (run-command cmd)\n  (parameterize ([current-error-port (open-output-nowhere)])\n    (string-trim (with-output-to-string (λ () (system cmd))))))\n\n(define (git-command #:default default gitcmd . args)\n  (cond\n    [(or (directory-exists? \".git\") (file-exists? \".git\")) ; gitlinks like for worktrees\n     (define cmd (format \"git ~a ~a\" gitcmd (string-join args \" \")))\n     (define out (run-command cmd))\n     (if (equal? out \"\") default out)]\n    [else default]))\n\n(define *herbie-version* \"2.3\")\n\n(define *herbie-commit* (git-command \"rev-parse\" \"HEAD\" #:default *herbie-version*))\n\n(define *herbie-branch* (git-command \"rev-parse\" \"--abbrev-ref\" \"HEAD\" #:default \"release\"))\n\n;;; The \"reset\" mechanism for clearing caches and such\n\n(define resetters '())\n(define (register-resetter! fn)\n  (set! resetters (cons fn resetters)))\n\n(define (reset!)\n  (for ([fn (in-list resetters)])\n    (fn)))\n\n(define-syntax define/reset\n  (syntax-rules ()\n    ; default resetter sets parameter to `value`\n    [(_ name value) (define/reset name value (λ () (name value)))]\n    ; initial value and resetter\n    [(_ name value reset-fn)\n     (define name\n       (let ([param (make-parameter value)])\n         (register-resetter! reset-fn)\n         param))]))\n"
  },
  {
    "path": "src/core/alt-table.rkt",
    "content": "#lang racket\n\n(require racket/hash)\n(require math/flonum)\n(require \"../core/alternative.rkt\"\n         \"../utils/common.rkt\"\n         \"../utils/pareto.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/syntax.rkt\"\n         \"../syntax/platform.rkt\"\n         \"../syntax/batch.rkt\"\n         \"points.rkt\"\n         \"programs.rkt\")\n\n(provide (contract-out\n          (make-alt-table (batch? pcontext? alt? any/c . -> . alt-table?))\n          (atab-active-alts (alt-table? . -> . (listof alt?)))\n          (atab-all-alts (alt-table? . -> . (listof alt?)))\n          (atab-not-done-alts (alt-table? . -> . (listof alt?)))\n          (atab-eval-altns (alt-table? batch? (listof alt?) context? . -> . (values any/c any/c)))\n          (atab-add-altns (alt-table? (listof alt?) any/c any/c context? . -> . alt-table?))\n          (atab-set-picked (alt-table? (listof alt?) . -> . alt-table?))\n          (atab-completed? (alt-table? . -> . boolean?))\n          (atab-min-errors (alt-table? . -> . flvector?))\n          (alt-batch-costs (batch? context? . -> . (batchref? . -> . real?)))))\n\n;; Public API\n\n(struct alt-table (point-idx->alts alt->point-idxs alt->done? alt->cost pcontext all) #:prefab)\n\n(define (alt-batch-costs batch ctx)\n  (define node-cost-proc (platform-node-cost-proc (*active-platform*)))\n  (define reprs (batch-reprs batch ctx))\n  (batch-recurse batch\n                 (λ (brf recurse)\n                   (define node (deref brf))\n                   (define repr (reprs brf))\n                   (match node\n                     [(? literal?) ((node-cost-proc node repr))]\n                     [(? symbol?) ((node-cost-proc node repr))]\n                     [(? number?) 0] ; specs\n                     [(approx _ impl) (recurse impl)]\n                     [(list (? (negate impl-exists?) impl) args ...) 0] ; specs\n                     [(list impl args ...)\n                      (define cost-proc (node-cost-proc node repr))\n                      (apply cost-proc (map recurse args))]))))\n\n(define (make-alt-table batch pcontext initial-alt ctx)\n  (define cost ((alt-batch-costs batch ctx) (alt-expr initial-alt)))\n  (define errs (batchref-errors (alt-expr initial-alt) pcontext ctx))\n  (alt-table (for/vector #:length (pcontext-length pcontext)\n                         ([err (in-flvector errs)])\n               (list (pareto-point cost err (list initial-alt))))\n             (hasheq initial-alt\n                     (for/list ([idx (in-range (pcontext-length pcontext))])\n                       idx))\n             (hasheq initial-alt #f)\n             (hasheq initial-alt cost)\n             pcontext\n             (list initial-alt)))\n\n(define (atab-set-picked atab alts)\n  (struct-copy alt-table\n               atab\n               [point-idx->alts (vector-copy (alt-table-point-idx->alts atab))]\n               [alt->done?\n                (for/fold ([alt->done? (alt-table-alt->done? atab)]) ([alt (in-list alts)])\n                  (hash-set alt->done? alt #t))]))\n\n(define (atab-completed? atab)\n  (andmap (curry hash-ref (alt-table-alt->done? atab)) (hash-keys (alt-table-alt->point-idxs atab))))\n\n;;\n;; Hash/set iteration order is unspecified. Always sort extracted alternatives\n;; before iterating so search decisions do not depend on table iteration order.\n;;\n(define (order-altns altns)\n  (sort altns expr<? #:key alt-expr))\n\n(define (atab-active-alts atab)\n  (order-altns (hash-keys (alt-table-alt->point-idxs atab))))\n\n(define (atab-all-alts atab)\n  (order-altns (alt-table-all atab)))\n\n(define (atab-not-done-alts atab)\n  (define altns (hash-keys (alt-table-alt->point-idxs atab)))\n  (define not-done? (negate (curry hash-ref (alt-table-alt->done? atab))))\n  (order-altns (filter not-done? altns)))\n\n;; Implementation\n\n(struct set-cover (removable coverage))\n\n(define (atab->set-cover atab)\n  (match-define (alt-table pnts->alts alts->pnts alt->done? alt->cost _ _) atab)\n  (define tied (list->mutable-seteq (hash-keys alts->pnts)))\n  (define coverage '())\n  (for* ([pcurve (in-vector pnts->alts)]\n         [ppt (in-list pcurve)])\n    (match (pareto-point-data ppt)\n      [(list) (error \"This point has no alts which are best at it!\" ppt)]\n      [(list altn) (set-remove! tied altn)]\n      [altns (set! coverage (cons (list->vector altns) coverage))]))\n  (set-cover tied (list->vector coverage)))\n\n(define (set-cover-remove! sc altn)\n  (match-define (set-cover removable coverage) sc)\n  (set-remove! removable altn)\n  (for ([j (in-naturals)]\n        [s (in-vector coverage)]\n        #:when s)\n    (define count 0)\n    (define last #f)\n    (for ([i (in-naturals)]\n          [a (in-vector s)]\n          #:when a)\n      (cond\n        [(eq? a altn) (vector-set! s i #f)]\n        [a\n         (set! count (add1 count))\n         (set! last a)]))\n    (when (= count 1)\n      (vector-set! coverage j #f)\n      (set-remove! removable last))))\n\n(define ((removability<? atab) alt1 alt2)\n  (define alt1-done? (hash-ref (alt-table-alt->done? atab) alt1))\n  (define alt2-done? (hash-ref (alt-table-alt->done? atab) alt2))\n  (cond\n    [(and (not alt1-done?) alt2-done?) #t]\n    [(and alt1-done? (not alt2-done?)) #f]\n    [else\n     (define alt1-num (length (hash-ref (alt-table-alt->point-idxs atab) alt1)))\n     (define alt2-num (length (hash-ref (alt-table-alt->point-idxs atab) alt2)))\n     (cond\n       [(< alt1-num alt2-num) #t]\n       [(> alt1-num alt2-num) #f]\n       [else\n        (define alt1-cost (hash-ref (alt-table-alt->cost atab) alt1))\n        (define alt2-cost (hash-ref (alt-table-alt->cost atab) alt2))\n        (cond\n          [(< alt1-cost alt2-cost) #f]\n          [(< alt2-cost alt1-cost) #t]\n          [else (expr<? (alt-expr alt1) (alt-expr alt2))])])]))\n\n(define (atab-prune atab)\n  (define sc (atab->set-cover atab))\n  (define removability (sort (set->list (set-cover-removable sc)) (removability<? atab)))\n  (let loop ([removed '()]\n             [removability removability])\n    (match removability\n      ['() (apply atab-remove* atab removed)]\n      [(cons worst-alt other-alts)\n       (cond\n         [(set-member? (set-cover-removable sc) worst-alt)\n          (set-cover-remove! sc worst-alt)\n          (loop (cons worst-alt removed) other-alts)]\n         [else (loop removed other-alts)])])))\n\n(define (hash-remove* hash keys)\n  (for/fold ([hash hash]) ([key keys])\n    (hash-remove hash key)))\n\n(define (atab-remove* atab . altns)\n  (match-define (alt-table point-idx->alts alt->point-idxs alt->done? alt->cost pctx _) atab)\n  (define pnt-idx->alts*\n    (for/vector #:length (vector-length point-idx->alts)\n                ([pcurve (in-vector point-idx->alts)])\n      (pareto-map (curry remq* altns) pcurve)))\n  (struct-copy alt-table\n               atab\n               [point-idx->alts pnt-idx->alts*]\n               [alt->point-idxs (hash-remove* alt->point-idxs altns)]\n               [alt->done? (hash-remove* alt->done? altns)]\n               [alt->cost (hash-remove* alt->cost altns)]))\n\n(define (atab-eval-altns atab batch altns ctx)\n  (define brfs (map alt-expr altns))\n  (define errss (batch-errors batch brfs (alt-table-pcontext atab) ctx))\n  (define costs (map (alt-batch-costs batch ctx) brfs))\n  (values errss costs))\n\n(define (atab-add-altns atab altns errss costs ctx)\n  (define atab*\n    (for/fold ([atab atab])\n              ([altn (in-list altns)]\n               [errs (in-list errss)]\n               [cost (in-list costs)])\n      (atab-add-altn atab altn errs cost ctx)))\n  (define atab**\n    (struct-copy alt-table atab* [alt->point-idxs (invert-index (alt-table-point-idx->alts atab*))]))\n  (define atab*** (atab-prune atab**))\n  (struct-copy alt-table\n               atab***\n               [alt->point-idxs (invert-index (alt-table-point-idx->alts atab***))]\n               [all\n                (set-union (alt-table-all atab) (hash-keys (alt-table-alt->point-idxs atab***)))]))\n\n(define (invert-index point-idx->alts)\n  (define alt->points* (make-hasheq))\n  (for ([pcurve (in-vector point-idx->alts)]\n        [idx (in-naturals)])\n    (for* ([ppt (in-list pcurve)]\n           [alt (in-list (pareto-point-data ppt))])\n      (hash-update! alt->points* alt (λ (v) (cons idx v)) '())))\n  (make-immutable-hasheq (hash->list alt->points*)))\n\n(define (atab-add-altn atab altn errs cost ctx)\n  (match-define (alt-table point-idx->alts alt->point-idxs alt->done? alt->cost pcontext _) atab)\n  (define max-valid-bits (representation-total-bits (context-repr ctx)))\n  ;; Check  whether altn is already inserted into atab\n  (match (hash-has-key? alt->point-idxs altn)\n    [#f\n     (define point-idx->alts*\n       (for/vector #:length (vector-length point-idx->alts)\n                   ([pcurve (in-vector point-idx->alts)]\n                    [err (in-flvector errs)])\n         (cond\n           [(<= err max-valid-bits) ; Only include points if they are valid\n            (define ppt (pareto-point cost err (list altn)))\n            (pareto-union (list ppt) pcurve #:combine append)]\n           [else pcurve])))\n\n     (alt-table point-idx->alts*\n                (hash-set alt->point-idxs altn #f)\n                (hash-set alt->done? altn #f)\n                (hash-set alt->cost altn cost)\n                pcontext\n                #f)]\n    [_ atab]))\n\n(define (atab-min-errors atab)\n  (define pnt-idx->alts (alt-table-point-idx->alts atab))\n  (for/flvector #:length (pcontext-length (alt-table-pcontext atab))\n                ([curve (in-vector pnt-idx->alts)])\n                ;; Curve is sorted so lowest error is first\n                (pareto-point-error (first curve))))\n"
  },
  {
    "path": "src/core/alternative.rkt",
    "content": "#lang racket\n\n(require \"../syntax/platform.rkt\"\n         \"../syntax/batch.rkt\")\n(provide (struct-out alt)\n         (struct-out sp)\n         make-alt\n         alt-cost\n         alt-map\n         unbatchify-alts)\n\n;; A splitpoint (sp a b pt) means we should use alt a if b < pt\n;; The last splitpoint uses +nan.0 for pt and represents the \"else\"\n(struct sp (cidx bexpr point) #:prefab)\n\n;; Alts are an expression plus a derivation for it.\n\n(struct alt (expr event prevs) #:prefab)\n\n(define (make-alt expr)\n  (alt expr 'start '()))\n\n(define (alt-cost altn repr)\n  (define expr-cost (platform-cost-proc (*active-platform*)))\n  (expr-cost (alt-expr altn) repr))\n\n(define (alt-map f altn)\n  (f (struct-copy alt altn [prevs (map (curry alt-map f) (alt-prevs altn))])))\n\n;; Converts batchrefs of altns into expressions, assuming that batchrefs refer to batch\n(define (unbatchify-alts batch altns)\n  (define exprs (batch-exprs batch))\n  (define (unmunge-event event)\n    (match event\n      [(list 'evaluate (? batchref? start-expr)) (list 'evaluate (exprs start-expr))]\n      [(list 'taylor (? batchref? start-expr) name var) (list 'taylor (exprs start-expr) name var)]\n      [(list 'rr (? batchref? start-expr) (? batchref? end-expr) input proof)\n       (define proof* (and proof (map exprs proof)))\n       (list 'rr (exprs start-expr) (exprs end-expr) input proof*)]\n      [(list 'regimes splitpoints)\n       (list 'regimes\n             (for/list ([spt (in-list splitpoints)])\n               (struct-copy sp spt [bexpr (exprs (sp-bexpr spt))])))]\n      [_ event]))\n  (define (unmunge altn)\n    (define expr (alt-expr altn))\n    (define expr*\n      (if (batchref? expr)\n          (exprs expr)\n          expr))\n    (define event* (unmunge-event (alt-event altn)))\n    (struct-copy alt altn [expr expr*] [event event*]))\n  (map (curry alt-map unmunge) altns))\n"
  },
  {
    "path": "src/core/arrays.rkt",
    "content": "#lang racket\n\n(require racket/hash\n         racket/list\n         \"../syntax/types.rkt\")\n\n(provide flatten-arrays-for-rival)\n\n;; Flatten array inputs/outputs into scalar inputs/outputs for Rival.\n;; Returns:\n;;   - flattened specs\n;;   - flattened contexts\n;;   - flattened precondition\n;;   - point assembler (original point -> flattened point)\n;;   - output assembler (flattened outputs -> original outputs)\n;;   - flattened output reprs\n(define (flatten-arrays-for-rival specs ctxs pre)\n  (define orig-vars (context-vars (first ctxs)))\n  (define orig-reprs (map context-repr ctxs))\n  (define orig-var-reprs (context-var-reprs (first ctxs)))\n  (define taken (apply mutable-seteq orig-vars))\n  (define (fresh base)\n    (let loop ([i 0])\n      (define candidate (string->symbol (format \"~a_~a\" base i)))\n      (if (set-member? taken candidate)\n          (loop (add1 i))\n          (begin\n            (set-add! taken candidate)\n            candidate))))\n  (define (leaf-reprs repr)\n    (if (array-representation? repr)\n        (append* (for/list ([_ (in-range (array-representation-len repr))])\n                   (leaf-reprs (array-representation-elem repr))))\n        (list repr)))\n  (define (fresh-tree base repr)\n    (if (array-representation? repr)\n        (let-values ([(elems vars reprs) (for/lists (elems vars reprs)\n                                                    ([_ (in-range (array-representation-len repr))])\n                                                    (fresh-tree base\n                                                                (array-representation-elem repr)))])\n          (values `(array ,@elems) (append* vars) (append* reprs)))\n        (let ([v (fresh base)]) (values v (list v) (list repr)))))\n  (define (flatten-by-repr expr repr)\n    (if (array-representation? repr)\n        (match-let ([`(array ,elems ...) expr])\n          (append* (for/list ([elem (in-list elems)])\n                     (flatten-by-repr elem (array-representation-elem repr)))))\n        (list expr)))\n  (define (build-value next repr)\n    (if (array-representation? repr)\n        (for/vector #:length (array-representation-len repr)\n                    ([_ (in-range (array-representation-len repr))])\n          (build-value next (array-representation-elem repr)))\n        (next)))\n\n  (define env (make-hasheq))\n  (define new-vars '())\n  (define new-var-reprs '())\n  (for ([v orig-vars]\n        [r orig-var-reprs])\n    (cond\n      [(array-representation? r)\n       (define base (symbol->string v))\n       (define-values (tree vars reprs) (fresh-tree base r))\n       (hash-set! env v tree)\n       (set! new-vars (append new-vars vars))\n       (set! new-var-reprs (append new-var-reprs reprs))]\n      [else\n       (hash-set! env v v)\n       (set! new-vars (append new-vars (list v)))\n       (set! new-var-reprs (append new-var-reprs (list r)))]))\n  (define (lower-arr expr)\n    (match expr\n      [(? number?) expr]\n      [(? symbol? s) (hash-ref env s s)]\n      [`(,op ,args ...)\n       (define lowered `(,op ,@(map lower-arr args)))\n       (match lowered\n         [`(ref (array ,elems ...) ,idx) (list-ref elems idx)]\n         [_ lowered])]))\n\n  (define new-specs '())\n  (define new-reprs '())\n  (for ([spec (in-list specs)]\n        [repr (in-list orig-reprs)])\n    (define lowered (lower-arr spec))\n    (cond\n      [(array-representation? repr)\n       (define comps (flatten-by-repr lowered repr))\n       (define reprs (leaf-reprs repr))\n       (set! new-specs (append new-specs comps))\n       (set! new-reprs (append new-reprs reprs))]\n      [else\n       (set! new-specs (append new-specs (list lowered)))\n       (set! new-reprs (append new-reprs (list repr)))]))\n\n  (define new-pre (lower-arr pre))\n  (define ctxs*\n    (for/list ([ctx (in-list ctxs)])\n      (match-define (context _ repr _) ctx)\n      (context new-vars\n               (if (array-representation? repr)\n                   (array-representation-base repr)\n                   repr)\n               new-var-reprs)))\n\n  (define (assemble-point pt)\n    (define idx 0)\n    (define (next)\n      (begin0 (vector-ref pt idx)\n        (set! idx (add1 idx))))\n    (for/vector #:length (length orig-var-reprs)\n                ([repr (in-list orig-var-reprs)])\n      (build-value next repr)))\n\n  (define (assemble-output outs)\n    (define outputs\n      (if (vector? outs)\n          (vector->list outs)\n          outs))\n    (define idx 0)\n    (define (next)\n      (begin0 (list-ref outputs idx)\n        (set! idx (add1 idx))))\n    (for/list ([repr (in-list orig-reprs)])\n      (if (array-representation? repr)\n          (build-value next repr)\n          (next))))\n\n  (values new-specs ctxs* new-pre assemble-point assemble-output new-reprs))\n\n(module+ test\n  (require rackunit)\n\n  (define vec2 (make-array-representation #:elem <binary64> #:len 2))\n  (define ctx (context '(x) <binary64> (list vec2)))\n  (let-values ([(specs* _ pre* _assemble-point _assemble-output _reprs*)\n                (flatten-arrays-for-rival (list '(ref x 1)) (list ctx) '(< (ref x 0) (ref x 1)))])\n    (check-equal? specs* '(x_1))\n    (check-equal? pre* '(< x_0 x_1)))\n\n  (define mat2 (make-array-representation #:elem vec2 #:len 2))\n  (define nested-ctx (context '(x) <binary64> (list mat2)))\n  (let-values ([(specs* _ pre* assemble-point _assemble-output _reprs*)\n                (flatten-arrays-for-rival (list '(ref (ref x 1) 0))\n                                          (list nested-ctx)\n                                          '(< (ref (ref x 0) 1) (ref (ref x 1) 0)))])\n    (check-equal? specs* '(x_2))\n    (check-equal? pre* '(< x_1 x_2))\n    (check-equal? (assemble-point #(1 2 3 4)) #(#(#(1 2) #(3 4)))))\n\n  (let-values ([(specs* _ctxs* _pre* _assemble-point assemble-output reprs*)\n                (flatten-arrays-for-rival (list '(array (array 1 2) (array 3 4)))\n                                          (list (context '() mat2 '()))\n                                          'TRUE)])\n    (check-equal? specs* '(1 2 3 4))\n    (check-equal? reprs* (list <binary64> <binary64> <binary64> <binary64>))\n    (check-equal? (assemble-output '(10 11 12 13)) (list #(#(10 11) #(12 13))))))\n"
  },
  {
    "path": "src/core/batch-reduce.rkt",
    "content": "#lang racket\n\n(require \"../syntax/batch.rkt\"\n         \"../utils/common.rkt\"\n         \"programs.rkt\")\n\n(provide batch-reduce)\n\n(define global-batch (make-parameter #f))\n\n;; This is a transcription of egg-herbie/src/math.rs, lines 97-149\n(define (batch-eval-application batch)\n  (define exact-value? (conjoin number? exact?))\n  (define (eval-application brf recurse)\n    (match (deref brf)\n      [(? exact-value? val)\n       val] ;; this part is not naive in rewriting. should be considered for the future\n      [(list '+ (app recurse (? exact-value? as)) ...) (apply + as)]\n      [(list '- (app recurse (? exact-value? as)) ...) (apply - as)]\n      [(list '* (app recurse (? exact-value? as)) ...) (apply * as)]\n      [(list '/ (app recurse (? exact-value? num)) (app recurse (? exact-value? den)))\n       (and (not (zero? den)) (/ num den))]\n      [(list 'neg (app recurse (? exact-value? arg))) (- arg)]\n      [(list 'pow (app recurse (? exact-value? a)) (app recurse (? exact-value? b)))\n       (cond\n         [(and (zero? b) (not (zero? a))) 1]\n         [(and (zero? a) (positive? b)) 0]\n         [(and (not (zero? a)) (integer? b)) (expt a b)]\n         [(= a -1) (if (even? (numerator b)) 1 -1)]\n         [(= a 1) 1]\n         [else #f])]\n      [(list 'sqrt (app recurse (? exact-value? a)))\n       (define s1 (sqrt (numerator a)))\n       (define s2 (sqrt (denominator a)))\n       (and (real? s1) (real? s2) (exact? s1) (exact? s2) (/ s1 s2))]\n      [(list 'cbrt (app recurse (? exact-value? a)))\n       (define inexact-num (inexact->exact (expt (abs (numerator a)) 1/3)))\n       (define inexact-den (inexact->exact (expt (abs (denominator a)) 1/3)))\n       (and (real? inexact-num)\n            (real? inexact-den)\n            (= (expt inexact-num 3) (abs (numerator a)))\n            (= (expt inexact-den 3) (abs (denominator a)))\n            (* (sgn a) (/ inexact-num inexact-den)))]\n      [(list 'fabs (app recurse (? exact-value? a))) (abs a)]\n      [(list 'floor (app recurse (? exact-value? a))) (floor a)]\n      [(list 'ceil (app recurse (? exact-value? a))) (ceiling a)]\n      [(list 'round (app recurse (? exact-value? a))) (round a)]\n      [(list 'exp (app recurse 0)) 1]\n      [(list 'log (app recurse 1)) 0]\n      [_ #f]))\n  (batch-recurse batch eval-application))\n\n(define (batch-reduce batch)\n  ;; Dependencies\n  (define eval-application (batch-eval-application batch))\n  (define gather-multiplicative-terms (batch-gather-multiplicative-terms batch eval-application))\n\n  (letrec ([reduce-node\n            (batch-recurse\n             batch\n             (lambda (brf recurse)\n               (define brf* (reduce-evaluation brf))\n               (match (deref brf*)\n                 [(? number?) brf*]\n                 [(? symbol?) brf*]\n                 [(or `(+ ,_ ...) `(- ,_ ...) `(neg ,_))\n                  (make-addition-node (combine-aterms (gather-additive-terms brf*)))]\n                 [(or `(* ,_ ...)\n                      `(/ ,_ ...)\n                      `(cbrt ,_)\n                      `(pow ,_ ,(app deref (? (conjoin rational? (negate even-denominator?))))))\n                  (make-multiplication-node (combine-mterms (gather-multiplicative-terms brf*)))]\n                 [(list 'exp (app deref (list '* c (app deref (list 'log x)))))\n                  (define rewrite (batch-add! batch `(pow ,x ,c)))\n                  (recurse rewrite)]\n                 [else (reduce-inverses brf*)])))]\n           [gather-additive-terms\n            (batch-recurse\n             batch\n             (lambda (brf recurse)\n               (match (deref brf)\n                 [(? number? n) `((,n ,(batch-push! batch 1)))]\n                 [(? symbol?) `((1 ,brf))]\n                 [`(+ ,args ...) (append-map recurse args)]\n                 [`(neg ,arg) (map negate-term (recurse arg))]\n                 [`(- ,arg ,args ...)\n                  (append (recurse arg) (map negate-term (append-map recurse args)))]\n                 ; Prevent fall-through to the next case\n                 [`(/ ,arg) `((1 ,brf))]\n                 [`(/ ,arg ,args ...)\n                  (for/list ([term (recurse arg)])\n                    (list (car term) (reduce-node (batch-add! batch (list* '/ (cadr term) args)))))]\n                 [else `((1 ,brf))])))])\n\n    ;; Actual code\n    (define (reduce brf recurse)\n      (parameterize ([global-batch batch])\n        (define node (deref brf))\n        (match node\n          [(? number?) brf]\n          [(? symbol?) brf]\n          [`(,op ,args ...)\n           (define args* (map recurse args))\n           (define brf* (batch-add! batch (list* op args*)))\n           (define val (eval-application brf*))\n           (when val ;; convert to batchref if result is not #f\n             (set! val (batch-push! batch val)))\n           (or val (reduce-node brf*))])))\n    (batch-recurse batch reduce)))\n\n(define (reduce-evaluation brf)\n  (define batch (batchref-batch brf))\n  (define (pi-multiple expr)\n    (match expr\n      [`(PI) 1]\n      [`(* ,(app deref (? rational? coeff)) ,(app deref '(PI))) coeff]\n      [`(* ,(app deref '(PI)) ,(app deref (? rational? coeff))) coeff]\n      [`(/ ,(app deref '(PI)) ,(app deref (? rational? denom))) (/ denom)]\n      [_ #f]))\n  (define node*\n    (match (deref brf)\n      [(list 'sin (app deref 0)) 0]\n      [(list 'cos (app deref 0)) 1]\n      [(list 'sin (app deref (app pi-multiple 1))) 0]\n      [(list 'cos (app deref (app pi-multiple 1))) -1]\n      [(list 'exp (app deref 1)) '(E)]\n      [(list 'tan (app deref 0)) 0]\n      [(list 'sinh (app deref 0)) 0]\n      [(list 'log (app deref (list 'E))) 1]\n      [(list 'exp (app deref 0)) 1]\n      [(list 'tan (app deref (app pi-multiple 1))) 0]\n      [(list 'cosh (app deref 0)) 1]\n      [(list 'cos (app deref (app pi-multiple 1/6))) '(/ (sqrt 3) 2)]\n      [(list 'tan (app deref (app pi-multiple 1/3))) '(sqrt 3)]\n      [(list 'tan (app deref (app pi-multiple 1/4))) 1]\n      [(list 'cos (app deref (app pi-multiple 1/2))) 0]\n      [(list 'tan (app deref (app pi-multiple 1/6))) '(/ 1 (sqrt 3))]\n      [(list 'sin (app deref (app pi-multiple 1/3))) '(/ (sqrt 3) 2)]\n      [(list 'sin (app deref (app pi-multiple 1/6))) 1/2]\n      [(list 'sin (app deref (app pi-multiple 1/4))) '(/ (sqrt 2) 2)]\n      [(list 'sin (app deref (app pi-multiple 1/2))) 1]\n      [(list 'cos (app deref (app pi-multiple 1/3))) 1/2]\n      [(list 'cos (app deref (app pi-multiple 1/4))) '(/ (sqrt 2) 2)]\n      [node node]))\n  (batch-add! batch node*))\n\n(define (reduce-inverses brf)\n  (match (deref brf)\n    [(list 'tanh (app deref (list 'atanh x))) x]\n    [(list 'cosh (app deref (list 'acosh x))) x]\n    [(list 'sinh (app deref (list 'asinh x))) x]\n    [(list 'acos (app deref (list 'cos x))) x]\n    [(list 'asin (app deref (list 'sin x))) x]\n    [(list 'atan (app deref (list 'tan x))) x]\n    [(list 'tan (app deref (list 'atan x))) x]\n    [(list 'cos (app deref (list 'acos x))) x]\n    [(list 'sin (app deref (list 'asin x))) x]\n    [(list 'pow x (app deref 1)) x]\n    [(list 'log (app deref (list 'exp x))) x]\n    [(list 'exp (app deref (list 'log x))) x]\n    [(list 'cbrt (app deref (list 'pow x (app deref 3)))) x]\n    [(list 'pow (app deref (list 'cbrt x)) (app deref 3)) x]\n    [_ brf]))\n\n(define (negate-term term)\n  (cons (- (car term)) (cdr term)))\n\n(define (even-denominator? x)\n  (even? (denominator x)))\n\n(define (batch-gather-multiplicative-terms batch eval-application)\n  (define (nan-term)\n    `(+nan.0 . ((1 . ,(batch-push! batch 1)))))\n  (define (gather-multiplicative-terms brf recurse)\n    (match (deref brf)\n      [+nan.0 (nan-term)]\n      [(? number? n) (list n)]\n      [(? symbol?) `(1 . ((1 . ,brf)))]\n      [`(neg ,arg)\n       (define terms (recurse arg))\n       (if (eq? (car terms) +nan.0)\n           (nan-term)\n           (negate-term terms))]\n      [`(* ,args ...)\n       (define terms (map recurse args))\n       (if (ormap (curry eq? +nan.0) (map car terms))\n           (nan-term)\n           (cons (apply * (map car terms)) (append-map cdr terms)))]\n      [`(/ ,arg)\n       (define term (recurse arg))\n       (if (member (car term) '(0 +nan.0))\n           (nan-term)\n           (cons (/ (car term)) (map negate-term (cdr term))))]\n      [`(/ ,arg ,args ...)\n       (define num (recurse arg))\n       (define dens (map recurse args))\n       (if (or (eq? (car num) +nan.0) (ormap (compose (curryr member '(0 +nan.0)) car) dens))\n           (nan-term)\n           (cons (apply / (car num) (map car dens))\n                 (append (cdr num) (map negate-term (append-map cdr dens)))))]\n      [`(cbrt ,arg)\n       (define terms (recurse arg))\n       (cond\n         [(equal? (car terms) +nan.0) (nan-term)]\n         [else\n          (define exact-cbrt (eval-application (batch-add! batch (list 'cbrt (car terms)))))\n          (if exact-cbrt\n              (cons exact-cbrt\n                    (for/list ([term (cdr terms)])\n                      (cons (/ (car term) 3) (cdr term))))\n              (list* 1\n                     (cons 1 (batch-add! batch `(cbrt ,(car terms))))\n                     (for/list ([term (cdr terms)])\n                       (cons (/ (car term) 3) (cdr term)))))])]\n      [`(pow ,arg ,(app deref 0))\n       (define terms (recurse arg))\n       (if (equal? (car terms) +nan.0)\n           (nan-term)\n           `(1 . ()))]\n      [`(pow ,arg ,(app deref (? (conjoin rational? (negate even-denominator?)) a)))\n       (define terms (recurse arg))\n       (define exact-pow\n         (match (car terms)\n           [+nan.0 +nan.0]\n           [x (eval-application (batch-add! batch (list 'pow x a)))]))\n       (if exact-pow\n           (cons exact-pow\n                 (for/list ([term (cdr terms)])\n                   (cons (* a (car term)) (cdr term))))\n           (list* 1\n                  (cons a (batch-push! batch (car terms)))\n                  (for/list ([term (cdr terms)])\n                    (cons (* a (car term)) (cdr term)))))]\n      [_ `(1 . ((1 . ,brf)))]))\n  (batch-recurse batch gather-multiplicative-terms))\n\n(define (combine-aterms terms)\n  (define h (make-hash))\n  (for ([term terms])\n    (hash-update! h (cadr term) (λ (sum) (+ (car term) sum)) 0))\n  (sort (reap [sow]\n              (for ([(k v) (in-hash h)]\n                    #:when (not (= v 0)))\n                (sow (cons v k))))\n        expr<?\n        #:key cdr))\n\n(define (combine-mterms terms)\n  (cons (car terms)\n        (let ([h (make-hash)])\n          (for ([term (cdr terms)])\n            (hash-update! h (cdr term) (λ (sum) (+ (car term) sum)) 0))\n          (sort (reap [sow]\n                      (for ([(k v) (in-hash h)]\n                            #:unless (= v 0))\n                        (sow (cons v k))))\n                expr<?\n                #:key cdr))))\n\n(define (aterm->expr term)\n  (match term\n    [`(1 . ,x) x]\n    [`(,x . ,(app deref 1)) (batch-push! (global-batch) x)]\n    [`(-1 . ,x) (batch-add! (global-batch) `(neg ,x))]\n    [`(,coeff . ,x) (batch-add! (global-batch) `(* ,coeff ,x))]))\n\n(define (make-addition-node terms)\n  (define-values (pos neg) (partition (λ (x) (and (real? (car x)) (positive? (car x)))) terms))\n  (cond\n    [(and (null? pos) (null? neg)) (batch-push! (global-batch) 0)]\n    [(null? pos) (batch-add! (global-batch) `(neg ,(make-addition-node* (map negate-term neg))))]\n    [(null? neg) (make-addition-node* pos)]\n    [else\n     (batch-add! (global-batch)\n                 `(- ,(make-addition-node* pos) ,(make-addition-node* (map negate-term neg))))]))\n\n(define (make-addition-node* terms)\n  (match terms\n    ['() (batch-push! (global-batch) 0)]\n    [`(,term) (aterm->expr term)]\n    [`(,term ,terms ...)\n     (batch-add! (global-batch) `(+ ,(aterm->expr term) ,(make-addition-node terms)))]))\n\n(define (make-multiplication-node term)\n  (match (cons (car term) (make-multiplication-subnode (cdr term)))\n    [(cons +nan.0 e) (batch-push! (global-batch) '(NAN))]\n    [(cons 0 e) (batch-push! (global-batch) 0)]\n    [(cons 1 '()) (batch-push! (global-batch) 1)]\n    [(cons 1 e) e]\n    [(cons a (app deref 1)) (batch-push! (global-batch) a)]\n    [(cons a (app deref (list '/ (app deref 1) denom))) (batch-add! (global-batch) `(/ ,a ,denom))]\n    [(cons a '()) (batch-push! (global-batch) a)]\n    [(cons a e) (batch-add! (global-batch) `(* ,a ,e))]))\n\n(define (make-multiplication-subnode terms)\n  (make-multiplication-subsubsubnode\n   (list (cons 1 (mterm->expr (cons 1 (make-multiplication-subsubnode terms)))))))\n\n(define (make-multiplication-subsubnode terms)\n  (define-values (pos neg) (partition (compose positive? car) terms))\n  (cond\n    [(and (null? pos) (null? neg)) (batch-push! (global-batch) 1)]\n    [(null? pos)\n     (batch-add! (global-batch) `(/ 1 ,(make-multiplication-subsubsubnode (map negate-term neg))))]\n    [(null? neg) (make-multiplication-subsubsubnode pos)]\n    [else\n     (batch-add! (global-batch)\n                 `(/ ,(make-multiplication-subsubsubnode pos)\n                     ,(make-multiplication-subsubsubnode (map negate-term neg))))]))\n\n(define (make-multiplication-subsubsubnode terms)\n  (match terms\n    ['() (batch-push! (global-batch) 1)]\n    [`(,term) (mterm->expr term)]\n    [`(,term ,terms ...)\n     (batch-add! (global-batch)\n                 `(* ,(mterm->expr term) ,(make-multiplication-subsubsubnode terms)))]))\n\n(define (mterm->expr term)\n  (match term\n    [(cons 1 x) x]\n    [(cons -1 x) (batch-add! (global-batch) `(/ 1 ,x))]\n    [(cons 1/2 x) (batch-add! (global-batch) `(sqrt ,x))]\n    [(cons -1/2 x) (batch-add! (global-batch) `(/ 1 (sqrt ,x)))]\n    [(cons 1/3 x) (batch-add! (global-batch) `(cbrt ,x))]\n    [(cons -1/3 x) (batch-add! (global-batch) `(/ 1 (cbrt ,x)))]\n    [(cons power x) (batch-add! (global-batch) `(pow ,x ,power))]))\n\n(module+ test\n  (require rackunit)\n  (define batch (batch-empty))\n  (define evaluator (batch-eval-application batch))\n  (define (evaluator-results expr)\n    (evaluator (batch-add! batch expr)))\n\n  ;; Checks for batch-eval-application\n  (check-equal? (evaluator-results '(+ 1 1)) 2)\n  (check-equal? (evaluator-results '(+)) 0)\n  (check-equal? (evaluator-results '(/ 1 0)) #f) ; Not valid\n  (check-equal? (evaluator-results '(cbrt 1)) 1)\n  (check-equal? (evaluator-results '(log 1)) 0)\n  (check-equal? (evaluator-results '(exp 2)) #f) ; Not exact\n\n  ;; Checks for batch-reduce-evaluation\n  (define (reducer-results expr)\n    ((batch-exprs batch) (reduce-evaluation (batch-add! batch expr))))\n  (check-equal? (reducer-results '(cos (/ (PI) 6))) '(/ (sqrt 3) 2))\n  (check-equal? (reducer-results '(sin (/ (PI) 4))) '(/ (sqrt 2) 2))\n  (check-equal? (reducer-results '(cos (PI))) -1)\n  (check-equal? (reducer-results '(exp 1)) '(E))\n\n  ;; Checks for batch-reduce-inverses\n  (define (inverse-reducer-results expr)\n    ((batch-exprs batch) (reduce-inverses (batch-add! batch expr))))\n  (check-equal? (inverse-reducer-results '(cosh (acosh x))) 'x)\n  (check-equal? (inverse-reducer-results '(tanh (atanh x))) 'x)\n  (check-equal? (inverse-reducer-results '(sinh (asinh x))) 'x)\n  (check-equal? (inverse-reducer-results '(acos (cos x))) 'x)\n  (check-equal? (inverse-reducer-results '(asin (sin x))) 'x)\n  (check-equal? (inverse-reducer-results '(asin (sin x))) 'x)\n  (check-equal? (inverse-reducer-results '(atan (tan x))) 'x)\n  (check-equal? (inverse-reducer-results '(tan (atan x))) 'x)\n  (check-equal? (inverse-reducer-results '(cos (acos x))) 'x)\n  (check-equal? (inverse-reducer-results '(sin (asin x))) 'x)\n  (check-equal? (inverse-reducer-results '(pow x 1)) 'x)\n  (check-equal? (inverse-reducer-results '(log (exp x))) 'x)\n  (check-equal? (inverse-reducer-results '(exp (log x))) 'x)\n  (check-equal? (inverse-reducer-results '(cbrt (pow x 3))) 'x)\n  (check-equal? (inverse-reducer-results '(pow (cbrt x) 3)) 'x)\n\n  ;; Checks for batch-reduce\n  (define reduce (batch-reduce batch))\n  (define (reduce-results expr)\n    ((batch-exprs batch) (reduce (batch-add! batch expr))))\n  (check-equal? '(- (pow (+ 1 x) 2) 1) (reduce-results '(- (* (+ x 1) (+ x 1)) 1)))\n  (check-equal? '(neg (* 2 (/ 1 x))) (reduce-results '(+ (/ 1 (neg x)) (/ 1 (neg x)))))\n  (check-equal? '(- (pow (- 1 (/ 1 x)) 2) 1)\n                (reduce-results '(- (* (+ (/ 1 (neg x)) 1) (+ (/ 1 (neg x)) 1)) 1)))\n  (check-equal? '(pow (- 1 (/ 1 x)) 2) (reduce-results '(* (+ (/ 1 (neg x)) 1) (+ (/ 1 (neg x)) 1))))\n  (check-equal? '(+ (* 2 (/ 1 x)) (/ 1 (pow x 2)))\n                (reduce-results '(+ (* (/ 1 x) (/ 1 x)) (+ (/ 1 x) (/ 1 x)))))\n  (check-equal? '(+ (* 2 (/ 1 x)) (/ 1 (pow x 2)))\n                (reduce-results '(+ (* (/ 1 x) (/ 1 x)) (+ (/ 1 x) (/ 1 x)))))\n  (check-equal? '(/ 1 (* (cbrt 2) (cbrt a))) (reduce-results '(pow (+ a a) -1/3))))\n"
  },
  {
    "path": "src/core/bsearch.rkt",
    "content": "#lang racket\n\n(require math/bigfloat\n         racket/random)\n(require \"../config.rkt\"\n         \"../core/alternative.rkt\"\n         \"../utils/common.rkt\"\n         \"../utils/timeline.rkt\"\n         \"../utils/errors.rkt\"\n         \"../syntax/float.rkt\"\n         \"../utils/pretty-print.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/syntax.rkt\"\n         \"../syntax/platform.rkt\"\n         \"../syntax/batch.rkt\"\n         \"compiler.rkt\"\n         \"regimes.rkt\"\n         \"../syntax/rival.rkt\"\n         \"sampling.rkt\"\n         \"points.rkt\"\n         \"programs.rkt\")\n\n(provide combine-alts\n         combine-alts/binary\n         regimes-pcontext-masks)\n\n(module+ test\n  (require rackunit))\n\n(define (finish-combine-alts batch alts brf splitindices splitpoints ctx)\n  (define splitpoints* (append splitpoints (list (sp (si-cidx (last splitindices)) brf +nan.0))))\n  (define reprs (batch-reprs batch ctx))\n  (define brf*\n    (for/fold ([brf (alt-expr (list-ref alts (sp-cidx (last splitpoints*))))])\n              ([splitpoint (cdr (reverse splitpoints*))])\n      (define repr (reprs (sp-bexpr splitpoint)))\n      (define if-impl (get-fpcore-impl 'if '() (list (get-representation 'bool) repr repr)))\n      (define <=-impl (get-fpcore-impl '<= '() (list repr repr)))\n      (define lit-brf\n        (batch-add! batch\n                    (literal (repr->real (sp-point splitpoint) repr) (representation-name repr))))\n      (define cmp-brf (batch-add! batch `(,<=-impl ,(sp-bexpr splitpoint) ,lit-brf)))\n      (batch-add! batch `(,if-impl ,cmp-brf ,(alt-expr (list-ref alts (sp-cidx splitpoint))) ,brf))))\n\n  ;; We don't want unused alts in our history!\n  (define-values (alts* splitpoints**) (remove-unused-alts alts splitpoints*))\n  (alt brf* (list 'regimes splitpoints**) alts*))\n\n(define (combine-alts batch best-option ctx)\n  (match-define (option splitindices alts pts brf) best-option)\n  (define splitpoints (sindices->spoints/left batch pts brf splitindices ctx))\n  (finish-combine-alts batch alts brf splitindices splitpoints ctx))\n\n(define (combine-alts/binary batch best-option start-prog ctx pcontext)\n  (match-define (option splitindices alts pts brf) best-option)\n  (define splitpoints\n    (sindices->spoints/binary batch pts brf alts splitindices start-prog ctx pcontext))\n  (finish-combine-alts batch alts brf splitindices splitpoints ctx))\n\n(define (remove-unused-alts alts splitpoints)\n  (for/fold ([alts* '()]\n             [splitpoints* '()])\n            ([splitpoint splitpoints])\n    (define alt (list-ref alts (sp-cidx splitpoint)))\n    ;; It's important to snoc the alt in order for the indices not to change\n    (define alts** (remove-duplicates (append alts* (list alt))))\n    (define splitpoint* (struct-copy sp splitpoint [cidx (index-of alts** alt)]))\n    (define splitpoints** (append splitpoints* (list splitpoint*)))\n    (values alts** splitpoints**)))\n\n;; Invariant: (pred p1) and (not (pred p2))\n(define (binary-search-floats pred p1 p2 repr ulps)\n  (cond\n    [(<= (ulps->bits (ulps p1 p2)) (*binary-search-accuracy*))\n     (timeline-push! 'stop \"narrow-enough\" 1)\n     (values p1 p2)]\n    [else\n     (define p3 (midpoint p1 p2 repr))\n     (define cmp\n       ;; Sampling error: don't know who's better\n       (with-handlers ([exn:fail:user:herbie:sampling? (const 'fail)])\n         (pred p3)))\n\n     (cond\n       [(eq? cmp 'fail)\n        (timeline-push! 'stop \"predicate-failed\" 1)\n        (values p1 p2)]\n       [(negative? cmp) (binary-search-floats pred p3 p2 repr ulps)]\n       [(positive? cmp) (binary-search-floats pred p1 p3 repr ulps)]\n       ;; cmp = 0 usually means sampling failed, so we give up\n       [else\n        (timeline-push! 'stop \"predicate-same\" 1)\n        (values p1 p2)])]))\n\n(define (extract-subexpression batch brf var pattern-brf ctx)\n  (define var-brf (batch-add! batch var))\n  (if (= (batchref-idx pattern-brf) (batchref-idx var-brf))\n      brf\n      (let ()\n        (define free-vars (batch-free-vars batch))\n        (define body-brf (batch-replace-subexpr batch brf pattern-brf var-brf))\n        (define vars* (set-subtract (list->set (context-vars ctx)) (free-vars pattern-brf)))\n        (and (subset? (free-vars body-brf) (set-add vars* var)) body-brf))))\n\n(define (deterministic-branch-var ctx)\n  (define used-vars (list->set (context-vars ctx)))\n  (let loop ([n 0])\n    (define var (string->symbol (format \"branch-~a\" n)))\n    (if (set-member? used-vars var)\n        (loop (add1 n))\n        var)))\n\n(define (prepend-argument evaluator val pcontext)\n  (define pts\n    (for/list ([(pt ex) (in-pcontext pcontext)])\n      pt))\n  ; new-sampler returns: (cons (cons val pts) hint)\n  ; Since the sampler does not call rival-analyze, the hint is set to #f\n  (define (new-sampler)\n    (values (vector-append (vector val) (random-ref pts)) #f))\n  (define-values (results _) (batch-prepare-points evaluator new-sampler))\n  (apply mk-pcontext results))\n\n(define/reset *prepend-arguement-cache* (make-hash))\n(define (cache-get-prepend v brf macro)\n  (define key (cons brf v))\n  (hash-ref! (*prepend-arguement-cache*) key (lambda () (macro v))))\n\n;; Accepts a list of sindices in one indexed form and returns the\n;; proper interior splitpoints in float form. A crucial constraint is that the\n;; float form always come from the range [f(idx1), f(idx2)). If the\n;; float form of a split is f(idx2), or entirely outside that range,\n;; problems may arise.\n(define/contract (sindices->spoints/left batch points brf sindices ctx)\n  (-> batch? (listof vector?) batchref? (listof si?) context? (listof sp?))\n  (define repr ((batch-reprs batch ctx) brf))\n  (define eval-expr (compose (curryr vector-ref 0) (compile-batch batch (list brf) ctx)))\n\n  (define (left-point p1 p2)\n    (define left ((representation-repr->bf repr) p1))\n    (define right ((representation-repr->bf repr) p2))\n    (define out ; TODO: Try using bigfloat-pick-point here?\n      (if (bfnegative? left)\n          (bigfloat-interval-shortest left (bfmin (bf/ left 2.bf) right))\n          (bigfloat-interval-shortest left (bfmin (bf* left 2.bf) right))))\n    ;; It's important to return something strictly less than right\n    (if (bf= out right)\n        p1\n        ((representation-bf->repr repr) out)))\n\n  (for/list ([si1 sindices]\n             [si2 (cdr sindices)])\n    (define p1 (eval-expr (list-ref points (sub1 (si-pidx si1)))))\n    (define p2 (eval-expr (list-ref points (si-pidx si1))))\n\n    (define timeline-stop! (timeline-start! 'bstep (value->json p1 repr) (value->json p2 repr)))\n    (define split-at (left-point p1 p2))\n    (timeline-stop!)\n\n    (timeline-push! 'method \"left-value\")\n    (sp (si-cidx si1) brf split-at)))\n\n(define/contract (sindices->spoints/binary batch points brf alts sindices start-prog ctx pcontext)\n  (-> batch?\n      (listof vector?)\n      batchref?\n      (listof alt?)\n      (listof si?)\n      any/c\n      context?\n      pcontext?\n      (listof sp?))\n  (define repr ((batch-reprs batch ctx) brf))\n  (define ulps (repr-ulps repr))\n  (define eval-expr (compose (curryr vector-ref 0) (compile-batch batch (list brf) ctx)))\n  (define brf-node (deref brf))\n  (define var\n    (if (symbol? brf-node)\n        brf-node\n        (deterministic-branch-var ctx)))\n  (define ctx* (context-extend ctx var repr))\n  (define progs\n    (for/list ([alt (in-list alts)])\n      (extract-subexpression batch (alt-expr alt) var brf ctx)))\n  (define start-prog-sub (extract-subexpression batch start-prog var brf ctx))\n  (unless (and start-prog-sub (andmap identity progs))\n    (raise-user-error\n     'sindices->spoints/binary\n     \"mainloop called binary splitpoint search without extractable critical subexpressions\"))\n  (define spec-brfs (batch-to-spec! batch (list start-prog)))\n  (define start-real-compiler (make-real-compiler batch spec-brfs (list ctx*)))\n\n  (define (prepend-macro v)\n    (prepend-argument start-real-compiler v pcontext))\n\n  (define (find-split si1 si2 p1 p2)\n    (define brf1 (list-ref progs (si-cidx si1)))\n    (define brf2 (list-ref progs (si-cidx si2)))\n    (define eval-errors (compile-batch batch (list brf1 brf2) ctx*))\n    (define score-ulps (repr-ulps (context-repr ctx*)))\n    (define (pred v)\n      (define pctx\n        (parameterize ([*num-points* (*binary-search-test-points*)])\n          (cache-get-prepend v brf prepend-macro)))\n      (for/sum ([(pt ex) (in-pcontext pctx)])\n               (match-define (vector out1 out2) (eval-errors pt))\n               (- (ulps->bits (score-ulps out1 ex)) (ulps->bits (score-ulps out2 ex)))))\n    (define-values (bp1 _) (binary-search-floats pred p1 p2 repr ulps))\n    bp1)\n\n  (for/list ([si1 sindices]\n             [si2 (cdr sindices)])\n    (define p1 (eval-expr (list-ref points (sub1 (si-pidx si1)))))\n    (define p2 (eval-expr (list-ref points (si-pidx si1))))\n\n    (define timeline-stop! (timeline-start! 'bstep (value->json p1 repr) (value->json p2 repr)))\n    (define split-at (find-split si1 si2 p1 p2))\n    (timeline-stop!)\n\n    (timeline-push! 'method \"binary-search\")\n    (sp (si-cidx si1) brf split-at)))\n\n(define (regimes-pcontext-masks pcontext splitpoints alts ctx)\n  (define num-alts (length alts))\n  (define num-points (pcontext-length pcontext))\n  (define bexpr (sp-bexpr (car splitpoints)))\n  (define ctx* (struct-copy context ctx [repr (repr-of bexpr ctx)]))\n  (define prog (compile-prog bexpr ctx*))\n  (define masks (build-vector num-alts (λ (_) (make-vector num-points #f))))\n  (for ([(pt _) (in-pcontext pcontext)]\n        [idx (in-naturals)])\n    (define val (prog pt))\n    (for/first ([right (in-list splitpoints)]\n                #:when (or (equal? (sp-point right) +nan.0)\n                           (<=/total val (sp-point right) (context-repr ctx*))))\n      (vector-set! (vector-ref masks (sp-cidx right)) idx #t)))\n  masks)\n"
  },
  {
    "path": "src/core/compiler.rkt",
    "content": "#lang racket\n\n(require \"../syntax/syntax.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/platform.rkt\"\n         \"../syntax/float.rkt\"\n         \"../utils/timeline.rkt\"\n         \"../syntax/batch.rkt\")\n\n(provide compile-progs\n         compile-batch\n         compile-prog)\n\n;; Interpreter taking a narrow IR\n;; ```\n;; <prog> ::= #(<thunk> ..+)\n;; ```\n;; Must also provide the input variables for the program(s)\n;; as well as the indices of the roots to extract.\n(define (make-progs-interpreter tvec rootvec args vregs)\n  (define rootlen (vector-length rootvec))\n  (define vregs-len (vector-length tvec))\n  (define (compiled-prog args*)\n    (vector-copy! args 0 args*)\n    (for ([thunk (in-vector tvec)]\n          [n (in-range vregs-len)])\n      (vector-set! vregs n (thunk)))\n    (for/vector #:length rootlen\n                ([root (in-vector rootvec)])\n      (vector-ref vregs root)))\n  compiled-prog)\n\n(define (make-thunk op argidxs regs)\n  (match argidxs\n    ['() op]\n    [(list a) (λ () (op (vector-ref regs a)))]\n    [(list a b) (λ () (op (vector-ref regs a) (vector-ref regs b)))]\n    [(list a b c) (λ () (op (vector-ref regs a) (vector-ref regs b) (vector-ref regs c)))]\n    [(list args ...)\n     (define argc (length args))\n     (define argv (list->vector args))\n     (λ ()\n       (apply op\n              (for/list ([arg (in-vector argv)])\n                (vector-ref regs arg))))]))\n\n;; This function:\n;;   1) copies only nodes associated with provided brfs - so, gets rid of useless nodes\n;;   2) rewrites these nodes as fl-instructions\n(define (batch-for-compiler batch brfs vars args vregs)\n  (define out (batch-empty))\n  (define f\n    (batch-recurse batch\n                   (λ (brf recurse)\n                     (match (deref brf)\n                       [(approx _ impl) (recurse impl)] ;; do not push, it is already a batchref\n                       [(? symbol? n)\n                        (define idx (index-of vars n))\n                        (batch-push! out (make-thunk (λ () (vector-ref args idx)) '() vregs))]\n                       [(literal value (app get-representation repr))\n                        (batch-push! out (make-thunk (const (real->repr value repr)) '() vregs))]\n                       [(list op args ...)\n                        (batch-push! out\n                                     (make-thunk (impl-info op 'fl)\n                                                 (map (compose batchref-idx recurse) args)\n                                                 vregs))]))))\n  (values out (map f brfs)))\n\n;; Compiles a program of operator implementations into a procedure\n;; that evaluates the program on a single input of representation values\n;; returning representation values.\n;; Translates a Herbie IR into an interpretable IR.\n;; Requires some hooks to complete the translation.\n(define (compile-progs exprs ctx)\n  (define vars (context-vars ctx))\n  (define-values (batch brfs) (progs->batch exprs #:vars vars))\n  (compile-batch batch brfs ctx))\n\n(define (compile-batch batch brfs ctx)\n  (define vars (context-vars ctx))\n  (define args (make-vector (length vars)))\n  (define vregs (make-vector (batch-length batch)))\n  (define-values (batch* brfs*) (batch-for-compiler batch brfs vars args vregs))\n  (define thunks (batch-get-nodes batch*))\n  (define rootvec (list->vector (map batchref-idx brfs*)))\n\n  (timeline-push! 'compiler (batch-tree-size batch* brfs*) (batch-length batch*))\n\n  (make-progs-interpreter thunks rootvec args vregs))\n\n;; Like `compile-progs`, but a single prog.\n(define (compile-prog expr ctx)\n  (define core (compile-progs (list expr) ctx))\n  (define (compiled-prog . xs)\n    (vector-ref (apply core xs) 0))\n  compiled-prog)\n"
  },
  {
    "path": "src/core/derivations.rkt",
    "content": "#lang racket\n\n(require \"../core/alternative.rkt\"\n         \"../syntax/batch.rkt\"\n         \"programs.rkt\"\n         \"egg-herbie.rkt\"\n         \"../config.rkt\")\n\n(provide add-derivations)\n\n(define (canonicalize-proof batch prog-brf proof start-brf)\n  ;; Proofs are on subexpressions; lift to full expression\n  ;; Returns a list of batchrefs instead of expressions\n  (and proof\n       (for/list ([step (in-list proof)])\n         (define step-brf (batch-add! batch step))\n         (batch-replace-subexpr batch prog-brf start-brf step-brf))))\n\n;; Adds proof information to alternatives.\n;; start-expr and end-expr are batchrefs\n(define (add-derivations-to altn)\n  (match altn\n    ; recursive rewrite or simplify, both using egg\n    ; start-brf and end-brf are batchrefs for the subexpressions that were transformed\n    [(alt expr (list 'rr start-brf end-brf (? egg-runner? runner) #f) `(,prev))\n     (define batch (egg-runner-batch runner))\n     (define proof (and (not (flag-set? 'generate 'egglog)) (egraph-prove runner start-brf end-brf)))\n     (define proof* (canonicalize-proof batch (alt-expr altn) proof start-brf))\n     (alt expr `(rr ,start-brf ,end-brf ,runner ,proof*) (list prev))]\n\n    ; everything else\n    [_ altn]))\n\n(define (add-derivations alts)\n  (define cache (make-hash))\n  (for/list ([altn (in-list alts)])\n    ;; We need to cache this because we'll see the same alt several times\n    (alt-map (lambda (altn) (hash-ref! cache altn (lambda () (add-derivations-to altn)))) altn)))\n"
  },
  {
    "path": "src/core/egg-herbie.rkt",
    "content": "#lang racket\n\n(require egg-herbie\n         (only-in ffi/vector\n                  make-u32vector\n                  u32vector-length\n                  u32vector-set!\n                  u32vector-ref\n                  list->u32vector\n                  u32vector->list)\n         json) ; for dumping\n\n(require \"../utils/common.rkt\"\n         \"../utils/errors.rkt\"\n         \"../utils/timeline.rkt\"\n         \"../syntax/platform.rkt\"\n         \"../syntax/syntax.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/batch.rkt\"\n         \"programs.rkt\"\n         \"rules.rkt\")\n\n(provide (struct-out egg-runner)\n         make-egraph\n         egraph-equal?\n         egraph-prove\n         egraph-best\n         egraph-variations\n         egraph-analyze-rewrite-impact)\n\n(module+ test\n  (require rackunit))\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; FFI utils\n\n(define (u32vector-empty? x)\n  (zero? (u32vector-length x)))\n\n(define (in-u32vector vec)\n  (make-do-sequence\n   (lambda ()\n     (define len (u32vector-length vec))\n     (values (lambda (i) (u32vector-ref vec i)) add1 0 (lambda (i) (< i len)) #f #f))))\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; egg FFI shim\n;;\n;; egg-herbie requires a bit of nice wrapping\n;; - FFIRule: struct defined in egg-herbie\n;; - EgraphIter: struct defined in egg-herbie\n\n; Adds expressions returning the root ids\n(define (egraph-add-exprs ptr batch brfs ctx)\n\n  ; pre-allocated id vectors for all the common cases\n  (define 0-vec (make-u32vector 0))\n  (define 1-vec (make-u32vector 1))\n  (define 2-vec (make-u32vector 2))\n  (define 3-vec (make-u32vector 3))\n\n  (define (list->u32vec xs)\n    (match xs\n      [(list) 0-vec]\n      [(list x)\n       (u32vector-set! 1-vec 0 x)\n       1-vec]\n      [(list x y)\n       (u32vector-set! 2-vec 0 x)\n       (u32vector-set! 2-vec 1 y)\n       2-vec]\n      [(list x y z)\n       (u32vector-set! 3-vec 0 x)\n       (u32vector-set! 3-vec 1 y)\n       (u32vector-set! 3-vec 2 z)\n       3-vec]\n      [_ (list->u32vector xs)]))\n\n  ; node -> natural\n  ; inserts an expression into the e-graph, returning its e-class id.\n\n  (define (insert-node! node)\n    (match node\n      [(list op ids ...) (egraph_add_node ptr (~s op) (list->u32vec ids))]\n      [(? (disjoin symbol? number?) x) (egraph_add_node ptr (~s x) 0-vec)]))\n\n  (define reprs (batch-reprs batch ctx))\n  (define add-to-egraph\n    (batch-recurse\n     batch\n     (λ (brf recurse)\n       (define node (deref brf))\n       (match node\n         [(literal v _) (insert-node! v)]\n         [(? number?) (insert-node! node)]\n         [(? symbol?) (insert-node! (var->egg-var node ctx))]\n         [(hole prec spec) (recurse spec)] ; \"hole\" terms currently disappear\n         [(approx spec impl) (insert-node! (list '$approx (recurse spec) (recurse impl)))]\n         [(list op (app recurse args) ...) (insert-node! (cons op args))]))))\n\n  (for/list ([brf (in-list brfs)])\n    (define brf-id (add-to-egraph brf)) ; remapping of brf\n    (egraph_add_root ptr brf-id)\n    brf-id))\n\n;; runs rules on an egraph (optional iteration limit)\n(define (egraph-run ptr ffi-rules node-limit iter-limit scheduler)\n  (define u32_max 4294967295) ; since we can't send option types\n  (define node_limit (if node-limit node-limit u32_max))\n  (define iter_limit (if iter-limit iter-limit u32_max))\n  (define simple_scheduler?\n    (match scheduler\n      ['backoff #f]\n      ['simple #t]\n      [_ (error 'egraph-run \"unknown scheduler: `~a`\" scheduler)]))\n  (egraph_run ptr ffi-rules iter_limit node_limit simple_scheduler?))\n\n(define (egraph-get-simplest ptr node-id iteration ctx)\n  (define expr (egraph_get_simplest ptr node-id iteration))\n  (egg-expr->expr expr ctx))\n\n(define (egraph-get-variants ptr node-id orig-expr ctx)\n  (define egg-expr (expr->egg-expr orig-expr ctx))\n  (define exprs (egraph_get_variants ptr node-id egg-expr))\n  (for/list ([expr (in-list exprs)])\n    (egg-expr->expr expr ctx)))\n\n(define empty-u32vec (make-u32vector 0))\n\n;; Extracts the nodes of an e-class as a vector\n;; where each enode is either a symbol, number, or list\n(define (egraph-get-eclass ptr id)\n  (define eclass (egraph_get_eclass ptr id))\n  ; need to fix up any constant operators\n  (for ([enode (in-vector eclass)]\n        [i (in-naturals)]\n        #:when (and (symbol? enode) (not (string-prefix? (symbol->string enode) \"$var\"))))\n    (vector-set! eclass i (cons enode empty-u32vec)))\n  eclass)\n\n(define (egraph-expr-equal? ptr expr goal ctx)\n  (define-values (batch brfs) (progs->batch (list expr goal)))\n  (match-define (list id1 id2) (egraph-add-exprs ptr batch brfs ctx))\n  (= id1 id2))\n\n;; returns a flattened list of terms or #f if it failed to expand the proof due to budget\n(define (egraph-get-proof ptr expr goal ctx)\n  (define egg-expr (expr->egg-expr expr ctx))\n  (define egg-goal (expr->egg-expr goal ctx))\n  (define str (egraph_get_proof ptr egg-expr egg-goal))\n  (cond\n    [(<= (string-length str) (*proof-max-string-length*))\n     (define converted\n       (for/list ([expr (in-port read (open-input-string str))])\n         (egg-expr->expr expr ctx)))\n     (define expanded (expand-proof converted (box (*proof-max-length*))))\n     (if (member #f expanded) #f expanded)]\n    [else #f]))\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; eggIR\n;;\n;; eggIR is an S-expr language nearly identical to Herbie's various IRs\n;; consisting of two variants:\n;;  - patterns: all variables are prefixed by '?'\n;;  - expressions: all variables are normalized into `h<n>` where <n> is an integer\n;;\n\n;; Translates a Herbie rule LHS or RHS into a pattern usable by egg.\n;; Rules can be over specs or impls.\n(define (expr->egg-pattern expr)\n  (let loop ([expr expr])\n    (match expr\n      [(? number?) expr]\n      [(? literal?) (literal-value expr)]\n      [(? symbol?) (string->symbol (format \"?~a\" expr))]\n      [(approx spec impl) (list '$approx (loop spec) (loop impl))]\n      [(list op args ...) (cons op (map loop args))])))\n\n(define (var->egg-var var ctx)\n  (define idx (index-of (context-vars ctx) var))\n  (string->symbol (format \"$var~a\" idx)))\n\n(define (egg-var->var egg-var ctx)\n  (define idx (string->number (substring (symbol->string egg-var) 4)))\n  (list-ref (context-vars ctx) idx))\n\n;; Translates a Herbie expression into an expression usable by egg.\n;; Updates translation dictionary upon encountering variables.\n;; Result is the expression.\n(define (expr->egg-expr expr ctx)\n  (let loop ([expr expr])\n    (match expr\n      [(? number?) expr]\n      [(? literal?) (literal-value expr)]\n      [(? symbol? x) (var->egg-var x ctx)]\n      [(approx spec impl) (list '$approx (loop spec) (loop impl))]\n      [(hole precision spec) (loop spec)]\n      [(list op args ...) (cons op (map loop args))])))\n\n(define (flatten-let expr)\n  (let loop ([expr expr]\n             [env (hash)])\n    (match expr\n      [(? number?) expr]\n      [(? symbol?) (hash-ref env expr expr)]\n      [`(let (,var\n              ,term)\n          ,body)\n       (loop body (hash-set env var (loop term env)))]\n      [`(,op ,args ...) (cons op (map (curryr loop env) args))])))\n\n;; Converts an S-expr from egg into one Herbie understands\n;; TODO: typing information is confusing since proofs mean\n;; we may process mixed spec/impl expressions;\n;; only need `type` to correctly interpret numbers\n(define (egg-parsed->expr expr ctx type)\n  (let loop ([expr expr]\n             [type type])\n    (match expr\n      [(? number?)\n       (if (representation? type)\n           (literal expr (representation-name type))\n           expr)]\n      [(? symbol?)\n       (if (string-prefix? (symbol->string expr) \"$var\")\n           (egg-var->var expr ctx)\n           (list expr))]\n      [(list '$approx spec impl) ; approx\n       (define spec-type\n         (if (representation? type)\n             (representation-type type)\n             type))\n       (approx (loop spec spec-type) (loop impl type))]\n      [`(Explanation ,body ...) `(Explanation ,@(map (lambda (e) (loop e type)) body))]\n      [(list 'Rewrite=> rule expr) (list 'Rewrite=> rule (loop expr type))]\n      [(list 'Rewrite<= rule expr) (list 'Rewrite<= rule (loop expr type))]\n      [(list op args ...)\n       #:when (string-prefix? (symbol->string op) \"sound-\")\n       (define op* (string->symbol (substring (symbol->string op) (string-length \"sound-\"))))\n       (define args* (drop-right args 1))\n       (cons op* (map loop args* (map (const 'real) args*)))]\n      [(list op args ...)\n       ;; Unfortunately the type parameter doesn't tell us much because mixed exprs exist\n       ;; so if we see something like (and a b) we literally don't know which \"and\" it is\n       (cons op\n             (map loop\n                  args\n                  (cond\n                    [(and (operator-exists? op) (impl-exists? op))\n                     (if (representation? type)\n                         (impl-info op 'itype)\n                         (operator-info op 'itype))]\n                    [(impl-exists? op) (impl-info op 'itype)]\n                    [(operator-exists? op) (operator-info op 'itype)])))])))\n\n;; Parses a string from egg into a single S-expr.\n(define (egg-expr->expr egg-expr ctx)\n  (egg-parsed->expr (flatten-let egg-expr) ctx (context-repr ctx)))\n\n(module+ test\n  (require \"../syntax/float.rkt\"\n           \"../syntax/load-platform.rkt\")\n  (activate-platform! (*platform-name*))\n  (define ctx (context '(x y z) <binary64> (make-list 3 <binary64>)))\n\n  (define test-exprs\n    (list (cons '(+.f64 y x) '(+.f64 $var1 $var0))\n          (cons '(+.f64 x y) '(+.f64 $var0 $var1))\n          (cons '(-.f64 #s(literal 2 binary64) (+.f64 x y)) '(-.f64 2 (+.f64 $var0 $var1)))\n          (cons '(-.f64 z (+.f64 (+.f64 y #s(literal 2 binary64)) x))\n                '(-.f64 $var2 (+.f64 (+.f64 $var1 2) $var0)))\n          (cons '(*.f64 x y) '(*.f64 $var0 $var1))\n          (cons '(+.f64 (*.f64 x y) #s(literal 2 binary64)) '(+.f64 (*.f64 $var0 $var1) 2))\n          (cons '(cos.f32 (PI.f32)) '(cos.f32 (PI.f32)))\n          (cons '(if.f64 (TRUE) x y) '(if.f64 (TRUE) $var0 $var1))))\n\n  (let ([egg-graph (egraph_create)])\n    (for ([(in expected-out) (in-dict test-exprs)])\n      (define out (expr->egg-expr in ctx))\n      (define computed-in (egg-expr->expr out ctx))\n      (check-equal? out expected-out)\n      (check-equal? computed-in in)))\n\n  (check-equal? (egg-expr->expr '(sound-sqrt $var0 $var1) ctx) '(sqrt x))\n\n  (set! ctx (context '(x a b c r) <binary64> (make-list 5 <binary64>)))\n  (define extended-expr-list\n    ; specifications\n    (list '(/ (- (exp x) (exp (neg x))) 2)\n          '(/ (+ (neg b) (sqrt (- (* b b) (* (* 3 a) c)))) (* 3 a))\n          '(/ (+ (neg b) (sqrt (- (* b b) (* (* 3 a) c)))) (* 3 a))\n          '(* r 30)\n          '(* 23/54 r)\n          '(+ 3/2 14/10)\n          ; implementations\n          `(/.f64 (-.f64 (exp.f64 x) (exp.f64 (neg.f64 x))) ,(literal 2 'binary64))\n          `(/.f64 (+.f64 (neg.f64 b)\n                         (sqrt.f64 (-.f64 (*.f64 b b) (*.f64 (*.f64 ,(literal 3 'binary64) a) c))))\n                  (*.f64 ,(literal 3 'binary64) a))\n          `(/.f64 (+.f64 (neg.f64 b)\n                         (sqrt.f64 (-.f64 (*.f64 b b) (*.f64 (*.f64 ,(literal 3 'binary64) a) c))))\n                  (*.f64 ,(literal 3 'binary64) a))\n          `(*.f64 r ,(literal 30 'binary64))\n          `(*.f64 ,(literal 23/54 'binary64) r)\n          `(+.f64 ,(literal 3/2 'binary64) ,(literal 14/10 'binary64))))\n\n  (let ([egg-graph (egraph_create)])\n    (for ([expr extended-expr-list])\n      (define egg-expr (expr->egg-expr expr ctx))\n      (check-equal? (egg-expr->expr egg-expr ctx) expr))))\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; Proofs\n;;\n;; Proofs from egg contain let expressions (not Scheme like) as\n;; well as other information about rewrites; proof extraction requires\n;; some flattening and translation\n\n(define (remove-rewrites proof)\n  (match proof\n    [`(Rewrite=> ,_ ,something) (remove-rewrites something)]\n    [`(Rewrite<= ,_ ,something) (remove-rewrites something)]\n    [(list _ ...) (map remove-rewrites proof)]\n    [_ proof]))\n\n;; Performs a product, but traverses the elements in order\n;; This is the core logic of flattening a proof given flattened proofs for each child of a node\n(define (sequential-product elements)\n  (cond\n    [(empty? elements) (list empty)]\n    [else\n     (define without-rewrites (remove-rewrites (last (first elements))))\n     (append (for/list ([head (first elements)])\n               (cons head (map first (rest elements))))\n             (for/list ([other (in-list (rest (sequential-product (rest elements))))])\n               (cons without-rewrites other)))]))\n\n;; returns a flattened list of terms\n;; The first term has no rewrite- the rest have exactly one rewrite\n(define (expand-proof-term term budget)\n  (let loop ([term term])\n    (cond\n      [(<= (unbox budget) 0) (list #f)]\n      [else\n       (match term\n         [(? symbol?) (list term)]\n         [(? literal?) (list term)]\n         [(? number?) (list term)]\n         [(approx spec impl)\n          (define children (list (loop spec) (loop impl)))\n          (cond\n            [(member (list #f) children) (list #f)]\n            [else\n             (define res (sequential-product children))\n             (set-box! budget (- (unbox budget) (length res)))\n             (map (curry apply approx) res)])]\n         [`(Explanation ,body ...) (expand-proof body budget)]\n         [(? list?)\n          (define children (map loop term))\n          (cond\n            [(member (list #f) children) (list #f)]\n            [else\n             (define res (sequential-product children))\n             (set-box! budget (- (unbox budget) (length res)))\n             res])]\n         [_ (error \"Unknown proof term ~a\" term)])])))\n\n;; Remove the front term if it doesn't have any rewrites\n(define (remove-front-term proof)\n  (if (equal? (remove-rewrites (first proof)) (first proof))\n      (rest proof)\n      proof))\n\n;; converts a let-bound tree explanation\n;; into a flattened proof for use by Herbie\n(define (expand-proof proof budget)\n  (define expanded (map (curryr expand-proof-term budget) proof))\n  ;; get rid of any unnecessary terms\n  (define contiguous (cons (first expanded) (map remove-front-term (rest expanded))))\n  ;; append together the proofs\n  (define res (apply append contiguous))\n  (set-box! budget (- (unbox budget) (length proof)))\n  (if (member #f res)\n      (list #f)\n      res))\n\n(module+ test\n  (check-equal? (sequential-product `((1 2) (3 4 5) (6))) `((1 3 6) (2 3 6) (2 4 6) (2 5 6)))\n\n  (check-equal? (expand-proof-term '(Explanation (+ x y) (+ y x)) (box 10)) '((+ x y))))\n\n;; egg rule cache: rule -> FFI-rule\n(define/reset *egg-rule-cache* (make-hasheq))\n\n;; Expand and convert the rules for egg.\n;; Uses a cache to only expand each rule once.\n(define (convert-rules rules)\n  (for/list ([ru (in-list rules)])\n    (hash-ref! (*egg-rule-cache*)\n               ru\n               (lambda ()\n                 (define input (expr->egg-pattern (rule-input ru)))\n                 (define output (expr->egg-pattern (rule-output ru)))\n                 (make-ffi-rule (rule-name ru) input output)))))\n\n;; Rules from impl to spec (fixed for a particular platform)\n(define/reset *lifting-rules* (make-hash))\n\n;; Rules from spec to impl (fixed for a particular platform)\n(define/reset *lowering-rules* (make-hash))\n\n;; Synthesizes the LHS and RHS of lifting/lowering rules.\n(define (impl->rule-parts impl)\n  (define vars (impl-info impl 'vars))\n  (define spec (impl-info impl 'spec))\n  (values vars spec (cons impl vars)))\n\n;; Synthesizes lifting rules for a platform platform.\n(define (platform-lifting-rules [pform (*active-platform*)])\n  (define impls (platform-impls pform))\n  (for/list ([impl (in-list impls)])\n    (hash-ref! (*lifting-rules*)\n               (cons impl pform)\n               (lambda ()\n                 (define name (sym-append 'lift- impl))\n                 (define-values (vars spec-expr impl-expr) (impl->rule-parts impl))\n                 (rule name impl-expr spec-expr '(lifting))))))\n\n;; Synthesizes lowering rules for a given platform.\n(define (platform-lowering-rules [pform (*active-platform*)])\n  (define impls (platform-impls pform))\n  (append* (for/list ([impl (in-list impls)])\n             (hash-ref! (*lowering-rules*)\n                        (cons impl pform)\n                        (lambda ()\n                          (define name (sym-append 'lower- impl))\n                          (define-values (vars spec-expr impl-expr) (impl->rule-parts impl))\n                          (list (rule name spec-expr impl-expr '(lowering))))))))\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; Racket egraph\n;;\n;; Racket representation of a typed egraph.\n;; Given an e-graph from egg-herbie, we can split every e-class\n;; by type ensuring that every term in an e-class has the same output type.\n;; This trick makes extraction easier.\n\n;; - eclasses: vector of enodes\n;; - types: vector-map from e-class to type/representation\n;; - leaf?: vector-map from e-class to boolean indicating if it contains a leaf node\n;; - constants: vector-map from e-class to a number or #f\n;; - parents: vector-map from e-class to its parent e-classes (as a vector)\n;; - canon: map from (Rust) e-class, type to (Racket) e-class\n;; - ctx: the standard variable context\n(struct regraph (eclasses types leaf? constants parents canon ctx))\n\n;; Returns all representatations (and their types) in the current platform.\n(define (all-reprs/types [pform (*active-platform*)])\n  (remove-duplicates (cons 'array\n                           (append-map (lambda (repr) (list repr (representation-type repr)))\n                                       (platform-reprs pform)))))\n\n;; Returns the type(s) of an enode so it can be placed in the proper e-class.\n;; Typing rules:\n;;  - numbers: every real representation (or real type)\n;;  - variables: lookup in the context\n;;  - `if`: type is every representation (or type) [can prune incorrect ones]\n;;  - `approx`: every real representation [can prune incorrect ones]\n;;  - ops/impls: its output type/representation\n;; NOTE: we can constrain \"every\" type by using the platform.\n(define (enode-type enode ctx)\n  (match enode\n    [(? number?) (cons 'real (platform-reprs (*active-platform*)))] ; number\n    [(? symbol?) ; variable\n     (define var (egg-var->var enode ctx))\n     (define repr (context-lookup ctx var))\n     (list repr (representation-type repr))]\n    [(cons f _) ; application\n     (cond\n       [(eq? f '$approx) (platform-reprs (*active-platform*))]\n       [(string-prefix? (symbol->string f) \"sound-\") (list 'real)]\n       [else\n        (filter values\n                (list (and (impl-exists? f) (impl-info f 'otype))\n                      (and (operator-exists? f) (operator-info f 'otype))))])]))\n\n;; Rebuilds an e-node using typed e-classes\n(define (rebuild-enode enode type lookup)\n  (match enode\n    [(? number?) enode] ; number\n    [(? symbol?) enode] ; variable\n    [(cons f ids) ; application\n     (cond\n       [(eq? f '$approx) ; approx node\n        (define spec (u32vector-ref ids 0))\n        (define impl (u32vector-ref ids 1))\n        (list '$approx (lookup spec (representation-type type)) (lookup impl type))]\n       [(string-prefix? (~a f) \"sound-\")\n        (define op (string->symbol (substring (symbol->string f) (string-length \"sound-\"))))\n        (list* op\n               (map (λ (x) (lookup (u32vector-ref ids x) 'real))\n                    (range (- (u32vector-length ids) 1))))]\n       [else\n        (define itypes\n          (cond\n            [(representation? type) (impl-info f 'itype)]\n            [else (operator-info f 'itype)]))\n        ; unsafe since we don't check that |itypes| = |ids|\n        ; optimize for common cases to avoid extra allocations\n        (cons\n         f\n         (match itypes\n           [(list) '()]\n           [(list t1) (list (lookup (u32vector-ref ids 0) t1))]\n           [(list t1 t2) (list (lookup (u32vector-ref ids 0) t1) (lookup (u32vector-ref ids 1) t2))]\n           [(list t1 t2 t3)\n            (list (lookup (u32vector-ref ids 0) t1)\n                  (lookup (u32vector-ref ids 1) t2)\n                  (lookup (u32vector-ref ids 2) t3))]\n           [_ (map lookup (u32vector->list ids) itypes)]))])]))\n\n;; Splits untyped eclasses into typed eclasses.\n;; Nodes are duplicated across their possible types.\n(define (split-untyped-eclasses ptr ctx)\n  (define eclass-ids (egraph_get_eclasses ptr))\n  (define max-id\n    (for/fold ([current-max 0]) ([egg-id (in-u32vector eclass-ids)])\n      (max current-max egg-id)))\n  (define egg-id->idx (make-u32vector (+ max-id 1)))\n  (for ([egg-id (in-u32vector eclass-ids)]\n        [idx (in-naturals)])\n    (u32vector-set! egg-id->idx egg-id idx))\n\n  (define types (all-reprs/types))\n  (define type->idx (make-hash))\n  (for ([type (in-list types)]\n        [idx (in-naturals)])\n    (hash-set! type->idx type idx))\n  (define num-types (hash-count type->idx))\n\n  ; maps (idx, type) to type eclass id\n  (define (idx+type->id idx type)\n    (+ (* idx num-types) (hash-ref type->idx type)))\n\n  ; maps (untyped eclass id, type) to typed eclass id\n  (define (lookup-id eid type)\n    (idx+type->id (u32vector-ref egg-id->idx eid) type))\n\n  ; allocate enough eclasses for every (egg-id, type) combination\n  (define n (* (u32vector-length eclass-ids) num-types))\n  (define id->eclass (make-vector n '()))\n  (define id->parents (make-vector n '()))\n  (define id->leaf? (make-vector n #f))\n\n  ; for each eclass, extract the enodes\n  ;  <enode> ::= <symbol>\n  ;            | <number>\n  ;            | (<symbol> . <u32vector>)\n  ; NOTE: nodes in typed eclasses are reversed relative\n  ; to their position in untyped eclasses\n  (for ([eid (in-u32vector eclass-ids)]\n        [idx (in-naturals)])\n    (define enodes (egraph-get-eclass ptr eid))\n    (for ([enode (in-vector enodes)])\n      ; get all possible types for the enode\n      ; lookup its correct eclass and add the rebuilt node\n      (define types (enode-type enode ctx))\n      (for ([type (in-list types)])\n        (define id (idx+type->id idx type))\n        (define enode* (rebuild-enode enode type lookup-id))\n        (vector-set! id->eclass id (cons enode* (vector-ref id->eclass id)))\n        (match enode*\n          [(list _ ids ...)\n           #:when (null? ids)\n           (vector-set! id->leaf? id #t)]\n          [(list _ ids ...)\n           (for ([child-id (in-list ids)])\n             (vector-set! id->parents child-id (cons id (vector-ref id->parents child-id))))]\n          [(? symbol?) (vector-set! id->leaf? id #t)]\n          [(? number?) (vector-set! id->leaf? id #t)]))))\n\n  ; dedup `id->parents` values\n  (for ([id (in-range n)])\n    (vector-set! id->parents id (list->vector (remove-duplicates (vector-ref id->parents id)))))\n  (values id->eclass id->parents id->leaf? eclass-ids egg-id->idx type->idx))\n\n;; TODO: reachable from roots?\n;; Prunes e-nodes that are not well-typed.\n;; An e-class is well-typed if it has one well-typed node\n;; A node is well-typed if all of its child e-classes are well-typed.\n(define (prune-ill-typed! id->eclass id->parents id->leaf?)\n  (define n (vector-length id->eclass))\n\n  ;; is the e-class well-typed?\n  (define typed?-vec (make-vector n #f))\n  (define (eclass-well-typed? id)\n    (vector-ref typed?-vec id))\n\n  ;; is the e-node well-typed?\n  (define (enode-typed? enode)\n    (or (number? enode) (symbol? enode) (and (list? enode) (andmap eclass-well-typed? (cdr enode)))))\n\n  ; mark all well-typed e-classes and prune nodes that are not well-typed\n  (define (check-typed! dirty?-vec)\n    (define rerun? #f)\n    (for ([id (in-range n)]\n          [dirty? (in-vector dirty?-vec)]\n          [typed? (in-vector typed?-vec)]\n          [eclass (in-vector id->eclass)]\n          [parent-ids (in-vector id->parents)]\n          #:when dirty?)\n      (vector-set! dirty?-vec id #f)\n      (when (and (not typed?) (ormap enode-typed? eclass))\n        (vector-set! typed?-vec id #t)\n        (for ([parent-id (in-vector parent-ids)])\n          (vector-set! dirty?-vec parent-id #t)\n          (when (< parent-id id)\n            (set! rerun? #t)))))\n    (when rerun?\n      (check-typed! dirty?-vec)))\n\n  (check-typed! (vector-copy id->leaf?))\n  (for ([id (in-range n)])\n    (define eclass (vector-ref id->eclass id))\n    (vector-set! id->eclass id (filter enode-typed? eclass)))\n\n  ; sanity check: every child id points to a non-empty e-class\n  (for ([id (in-range n)])\n    (define eclass (vector-ref id->eclass id))\n    (for ([enode (in-list eclass)])\n      (match enode\n        [(list _ ids ...)\n         (for ([id (in-list ids)]\n               #:when (null? (vector-ref id->eclass id)))\n           (error 'prune-ill-typed!\n                  \"eclass ~a is empty, eclasses ~a\"\n                  id\n                  (for/vector #:length n\n                              ([id (in-range n)])\n                    (list id (vector-ref id->eclass id)))))]\n        [_ (void)]))))\n\n;; Rebuilds eclasses and associated data after pruning.\n(define (rebuild-eclasses id->eclass eclass-ids egg-id->idx type->idx)\n  (define n (vector-length id->eclass))\n  (define remap (make-vector n #f))\n\n  ; build the id map\n  (define n* 0)\n  (for ([id (in-range n)])\n    (define eclass (vector-ref id->eclass id))\n    (unless (null? eclass)\n      (vector-set! remap id n*)\n      (set! n* (add1 n*))))\n\n  ; invert `type->idx` map\n  (define idx->type (make-hash))\n  (define num-types (hash-count type->idx))\n  (for ([(type idx) (in-hash type->idx)])\n    (hash-set! idx->type idx type))\n\n  ; rebuild eclass and type vectors\n  ; transform each eclass from a list to a vector\n  (define eclasses (make-vector n* #f))\n  (define types (make-vector n* #f))\n  (for ([id (in-range n)])\n    (define id* (vector-ref remap id))\n    (when id*\n      (define eclass (vector-ref id->eclass id))\n      (vector-set! eclasses\n                   id*\n                   (for/vector #:length (length eclass)\n                               ([enode (in-list eclass)])\n                     (match enode\n                       [(? number?) enode]\n                       [(? symbol?) enode]\n                       [(list op ids ...)\n                        (define ids* (map (lambda (id) (vector-ref remap id)) ids))\n                        (cons op ids*)])))\n      (vector-set! types id* (hash-ref idx->type (modulo id num-types)))))\n\n  ; build the canonical id map\n  (define egg-id->id (make-hash))\n  (for ([eid (in-u32vector eclass-ids)])\n    (define idx (u32vector-ref egg-id->idx eid))\n    (define id0 (* idx num-types))\n    (for ([id (in-range id0 (+ id0 num-types))])\n      (define id* (vector-ref remap id))\n      (when id*\n        (define type (vector-ref types id*))\n        (hash-set! egg-id->id (cons eid type) id*))))\n\n  (values eclasses types egg-id->id))\n\n;; Splits untyped eclasses into typed eclasses,\n;; keeping only the subset of enodes that are well-typed.\n(define (make-typed-eclasses ptr ctx)\n  ;; Step 1: split Rust-eclasses by type\n  (define-values (id->eclass id->parents id->leaf? eclass-ids egg-id->idx type->idx)\n    (split-untyped-eclasses ptr ctx))\n\n  ;; Step 2: keep well-typed e-nodes\n  ;; An e-class is well-typed if it has one well-typed node\n  ;; A node is well-typed if all of its child e-classes are well-typed.\n  (prune-ill-typed! id->eclass id->parents id->leaf?)\n\n  ;; Step 3: remap e-classes\n  ;; Any empty e-classes must be removed, so we re-map every id\n  (rebuild-eclasses id->eclass eclass-ids egg-id->idx type->idx))\n\n;; Analyzes eclasses for their properties.\n;; The result are vector-maps from e-class ids to data.\n;;  - parents: parent e-classes (as a vector)\n;;  - leaf?: does the e-class contain a leaf node\n;;  - constants: the e-class constant (if one exists)\n(define (analyze-eclasses eclasses)\n  (define n (vector-length eclasses))\n  (define parents (make-vector n '()))\n  (define leaf? (make-vector n '#f))\n  (define constants (make-vector n #f))\n  (for ([id (in-range n)])\n    (define eclass (vector-ref eclasses id))\n    (for ([enode eclass]) ; might be a list or vector\n      (match enode\n        [(? number? n)\n         (vector-set! leaf? id #t)\n         (vector-set! constants id n)]\n        [(? symbol?) (vector-set! leaf? id #t)]\n        [(list _ ids ...)\n         (when (null? ids)\n           (vector-set! leaf? id #t))\n         (for ([child-id (in-list ids)])\n           (vector-set! parents child-id (cons id (vector-ref parents child-id))))])))\n\n  ; parent map: remove duplicates, convert lists to vectors\n  (for ([id (in-range n)])\n    (define ids (remove-duplicates (vector-ref parents id)))\n    (vector-set! parents id (list->vector ids)))\n\n  (values parents leaf? constants))\n\n;; Constructs a Racket egraph from an S-expr representation of\n;; an egraph and data to translate egg IR to herbie IR.\n(define (make-regraph ptr ctx)\n  ;; split the e-classes by type\n  (define-values (eclasses types canon) (make-typed-eclasses ptr ctx))\n\n  ;; analyze each eclass\n  (define-values (parents leaf? constants) (analyze-eclasses eclasses))\n\n  ; construct the `regraph` instance\n  (regraph eclasses types leaf? constants parents canon ctx))\n\n(define (regraph-nodes->json regraph)\n  (define cost (platform-node-cost-proc (*active-platform*)))\n  (for/hash ([n (in-naturals)]\n             [eclass (in-vector (regraph-eclasses regraph))]\n             #:when true\n             [k (in-naturals)]\n             [enode eclass])\n    (define type (vector-ref (regraph-types regraph) n))\n    (define cost\n      (if (representation? type)\n          (match enode\n            [(? number?) (platform-repr-cost (*active-platform*) type)]\n            [(? symbol?) (platform-repr-cost (*active-platform*) type)]\n            [(list '$approx x y) 0]\n            [(list op args ...) (impl-info op 'cost)])\n          1))\n    (values (string->symbol (format \"~a.~a\" n k))\n            (hash 'op\n                  (~a (if (list? enode)\n                          (car enode)\n                          enode))\n                  'children\n                  (if (list? enode)\n                      (map (lambda (e) (format \"~a.0\" e)) (cdr enode))\n                      '())\n                  'eclass\n                  (~a n)\n                  'cost\n                  cost))))\n\n;; Egraph node has children.\n;; Nullary operators have no children!\n(define (node-has-children? node)\n  (and (pair? node) (pair? (cdr node))))\n\n;; Computes an analysis for each eclass.\n;; Takes a regraph and an procedure taking the analysis, an eclass, and\n;; its eclass id producing a non-`#f` result when the parents of the eclass\n;; need to be revisited. Result is a vector where each entry is\n;; the eclass's analysis.\n(define (regraph-analyze regraph eclass-proc #:analysis [analysis #f])\n  (define eclasses (regraph-eclasses regraph))\n  (define leaf? (regraph-leaf? regraph))\n  (define parents (regraph-parents regraph))\n  (define n (vector-length eclasses))\n\n  ; set analysis if not provided\n  (unless analysis\n    (set! analysis (make-vector n #f)))\n  (define dirty?-vec (vector-copy leaf?)) ; visit eclass on next pass?\n  (define changed?-vec0 (make-vector n #f)) ; eclass was changed last iteration\n  (define changed?-vec*0 (make-vector n #f)) ; eclass changed this iteration\n\n  ; run the analysis\n  (let sweep! ([iter 0]\n               [changed?-vec changed?-vec0]\n               [changed?-vec* changed?-vec*0])\n    (define rerun? #f)\n    (for ([id (in-range n)]\n          [dirty-this? (in-vector dirty?-vec)]\n          [eclass (in-vector eclasses)]\n          [parent-ids (in-vector parents)]\n          #:when dirty-this?)\n      (vector-set! dirty?-vec id #f)\n      (when (eclass-proc analysis changed?-vec iter eclass id)\n        ; eclass analysis was updated: need to revisit the parents\n        ; expose updates to later eclasses in this iteration\n        (vector-set! changed?-vec id #t)\n        (vector-set! changed?-vec* id #t)\n        (for ([parent-id (in-vector parent-ids)])\n          (vector-set! dirty?-vec parent-id #t)\n          (when (<= parent-id id)\n            (set! rerun? #t)))))\n    ; if rerun, analysis has not converged so loop\n    (when rerun?\n      (vector-fill! changed?-vec #f)\n      (sweep! (add1 iter) changed?-vec* changed?-vec)))\n\n  ; Invariant: all eclasses have an analysis\n  (for ([id (in-range n)]\n        [eclass-analysis (in-vector analysis)]\n        #:unless eclass-analysis)\n    (define types (regraph-types regraph))\n    (error 'regraph-analyze\n           \"analysis not run on all eclasses: ~a ~a\"\n           eclass-proc\n           (for/vector #:length n\n                       ([id (in-range n)]\n                        [type (in-vector types)]\n                        [eclass (in-vector eclasses)]\n                        [eclass-analysis (in-vector analysis)])\n             (list id type eclass eclass-analysis))))\n\n  analysis)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; Regraph typed extraction\n;;\n;; Typed extraction is ideal for extracting specifications from an egraph.\n;; By \"typed\", we refer to the output \"representation\" of a given operator.\n;; This style of extractor associates to each eclass the best\n;; (cost, node) pair for each possible output type in the eclass.\n;; The extractor procedure takes an eclass id and an output type.\n;;\n;; Typed cost functions take:\n;;  - the regraph we are extracting from\n;;  - a mutable cache (to possibly stash per-node data)\n;;  - the node we are computing cost for\n;;  - 3 argument procedure taking:\n;;       - an eclass id\n;;       - an output type\n;;       - a default failure value\n;;\n\n;; The typed extraction algorithm.\n;; Extraction is partial, that is, the result of the extraction\n;; procedure is `#f` if extraction finds no well-typed program\n;; at a particular id with a particular output type.\n(define ((typed-egg-batch-extractor batch-extract-to) regraph)\n  (define eclasses (regraph-eclasses regraph))\n  (define types (regraph-types regraph))\n  (define n (vector-length eclasses))\n\n  ; e-class costs\n  (define costs (make-vector n #f))\n\n  ; looks up the cost\n  (define (unsafe-eclass-cost id)\n    (car (vector-ref costs id)))\n\n  ; do its children e-classes have a cost\n  (define (node-ready? node)\n    (match node\n      [(? number?) #t]\n      [(? symbol?) #t]\n      [(list '$approx _ impl) (vector-ref costs impl)]\n      [(list _ ids ...) (andmap (lambda (id) (vector-ref costs id)) ids)]))\n\n  ; computes cost of a node (as long as each of its children have costs)\n  ; cost function has access to a mutable value through `cache`\n  (define cache (box #f))\n  (define (node-cost node type)\n    (and (node-ready? node) (platform-egg-cost-proc regraph cache node type unsafe-eclass-cost)))\n\n  ; updates the cost of the current eclass.\n  ; returns whether the cost of the current eclass has improved.\n  (define (eclass-set-cost! _ changed?-vec iter eclass id)\n    (define type (vector-ref types id))\n    (define updated? #f)\n\n    ; update cost information\n    (define (update-cost! new-cost node)\n      (when new-cost\n        (define prev-cost&node (vector-ref costs id))\n        (when (or (not prev-cost&node) ; first cost\n                  (< new-cost (car prev-cost&node))) ; better cost\n          (vector-set! costs id (cons new-cost node))\n          (set! updated? #t))))\n\n    ; optimization: we only need to update node cost as needed.\n    ;  (i) terminals, nullary operators: only compute once\n    ;  (ii) non-nullary operators: compute when any of its child eclasses\n    ;       have their analysis updated\n    (define (node-requires-update? node)\n      (if (node-has-children? node)\n          (ormap (lambda (id) (vector-ref changed?-vec id)) (cdr node))\n          (= iter 0)))\n\n    ; iterate over each node\n    (for ([node (in-vector eclass)]\n          #:when (node-requires-update? node))\n      (define new-cost (node-cost node type))\n      (update-cost! new-cost node))\n\n    updated?)\n\n  ; run the analysis\n  (regraph-analyze regraph eclass-set-cost! #:analysis costs)\n\n  (define ctx (regraph-ctx regraph))\n  (define-values (add-id add-enode) (egg-nodes->batch costs batch-extract-to ctx))\n  ;; These functions provide a setup to extract nodes into batch-extract-to from nodes\n  (list add-id add-enode))\n\n(define (egg-nodes->batch egg-nodes batch ctx)\n  (define (eggref id)\n    (cdr (vector-ref egg-nodes id)))\n\n  (define memo (make-hash))\n\n  (define (add-enode enode type)\n    (define enode*\n      (match enode\n        [(? number?)\n         (if (representation? type)\n             (literal enode (representation-name type))\n             enode)]\n        [(? symbol?)\n         (if (string-prefix? (symbol->string enode) \"$var\")\n             (egg-var->var enode ctx)\n             enode)]\n        [(list '$approx spec impl)\n         (define spec-type\n           (if (representation? type)\n               (representation-type type)\n               type))\n         (approx (batchref-idx (add-id spec spec-type)) (batchref-idx (add-id impl type)))]\n        [(list impl args ...)\n         (define args*\n           (for/list ([arg-id (in-list args)]\n                      [arg-type (in-list (if (representation? type)\n                                             (impl-info impl 'itype)\n                                             (operator-info impl 'itype)))])\n             (batchref-idx (add-id arg-id arg-type))))\n         (cons impl args*)]))\n    (batchref-idx (batch-push! batch enode*)))\n\n  (define (add-id id type)\n    (define key (cons id type))\n    (define idx (hash-ref! memo key (λ () (add-enode (eggref id) type))))\n    (batchref batch idx))\n\n  (values add-id (λ (enode type) (batchref batch (add-enode enode type)))))\n\n;; Is fractional with odd denominator.\n(define (fraction-with-odd-denominator? frac)\n  (cond\n    [(rational? frac)\n     (define denom (denominator frac))\n     (and (> denom 1) (odd? denom))]\n    [else #f]))\n\n;; Decompose an e-node representing an impl of `(pow b e)`.\n;; Returns either `#f` or the `(cons b e)`\n(define (pow-impl-args impl args)\n  (define vars (impl-info impl 'vars))\n  (match (impl-info impl 'spec)\n    [(list 'pow b e)\n     #:when (set-member? vars e)\n     (define env (map cons vars args))\n     (define b* (dict-ref env b b))\n     (define e* (dict-ref env e e))\n     (cons b* e*)]\n    [_ #f]))\n\n;; Old cost model version\n(define (default-egg-cost-proc regraph cache node type rec)\n  (match node\n    [(? number?) 1]\n    [(? symbol?) 1]\n    ; approx node\n    [(list '$approx _ impl) (rec impl)]\n    [(list (? impl-exists? impl) args ...)\n     (match (pow-impl-args impl args)\n       [(cons _ e)\n        #:when (let ([n (vector-ref (regraph-constants regraph) e)])\n                 (fraction-with-odd-denominator? n))\n        +inf.0]\n       [_ (apply + 1 (map rec args))])]\n    [(list 'pow b e)\n     (define n (vector-ref (regraph-constants regraph) e))\n     (if (fraction-with-odd-denominator? n)\n         +inf.0\n         (+ 1 (rec b) (rec e)))]\n    [(list _ args ...) (apply + 1 (map rec args))]))\n\n;; Per-node cost function according to the platform\n;; `rec` takes an id, type, and failure value\n(define (platform-egg-cost-proc regraph cache node type rec)\n  (cond\n    [(representation? type)\n     (define ctx (regraph-ctx regraph))\n     (define node-cost-proc (platform-node-cost-proc (*active-platform*)))\n     (match node\n       ; numbers (repr is unused)\n       [(? number? n) ((node-cost-proc (literal n type) type))]\n       [(? symbol?) ; variables\n        (define repr (context-lookup ctx (egg-var->var node ctx)))\n        ((node-cost-proc node repr))]\n       ; approx node\n       [(list '$approx _ impl) (rec impl)]\n       [(list (? impl-exists?) args ...) ; impls\n        (define cost-proc (node-cost-proc node type))\n        (apply cost-proc (map rec args))])]\n    [else (default-egg-cost-proc regraph cache node type rec)]))\n\n;; Extracts the best expression according to the extractor.\n;; Result is a single element list.\n(define (regraph-extract-best regraph extract id type)\n  (define canon (regraph-canon regraph))\n  ; Extract functions to extract exprs from egraph\n  (match-define (list extract-id _) extract)\n  ; extract expr\n  (define key (cons id type))\n  (define id* (hash-ref canon key #f))\n  (cond\n    ; at least one extractable expression\n    [id* (list (extract-id id* type))]\n    ; no extractable expressions\n    [else (list)]))\n\n;; Extracts multiple expressions according to the extractor\n(define (regraph-extract-variants regraph extract id type)\n  ; regraph fields\n  (define eclasses (regraph-eclasses regraph))\n  (define canon (regraph-canon regraph))\n  ; Functions for egg-extraction\n  (match-define (list _ extract-enode) extract)\n  ; extract expressions\n  (define key (cons id type))\n  (cond\n    ; at least one extractable expression\n    [(hash-has-key? canon key)\n     (define id* (hash-ref canon key))\n\n     (remove-duplicates (for/list ([enode (vector-ref eclasses id*)])\n                          (extract-enode enode type))\n                        #:key batchref-idx)]\n    [else (list)]))\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; Scheduler\n;;\n;; A mini-interpreter for egraph \"schedules\" including running egg,\n;; pruning certain kinds of nodes, extracting expressions, etc.\n\n;; Runs rules over the egraph with the given egg parameters.\n(define (egraph-run-rules egg-graph0\n                          egg-rules\n                          #:node-limit [node-limit #f]\n                          #:iter-limit [iter-limit #f]\n                          #:scheduler [scheduler 'backoff])\n  ;; run the rules\n  (define egg-graph (egraph_copy egg-graph0))\n  (define iteration-data (egraph-run egg-graph egg-rules node-limit iter-limit scheduler))\n\n  (when (egraph_is_unsound_detected egg-graph)\n    (warn 'unsound-egraph #:url \"faq.html#unsound-egraph\" \"unsoundness detected in the egraph\"))\n  (timeline-push! 'stop (~a (egraph_get_stop_reason egg-graph)) 1)\n  (values egg-graph iteration-data))\n\n(define (egraph-analyze-rewrite-impact batch brfs ctx iter)\n  (define egg-graph (egraph_create))\n  (egraph-add-exprs egg-graph batch brfs ctx)\n  (define lifting-rules (convert-rules (platform-lifting-rules)))\n  (define-values (egg-graph1 _1)\n    (egraph-run-rules egg-graph lifting-rules #:iter-limit 1 #:scheduler 'simple))\n  (define-values (egg-graph2 iter-data2)\n    (if (> iter 0)\n        (egraph-run-rules egg-graph1 (convert-rules (*rules*)) #:iter-limit iter)\n        (values egg-graph1 _1)))\n  (define-values (egg-graph3 iter-data3) (egraph-run-rules egg-graph2 '()))\n  (define initial-size (iteration-data-num-nodes (last iter-data3)))\n  (define results\n    (for/list ([rule (in-list (*rules*))])\n      (define-values (egg-graph5 iter-data5)\n        (egraph-run-rules egg-graph3 (convert-rules (list rule)) #:iter-limit 2))\n      (define size (iteration-data-num-nodes (last (if (empty? iter-data5) iter-data3 iter-data5))))\n      (cons rule (- size initial-size))))\n  (define final-size\n    (let-values ([(egg-graph6 iter-data6)\n                  (egraph-run-rules egg-graph3 (convert-rules (*rules*)) #:iter-limit 2)])\n      (iteration-data-num-nodes (last (if (empty? iter-data6) iter-data3 iter-data6)))))\n  (values initial-size final-size results))\n\n(define (egraph-run-schedule batch brfs schedule ctx)\n  ; allocate the e-graph\n  (define egg-graph (egraph_create))\n\n  ; insert expressions into the e-graph\n  (define root-ids (egraph-add-exprs egg-graph batch brfs ctx))\n\n  ; run the schedule\n  (define egg-graph*\n    (for/fold ([egg-graph egg-graph]) ([step (in-list schedule)])\n      (define-values (egg-graph* iteration-data)\n        (match step\n          ['lift\n           (define rules (convert-rules (platform-lifting-rules)))\n           (egraph-run-rules egg-graph rules #:iter-limit 1 #:scheduler 'simple)]\n          ['lower\n           (define rules (convert-rules (platform-lowering-rules)))\n           (egraph-run-rules egg-graph rules #:iter-limit 1 #:scheduler 'simple)]\n          ['unsound\n           (define rules (convert-rules (*sound-removal-rules*)))\n           (egraph-run-rules egg-graph rules #:iter-limit 1 #:scheduler 'simple)]\n          ['rewrite\n           (define rules (convert-rules (*rules*)))\n           (egraph-run-rules egg-graph rules #:node-limit (*node-limit*))]))\n\n      ; get cost statistics\n      (for ([iter (in-list iteration-data)]\n            [i (in-naturals)])\n        (define cnt (iteration-data-num-nodes iter))\n        (define cost (for/sum ([id (in-list root-ids)]) (egraph_get_cost egg-graph* id i)))\n        (timeline-push! 'egraph i cnt cost (iteration-data-time iter)))\n\n      egg-graph*))\n\n  ; root eclasses may have changed\n  (define root-ids* (map (lambda (id) (egraph_find egg-graph* id)) root-ids))\n  ; return what we need\n  (values root-ids* egg-graph*))\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; Public API\n;;\n;; Most calls to egg should be done through this interface.\n;;  - `make-egraph`: constructs an egraph and runs rules on it\n;;  - `egraph-equal?`: test if two expressions are equal\n;;  - `egraph-prove`: return a proof that two expressions are equal\n;;  - `egraph-best`: return a batch with the best versions of another batch\n;;  - `egraph-variations`: return a batch with all versions of another batch\n\n;; Herbie's version of an egg runner.\n;; Defines parameters for running rewrite rules with egg\n(struct egg-runner (batch reprs schedule ctx new-roots egg-graph)\n  #:transparent ; for equality\n  #:methods gen:custom-write ; for abbreviated printing\n  [(define (write-proc alt port mode)\n     (fprintf port \"#<egg-runner>\"))])\n\n;; Constructs an egg runner.\n;;\n;; The schedule is a list of step symbols:\n;;  - `lift`: run lifting rules for 1 iteration with simple scheduler\n;;  - `rewrite`: run rewrite rules up to node limit with backoff scheduler\n;;  - `unsound`: run sound-removal rules for 1 iteration with simple scheduler\n;;  - `lower`: run lowering rules for 1 iteration with simple scheduler\n(define (make-egraph batch brfs reprs schedule ctx)\n  (define (oops! fmt . args)\n    (apply error 'verify-schedule! fmt args))\n  ; verify the schedule\n  (for ([step (in-list schedule)])\n    (unless (memq step '(lift lower unsound rewrite))\n      (oops! \"unknown schedule step `~a`\" step)))\n\n  (define-values (root-ids egg-graph) (egraph-run-schedule batch brfs schedule ctx))\n\n  ; make the runner\n  (egg-runner batch reprs schedule ctx root-ids egg-graph))\n\n(define (regraph-dump regraph root-ids reprs)\n  (define dump-dir \"dump-egg\")\n  (unless (directory-exists? dump-dir)\n    (make-directory dump-dir))\n  (define name\n    (for/first ([i (in-naturals)]\n                #:unless (file-exists? (build-path dump-dir (format \"~a.json\" i))))\n      (build-path dump-dir (format \"~a.json\" i))))\n  (define nodes (regraph-nodes->json regraph))\n  (define canon (regraph-canon regraph))\n  (define roots\n    (filter values\n            (for/list ([id (in-list root-ids)]\n                       [type (in-list reprs)])\n              (hash-ref canon (cons id type) #f))))\n  (call-with-output-file\n   name\n   #:exists 'replace\n   (lambda (p) (write-json (hash 'nodes nodes 'root_eclasses (map ~a roots) 'class_data (hash)) p))))\n\n(define (egraph-equal? runner start end)\n  (define ctx (egg-runner-ctx runner))\n  (define egg-graph (egg-runner-egg-graph runner))\n  (egraph-expr-equal? egg-graph start end ctx))\n\n(define (egraph-prove runner start-brf end-brf)\n  (define ctx (egg-runner-ctx runner))\n  (define egg-graph (egg-runner-egg-graph runner))\n  (define batch (egg-runner-batch runner))\n  (define exprs (batch-exprs batch))\n  (define start (exprs start-brf))\n  (define end (exprs end-brf))\n\n  (unless (egraph-expr-equal? egg-graph start end ctx)\n    (error 'egraph-prove \"cannot prove ~a is equal to ~a; not equal\" start end))\n  (define proof (egraph-get-proof egg-graph start end ctx))\n  (when (null? proof)\n    (error 'egraph-prove \"proof extraction failed between`~a` and `~a`\" start end))\n  proof)\n\n(define (egraph-best runner batch)\n  (define ctx (egg-runner-ctx runner))\n  (define root-ids (egg-runner-new-roots runner))\n  (define egg-graph (egg-runner-egg-graph runner))\n\n  ; Return empty results if unsound\n  (cond\n    [(egraph_is_unsound_detected egg-graph) (map (const empty) root-ids)]\n    [else\n     (define regraph (make-regraph egg-graph ctx))\n     (define reprs (egg-runner-reprs runner))\n     (when (flag-set? 'dump 'egg)\n       (regraph-dump regraph root-ids reprs))\n\n     (define extract-id ((typed-egg-batch-extractor batch) regraph))\n\n     ; (Listof (Listof batchref))\n     (for/list ([id (in-list root-ids)]\n                [repr (in-list reprs)])\n       (regraph-extract-best regraph extract-id id repr))]))\n\n(define (egraph-variations runner batch)\n  (define ctx (egg-runner-ctx runner))\n  (define root-ids (egg-runner-new-roots runner))\n  (define egg-graph (egg-runner-egg-graph runner))\n\n  ; Return empty results if unsound\n  (cond\n    [(egraph_is_unsound_detected egg-graph) (map (const empty) root-ids)]\n    [else\n     (define regraph (make-regraph egg-graph ctx))\n     (define reprs (egg-runner-reprs runner))\n     (when (flag-set? 'dump 'egg)\n       (regraph-dump regraph root-ids reprs))\n\n     (define extract-id ((typed-egg-batch-extractor batch) regraph))\n\n     ; (Listof (Listof batchref))\n     (for/list ([id (in-list root-ids)]\n                [repr (in-list reprs)])\n       (regraph-extract-variants regraph extract-id id repr))]))\n"
  },
  {
    "path": "src/core/egglog-herbie-tests.rkt",
    "content": "#lang racket\n\n(require rackunit\n         \"egglog-herbie.rkt\"\n         \"egglog-subprocess.rkt\"\n         \"../syntax/syntax.rkt\")\n\n(define (test-e1->expr)\n  (check-equal? (e1->expr '(Num (bigrat (from-string \"3\") (from-string \"4\")))) 3/4)\n\n  (check-equal? (e1->expr '(Var \"x\")) 'x)\n\n  (check-equal? (e1->expr '(If (Var \"x\")\n                               (Num (bigrat (from-string \"1\") (from-string \"2\")))\n                               (Num (bigrat (from-string \"0\") (from-string \"5\")))))\n                '(if x 1/2 0))\n\n  (check-equal? (e1->expr '(Add (Num (bigrat (from-string \"1\") (from-string \"1\")))\n                                (Num (bigrat (from-string \"2\") (from-string \"1\")))))\n                '(+ 1 2))\n\n  (check-equal? (e1->expr '(Mul (Num (bigrat (from-string \"2\") (from-string \"1\")))\n                                (Num (bigrat (from-string \"3\") (from-string \"1\")))))\n                '(* 2 3))\n\n  (check-equal?\n   (e1->expr '(Add (Mul (Var \"a\") (Div (Num (bigrat (from-string \"3\") (from-string \"2\"))) (Var \"b\")))\n                   (Sub (Num (bigrat (from-string \"5\") (from-string \"6\")))\n                        (Mul (Var \"c\") (Num (bigrat (from-string \"-1\") (from-string \"4\")))))))\n   '(+ (* a (/ 3/2 b)) (- 5/6 (* c -1/4))))\n\n  (check-equal? (e1->expr '(Div (Mul (Sub (Var \"x\") (Var \"y\"))\n                                     (Add (Num (bigrat (from-string \"7\") (from-string \"5\")))\n                                          (Var \"z\")))\n                                (Num (bigrat (from-string \"2\") (from-string \"3\")))))\n                '(/ (* (- x y) (+ 7/5 z)) 2/3))\n\n  (check-equal? (e1->expr '(Eq (Add (Mul (Var \"p\") (Num (bigrat (from-string \"1\") (from-string \"2\"))))\n                                    (Div (Var \"q\")\n                                         (Num (bigrat (from-string \"3\") (from-string \"4\")))))\n                               (Num (bigrat (from-string \"5\") (from-string \"6\")))))\n                '(== (+ (* p 1/2) (/ q 3/4)) 5/6))\n\n  (check-equal? (e1->expr '(Gte (Div (Var \"r\") (Add (Var \"s\") (Var \"t\")))\n                                (Sub (Num (bigrat (from-string \"8\") (from-string \"9\")))\n                                     (Mul (Num (bigrat (from-string \"1\") (from-string \"3\")))\n                                          (Var \"u\")))))\n                '(>= (/ r (+ s t)) (- 8/9 (* 1/3 u)))))\n\n(define (test-e2->expr)\n  (check-equal? (e2->expr '(Numbinary64 (bigrat (from-string \"5\") (from-string \"6\"))))\n                '#s(literal 5/6 binary64))\n\n  (check-equal? (e2->expr '(Varbinary64 \"y\")) 'y)\n\n  (check-equal? (e2->expr '(Iff64Ty (Varbinary64 \"y\")\n                                    (Numbinary64 (bigrat (from-string \"1\") (from-string \"2\")))\n                                    (Numbinary64 (bigrat (from-string \"0\") (from-string \"1\")))))\n                '(if.f64 y #s(literal 1/2 binary64) #s(literal 0 binary64)))\n\n  (check-equal? (e2->expr '(Mulf64Ty (Numbinary64 (bigrat (from-string \"2\") (from-string \"1\")))\n                                     (Numbinary64 (bigrat (from-string \"3\") (from-string \"1\")))))\n                '(*.f64 #s(literal 2 binary64) #s(literal 3 binary64)))\n\n  (check-equal?\n   (e2->expr '(Approx (Add (Num (bigrat (from-string \"1\") (from-string \"1\")))\n                           (Num (bigrat (from-string \"2\") (from-string \"1\"))))\n                      (Mulf64Ty (Numbinary64 (bigrat (from-string \"3\") (from-string \"1\")))\n                                (Numbinary64 (bigrat (from-string \"1\") (from-string \"1\"))))))\n   '#s(approx (+ 1 2) (*.f64 #s(literal 3 binary64) #s(literal 1 binary64))))\n\n  ;; Complex 1\n  (check-equal?\n   (e2->expr\n    '(Approx\n      (Add (Sin (Add (Var \"x\") (Var \"eps\")))\n           (Mul (Num (bigrat (from-string \"-1\") (from-string \"1\"))) (Sin (Var \"x\"))))\n      (Fmaf64Ty\n       (Fmaf64Ty (Sinf64Ty (Varbinary64 \"x\"))\n                 (Fmaf64Ty (Mulf64Ty (Varbinary64 \"eps\")\n                                     (Numbinary64 (bigrat (from-string \"1\") (from-string \"24\"))))\n                           (Varbinary64 \"eps\")\n                           (Numbinary64 (bigrat (from-string \"-1\") (from-string \"2\"))))\n                 (Mulf64Ty (Mulf64Ty (Varbinary64 \"eps\")\n                                     (Numbinary64 (bigrat (from-string \"-1\") (from-string \"6\"))))\n                           (Cosf64Ty (Varbinary64 \"x\"))))\n       (Mulf64Ty (Varbinary64 \"eps\") (Varbinary64 \"eps\"))\n       (Mulf64Ty (Cosf64Ty (Varbinary64 \"x\")) (Varbinary64 \"eps\")))))\n   '#s(approx (+ (sin (+ x eps)) (* -1 (sin x)))\n              (fma.f64\n               (fma.f64 (sin.f64 x)\n                        (fma.f64 (*.f64 eps #s(literal 1/24 binary64)) eps #s(literal -1/2 binary64))\n                        (*.f64 (*.f64 eps #s(literal -1/6 binary64)) (cos.f64 x)))\n               (*.f64 eps eps)\n               (*.f64 (cos.f64 x) eps))))\n\n  ;; Complex 2\n  (check-equal?\n   (e2->expr\n    '(Mulf64Ty\n      (Fmaf64Ty\n       (Mulf64Ty (Fmaf64Ty (Mulf64Ty (Varbinary64 \"eps\")\n                                     (Numbinary64 (bigrat (from-string \"1\") (from-string \"24\"))))\n                           (Varbinary64 \"eps\")\n                           (Numbinary64 (bigrat (from-string \"-1\") (from-string \"2\"))))\n                 (Sinf64Ty (Varbinary64 \"x\")))\n       (Varbinary64 \"eps\")\n       (Mulf64Ty (Fmaf64Ty (Mulf64Ty (Varbinary64 \"eps\")\n                                     (Numbinary64 (bigrat (from-string \"-1\") (from-string \"6\"))))\n                           (Varbinary64 \"eps\")\n                           (Numbinary64 (bigrat (from-string \"1\") (from-string \"1\"))))\n                 (Cosf64Ty (Varbinary64 \"x\"))))\n      (Varbinary64 \"eps\")))\n   '(*.f64\n     (fma.f64 (*.f64 (fma.f64 (*.f64 eps #s(literal 1/24 binary64)) eps #s(literal -1/2 binary64))\n                     (sin.f64 x))\n              eps\n              (*.f64 (fma.f64 (*.f64 eps #s(literal -1/6 binary64)) eps #s(literal 1 binary64))\n                     (cos.f64 x)))\n     eps))\n\n  ;; Complex 3\n  (check-equal?\n   (e2->expr\n    '(Fmaf64Ty\n      (Mulf64Ty (Fmaf64Ty (Mulf64Ty (Varbinary64 \"eps\")\n                                    (Numbinary64 (bigrat (from-string \"1\") (from-string \"24\"))))\n                          (Varbinary64 \"eps\")\n                          (Numbinary64 (bigrat (from-string \"-1\") (from-string \"2\"))))\n                (Sinf64Ty (Varbinary64 \"x\")))\n      (Varbinary64 \"eps\")\n      (Mulf64Ty (Fmaf64Ty (Mulf64Ty (Varbinary64 \"eps\")\n                                    (Numbinary64 (bigrat (from-string \"-1\") (from-string \"6\"))))\n                          (Varbinary64 \"eps\")\n                          (Numbinary64 (bigrat (from-string \"1\") (from-string \"1\"))))\n                (Cosf64Ty (Varbinary64 \"x\")))))\n   '(fma.f64\n     (*.f64 (fma.f64 (*.f64 eps #s(literal 1/24 binary64)) eps #s(literal -1/2 binary64)) (sin.f64 x))\n     eps\n     (*.f64 (fma.f64 (*.f64 eps #s(literal -1/6 binary64)) eps #s(literal 1 binary64)) (cos.f64 x))))\n\n  ;; Complex 4\n  (check-equal?\n   (e2->expr\n    '(Fmaf64Ty (Sinf64Ty (Varbinary64 \"x\"))\n               (Fmaf64Ty (Mulf64Ty (Varbinary64 \"eps\")\n                                   (Numbinary64 (bigrat (from-string \"1\") (from-string \"24\"))))\n                         (Varbinary64 \"eps\")\n                         (Numbinary64 (bigrat (from-string \"-1\") (from-string \"2\"))))\n               (Mulf64Ty (Mulf64Ty (Varbinary64 \"eps\")\n                                   (Numbinary64 (bigrat (from-string \"-1\") (from-string \"6\"))))\n                         (Cosf64Ty (Varbinary64 \"x\")))))\n   '(fma.f64 (sin.f64 x)\n             (fma.f64 (*.f64 eps #s(literal 1/24 binary64)) eps #s(literal -1/2 binary64))\n             (*.f64 (*.f64 eps #s(literal -1/6 binary64)) (cos.f64 x))))\n\n  (check-equal? (e2->expr '(Approx (Add (Sin (Add (Var \"x\") (Var \"eps\"))))\n                                   (Mulf64Ty (Numbinary64 (bigrat (from-string \"-1\")\n                                                                  (from-string \"1\")))\n                                             (Cosf64Ty (Varbinary64 \"x\")))))\n                '#s(approx (+ (sin (+ x eps))) (*.f64 #s(literal -1 binary64) (cos.f64 x))))\n\n  (check-equal? (e2->expr '(Mulf32Ty (Numbinary32 (bigrat (from-string \"3\") (from-string \"2\")))\n                                     (Addf32Ty (Numbinary32 (bigrat (from-string \"4\")\n                                                                    (from-string \"5\")))\n                                               (Varbinary32 \"z\"))))\n                '(*.f32 #s(literal 3/2 binary32) (+.f32 #s(literal 4/5 binary32) z)))\n\n  (check-equal? (e2->expr '(Iff32Ty (Varbinary32 \"cond\")\n                                    (Numbinary32 (bigrat (from-string \"7\") (from-string \"8\")))\n                                    (Numbinary32 (bigrat (from-string \"-2\") (from-string \"3\")))))\n                '(if.f32 cond #s(literal 7/8 binary32) #s(literal -2/3 binary32))))\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; Testing API\n;; Test helpers for e1/e2 serialization tables.\n;;  - `populate-e->id-tables`: Used for testing e1-> expr and e2-> expr.\n;;                             Populates the e1->id and e2->id tables\n(define (populate-e->id-tables)\n  (begin\n\n    (for ([op (in-list (all-operators))])\n      (hash-set! (e1->id) (serialize-op op) op))\n\n    (for-each (λ (pair) (hash-set! (e2->id) (car pair) (cdr pair)))\n              '((Acosf32Ty . acos.f32) (Acosf64Ty . acos.f64)\n                                       (Acoshf32Ty . acosh.f32)\n                                       (Acoshf64Ty . acosh.f64)\n                                       (Addf32Ty . +.f32)\n                                       (Addf64Ty . +.f64)\n                                       (AndboolTy . and.bool)\n                                       (Asinf32Ty . asin.f32)\n                                       (Asinf64Ty . asin.f64)\n                                       (Asinhf32Ty . asinh.f32)\n                                       (Asinhf64Ty . asinh.f64)\n                                       (Atan2f32Ty . atan2.f32)\n                                       (Atan2f64Ty . atan2.f64)\n                                       (Atanf32Ty . atan.f32)\n                                       (Atanf64Ty . atan.f64)\n                                       (Atanhf32Ty . atanh.f32)\n                                       (Atanhf64Ty . atanh.f64)\n                                       (Cbrtf32Ty . cbrt.f32)\n                                       (Cbrtf64Ty . cbrt.f64)\n                                       (Ceilf32Ty . ceil.f32)\n                                       (Ceilf64Ty . ceil.f64)\n                                       (Copysignf32Ty . copysign.f32)\n                                       (Copysignf64Ty . copysign.f64)\n                                       (Cosf32Ty . cos.f32)\n                                       (Cosf64Ty . cos.f64)\n                                       (Coshf32Ty . cosh.f32)\n                                       (Coshf64Ty . cosh.f64)\n                                       (Divf32Ty . /.f32)\n                                       (Divf64Ty . /.f64)\n                                       (Ef32Ty . E.f32)\n                                       (Ef64Ty . E.f64)\n                                       (Eqf32Ty . ==.f32)\n                                       (Eqf64Ty . ==.f64)\n                                       (Erfcf32Ty . erfc.f32)\n                                       (Erfcf64Ty . erfc.f64)\n                                       (Erff32Ty . erf.f32)\n                                       (Erff64Ty . erf.f64)\n                                       (Exp2f32Ty . exp2.f32)\n                                       (Exp2f64Ty . exp2.f64)\n                                       (Expf32Ty . exp.f32)\n                                       (Expf64Ty . exp.f64)\n                                       (Expm1f32Ty . expm1.f32)\n                                       (Expm1f64Ty . expm1.f64)\n                                       (Fabsf32Ty . fabs.f32)\n                                       (Fabsf64Ty . fabs.f64)\n                                       (FalseboolTy . FALSE.bool)\n                                       (Fdimf32Ty . fdim.f32)\n                                       (Fdimf64Ty . fdim.f64)\n                                       (Floorf32Ty . floor.f32)\n                                       (Floorf64Ty . floor.f64)\n                                       (Fmaf32Ty . fma.f32)\n                                       (Fmaf64Ty . fma.f64)\n                                       (Fmaxf32Ty . fmax.f32)\n                                       (Fmaxf64Ty . fmax.f64)\n                                       (Fminf32Ty . fmin.f32)\n                                       (Fminf64Ty . fmin.f64)\n                                       (Fmodf32Ty . fmod.f32)\n                                       (Fmodf64Ty . fmod.f64)\n                                       (Gtef32Ty . >=.f32)\n                                       (Gtef64Ty . >=.f64)\n                                       (Gtf32Ty . >.f32)\n                                       (Gtf64Ty . >.f64)\n                                       (Hypotf32Ty . hypot.f32)\n                                       (Hypotf64Ty . hypot.f64)\n                                       (Infinityf32Ty . INFINITY.f32)\n                                       (Infinityf64Ty . INFINITY.f64)\n                                       (Lgammaf32Ty . lgamma.f32)\n                                       (Lgammaf64Ty . lgamma.f64)\n                                       (Log10f32Ty . log10.f32)\n                                       (Log10f64Ty . log10.f64)\n                                       (Log1pf32Ty . log1p.f32)\n                                       (Log1pf64Ty . log1p.f64)\n                                       (Log2f32Ty . log2.f32)\n                                       (Log2f64Ty . log2.f64)\n                                       (Logbf32Ty . logb.f32)\n                                       (Logbf64Ty . logb.f64)\n                                       (Logf32Ty . log.f32)\n                                       (Logf64Ty . log.f64)\n                                       (Ltef32Ty . <=.f32)\n                                       (Ltef64Ty . <=.f64)\n                                       (Ltf32Ty . <.f32)\n                                       (Ltf64Ty . <.f64)\n                                       (Mulf32Ty . *.f32)\n                                       (Mulf64Ty . *.f64)\n                                       (Nanf32Ty . NAN.f32)\n                                       (Nanf64Ty . NAN.f64)\n                                       (Negf32Ty . neg.f32)\n                                       (Negf64Ty . neg.f64)\n                                       (Neqf32Ty . !=.f32)\n                                       (Neqf64Ty . !=.f64)\n                                       (NotboolTy . not.bool)\n                                       (OrboolTy . or.bool)\n                                       (Iff32Ty . if.f32)\n                                       (Iff64Ty . if.f64)\n                                       (Pif32Ty . PI.f32)\n                                       (Pif64Ty . PI.f64)\n                                       (Powf32Ty . pow.f32)\n                                       (Powf64Ty . pow.f64)\n                                       (Remainderf32Ty . remainder.f32)\n                                       (Remainderf64Ty . remainder.f64)\n                                       (Rintf32Ty . rint.f32)\n                                       (Rintf64Ty . rint.f64)\n                                       (Roundf32Ty . round.f32)\n                                       (Roundf64Ty . round.f64)\n                                       (Sinf32Ty . sin.f32)\n                                       (Sinf64Ty . sin.f64)\n                                       (Sinhf32Ty . sinh.f32)\n                                       (Sinhf64Ty . sinh.f64)\n                                       (Sqrtf32Ty . sqrt.f32)\n                                       (Sqrtf64Ty . sqrt.f64)\n                                       (Subf32Ty . -.f32)\n                                       (Subf64Ty . -.f64)\n                                       (Tanf32Ty . tan.f32)\n                                       (Tanf64Ty . tan.f64)\n                                       (Tanhf32Ty . tanh.f32)\n                                       (Tanhf64Ty . tanh.f64)\n                                       (Tgammaf32Ty . tgamma.f32)\n                                       (Tgammaf64Ty . tgamma.f64)\n                                       (TrueboolTy . TRUE.bool)\n                                       (Truncf32Ty . trunc.f32)\n                                       (Truncf64Ty . trunc.f64)))))\n\n; run-tests\n(module+ test\n  (require rackunit\n           \"egglog-herbie.rkt\")\n\n  (when (find-executable-path \"egglog\")\n    (populate-e->id-tables)\n    (test-e1->expr)\n    (test-e2->expr)))\n\n;; run-sample-egglog\n(module+ test\n  (require rackunit\n           \"egglog-herbie.rkt\"\n           \"../syntax/types.rkt\"\n           \"../syntax/batch.rkt\"\n           \"rules.rkt\"\n           \"../config.rkt\"\n           \"../syntax/platform.rkt\"\n           \"../syntax/float.rkt\"\n           \"../syntax/load-platform.rkt\")\n  (activate-platform! \"c\")\n\n  (define-values (batch brfs)\n    (progs->batch (list '(-.f64 (sin.f64 (+.f64 x eps)) (sin.f64 x))\n                        '(sin.f64 (+.f64 x eps))\n                        '(+.f64 x eps)\n                        'x\n                        'eps\n                        '(sin.f64 x))))\n\n  (define-values (batch2 brfs2)\n    (progs->batch\n     (list\n      '(-.f64 (sin.f64 (+.f64 x #s(literal 1 binary64))) (sin.f64 x))\n      '(sin.f64 (+.f64 x #s(literal 1 binary64)))\n      '(+.f64 x #s(literal 1 binary64))\n      'x\n      #s(literal 1 binary64)\n      '(sin.f64 x)\n      #s(approx (- (sin (+ x 1)) (sin x)) #s(hole binary64 (sin 1)))\n      #s(approx (- (sin (+ x 1)) (sin x)) #s(hole binary64 (+ (sin 1) (* x (- (cos 1) 1)))))\n      #s(approx (- (sin (+ x 1)) (sin x))\n                #s(hole binary64 (+ (sin 1) (* x (- (+ (cos 1) (* -1/2 (* x (sin 1)))) 1)))))\n      #s(approx (- (sin (+ x 1)) (sin x))\n                #s(hole binary64\n                        (+ (sin 1)\n                           (* x\n                              (- (+ (cos 1) (* x (+ (* -1/2 (sin 1)) (* x (+ 1/6 (* -1/6 (cos 1)))))))\n                                 1)))))\n      #s(approx (sin (+ x 1)) #s(hole binary64 (+ (sin 1) (* x (cos 1)))))\n      #s(approx (sin (+ x 1)) #s(hole binary64 (+ (sin 1) (* x (+ (cos 1) (* -1/2 (* x (sin 1))))))))\n      #s(approx (sin (+ x 1))\n                #s(hole binary64\n                        (+ (sin 1)\n                           (* x (+ (cos 1) (* x (+ (* -1/2 (sin 1)) (* -1/6 (* x (cos 1))))))))))\n      #s(approx (+ x 1) #s(hole binary64 1))\n      #s(approx (+ x 1) #s(hole binary64 (+ 1 x)))\n      #s(approx x #s(hole binary64 x))\n      #s(approx (sin x) #s(hole binary64 (* x (+ 1 (* -1/6 (pow x 2))))))\n      #s(approx (sin x) #s(hole binary64 (* x (+ 1 (* (pow x 2) (- (* 1/120 (pow x 2)) 1/6))))))\n      #s(approx\n         (sin x)\n         #s(hole binary64\n                 (* x (+ 1 (* (pow x 2) (- (* (pow x 2) (+ 1/120 (* -1/5040 (pow x 2)))) 1/6))))))\n      #s(approx (- (sin (+ x 1)) (sin x)) #s(hole binary64 (- (sin (+ 1 x)) (sin x))))\n      #s(approx (sin (+ x 1)) #s(hole binary64 (sin (+ 1 x))))\n      #s(approx (+ x 1) #s(hole binary64 (* x (+ 1 (/ 1 x)))))\n      #s(approx (sin x) #s(hole binary64 (sin x)))\n      #s(approx (- (sin (+ x 1)) (sin x)) #s(hole binary64 (- (sin (- 1 (* -1 x))) (sin x))))\n      #s(approx (sin (+ x 1)) #s(hole binary64 (sin (- 1 (* -1 x))))))))\n\n  (define ctx (context '(x eps) <binary64> (make-list 2 <binary64>)))\n\n  (define reprs (make-list (length brfs) (context-repr ctx)))\n\n  (define schedule '(lift rewrite lower))\n\n  (when (find-executable-path \"egglog\")\n    (void (run-egglog (make-egglog-runner batch brfs reprs schedule ctx) batch #:extract 1000000))))\n\n(module+ test\n  (require rackunit)\n  (when (find-executable-path \"egglog\")\n    (define subproc (create-new-egglog-subprocess #f))\n\n    (define first-commands\n      (list '(datatype Expr (Var String :cost 150) (Add Expr Expr :cost 200))\n            '(constructor const1 () Expr :unextractable)\n            '(constructor const2 () Expr :unextractable)\n            '(constructor const3 () Expr :unextractable)\n            '(function unsound () bool :merge (or old new))\n            '(ruleset unsound-rule)\n            '(set (unsound) false)\n            '(rule ((= (Var c1) (Var c2)) (!= c1 c2)) ((set (unsound) true)) :ruleset unsound-rule)\n            '(ruleset init)\n            '(rule ()\n                   ((let a1 (Var\n                             \"x\")\n                      )\n                    (union (const1) a1)\n                    (let a2 (Var\n                             \"y\")\n                      )\n                    (union (const2) a2)\n                    (let b1 (Add\n                             a1\n                             a2)\n                      )\n                    (union (const3) b1))\n                   :ruleset\n                   init)\n            '(run init 1)))\n\n    ; Nothing to output\n    (apply egglog-send subproc first-commands)\n\n    ; Has extract 1 thing\n    (define lines1 (egglog-extract subproc '(extract (const1) 1)))\n    (check-equal? lines1 '((Var \"x\")))\n\n    ;; Print size\n\n    (match-define (list node-values '() (list \"false\"))\n      (egglog-send subproc '(print-size) '(run unsound-rule 1) '(extract (unsound))))\n    (define parsed-node-values\n      (for/list ([entry (in-list (with-input-from-string (string-join node-values \"\\n\") read))])\n        (match entry\n          [(list relation count) (cons relation count)])))\n    (check-equal? (sort parsed-node-values symbol<? #:key car)\n                  '((Add . 1) (Var . 2) (const1 . 1) (const2 . 1) (const3 . 1) (unsound . 1)))\n\n    ;; last two\n    (check-equal? '((Var \"y\")) (egglog-extract subproc '(extract (const2) 1)))\n    (check-equal? '((Add (Var \"x\") (Var \"y\"))) (egglog-extract subproc '(extract (const3) 1)))\n\n    (egglog-subprocess-close subproc)\n    (void)))\n"
  },
  {
    "path": "src/core/egglog-herbie.rkt",
    "content": "#lang racket\n\n(require racket/file\n         \"rules.rkt\"\n         \"../syntax/platform.rkt\"\n         \"../syntax/syntax.rkt\"\n         \"../syntax/types.rkt\"\n         \"../config.rkt\"\n         \"../syntax/batch.rkt\"\n         \"../utils/common.rkt\"\n         \"egglog-subprocess.rkt\")\n\n(provide (struct-out egglog-runner)\n         prelude\n         egglog-add-exprs\n         make-egglog-runner\n         run-egglog\n         e2->expr\n         e1->expr\n         egglog-var?\n         serialize-op\n         e1->id\n         e2->id)\n\n(define op-string-names\n  (hash '+ 'Add '- 'Sub '* 'Mul '/ 'Div '== 'Eq '!= 'Neq '> 'Gt '< 'Lt '>= 'Gte '<= 'Lte))\n\n(define/reset id->e1 (make-hasheq))\n(define/reset e1->id (make-hasheq))\n(define/reset id->e2 (make-hasheq))\n(define/reset e2->id (make-hasheq))\n\n;; [Copied from egg-herbie.rkt] Returns all representatations (and their types) in the current platform.\n(define (all-repr-names [pform (*active-platform*)])\n  (map representation-name (platform-reprs pform)))\n\n(define (real->bigrat val)\n  `(bigrat (from-string ,(~s (numerator val))) (from-string ,(~s (denominator val)))))\n\n; Types handled\n; - rationals\n; - string\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; Public API\n;; Most calls to egglog should be done through this interface.\n;;  - `make-egglog-runner`: creates a struct that describes a _reproducible_ egglog instance\n;;  - `run-egglog`: takes an egglog runner and performs an extraction (exprs or proof)\n\n;; Herbie's version of an egglog runner.\n;; Defines parameters for running rewrite rules with egglog\n(struct egglog-runner (batch brfs reprs schedule ctx)\n  #:transparent ; for equality\n  #:methods gen:custom-write ; for abbreviated printing\n  [(define (write-proc alt port mode)\n     (fprintf port \"#<egglog-runner>\"))])\n\n;; Constructs an egglog runner - structurally serves the same purpose as egg-runner\n;;\n;; The schedule is a list of step symbols:\n;;  - `lift`: run lifting rules for 1 iteration with simple scheduler\n;;  - `rewrite`: run rewrite rules up to node limit with backoff scheduler\n;;  - `unsound`: run sound-removal rules for 1 iteration with simple scheduler\n;;  - `lower`: run lowering rules for 1 iteration with simple scheduler\n(define (make-egglog-runner batch brfs reprs schedule ctx)\n  (define (oops! fmt . args)\n    (apply error 'verify-schedule! fmt args))\n  ; verify the schedule\n  (for ([step (in-list schedule)])\n    (unless (memq step '(lift lower unsound rewrite))\n      (oops! \"unknown schedule step `~a`\" step)))\n\n  ; make the runner\n  (egglog-runner batch brfs reprs schedule ctx))\n\n;; Runs egglog using an egglog runner by extracting multiple variants\n(define (run-egglog runner output-batch [label #f] #:extract extract) ; multi expression extraction\n  (define insert-batch (egglog-runner-batch runner))\n  (define insert-brfs (egglog-runner-brfs runner))\n  (define schedule (egglog-runner-schedule runner))\n  (define pform (*active-platform*))\n\n  ;;;; SUBPROCESS START ;;;;\n  (define subproc (create-new-egglog-subprocess label))\n\n  ;; 1. Add the prelude - send directly to egglog.\n  (prelude subproc #:mixed-egraph? #t)\n\n  ;; 2. Inserting expressions into the egglog program and getting a Listof (exprs . extract bindings)\n\n  ;; Overview of the new extraction method:\n  ;;\n  ;; The idea is to wrap the top-level `let` bindings inside a rule, and then\n  ;; execute that rule to perform the computation and store results using constructors.\n  ;;\n  ;; In the original design, we had a sequence of `let` bindings followed by a schedule run and\n  ;; then we perform an extraction of the required bindings.\n  ;;\n  ;; The new design introduces unextractable constructors to hold each intermediate result.\n  ;; These constructors are used in combination with a rule that performs all the bindings\n  ;; and assigns them via `set`\n  ;;\n  ;;   (constructor const1 () Expr :unextractable)\n  ;;   (constructor const2 () Expr :unextractable)\n  ;;   (constructor const3 () Expr :unextractable)\n  ;;   ...\n  ;;\n  ;;   (ruleset init)\n  ;;\n  ;;   (rule () (\n  ;;     (let a1 ...)\n  ;;     (union (const1) a1)\n  ;;\n  ;;     (let a2 ...)\n  ;;     (union (const2) a2)\n  ;;\n  ;;     (let b1 ...)\n  ;;     (union (const3) b1)\n  ;;   )\n  ;;   :ruleset init)\n  ;;\n  ;;   (run init 1)\n  ;;   (extract (const1))\n  ;;   (extract (const2))\n  ;;   (extract (const3))\n  ;;\n  ;;\n  ;; The idea behind this updated design is to prevent egglog from constantly rebuilding which\n  ;; it does after every top level command. Hence, we wrap the top level bindings into the actions\n  ;; of a rule and make them accessible through their unique constructor. Therefore, we must\n  ;; keep track of the mapping between each binding and its corresponding constructor.\n\n  (define-values (all-bindings extract-bindings)\n    (egglog-add-exprs insert-batch insert-brfs (egglog-runner-ctx runner) subproc))\n\n  (egglog-send subproc\n               `(ruleset run-extract-commands)\n               `(rule () (,@all-bindings) :ruleset run-extract-commands)\n               `(run-schedule (repeat 1 run-extract-commands)))\n\n  ;; 4. Running the schedule : having code inside to emulate egraph-run-rules\n\n  (for ([step (in-list schedule)])\n    (apply egglog-send subproc (egglog-step-commands step pform))\n    (match step\n      ['lift (egglog-send subproc '(run-schedule (saturate lift)))]\n      ['lower (egglog-send subproc '(run-schedule (saturate lower)))]\n      ['unsound (egglog-send subproc '(run-schedule (saturate unsound)))]\n      ;; Run the rewrite ruleset interleaved with const-fold until the best iteration\n      ['rewrite (egglog-unsound-detected-subprocess step subproc)]))\n\n  ;; 5. Extract using constructor names returned by egglog-add-exprs.\n  (define stdout-content\n    (egglog-multi-extract subproc\n                          `(multi-extract ,extract\n                                          ,@(for/list ([constructor-name extract-bindings])\n                                              `(,constructor-name)))))\n\n  ;; Close everything subprocess related\n  (egglog-subprocess-close subproc)\n\n  ;; (Listof (Listof exprs))\n  (define herbie-exprss\n    (for/list ([next-expr (in-list stdout-content)])\n      (map e2->expr next-expr)))\n\n  (for/list ([variants (in-list herbie-exprss)])\n    (for/list ([v (in-list variants)])\n      (batch-add! output-batch v))))\n\n;; Egglog requires integer costs, but Herbie uses floating-point costs.\n;; Scale by 1000 to convert Herbie's float costs to Egglog's integer costs.\n(define (normalize-cost c)\n  (exact-round (* c 1000)))\n\n(define (prelude subproc #:mixed-egraph? [mixed-egraph? #t])\n  (define pform (*active-platform*))\n\n  (egglog-send subproc `(datatype M ,@(platform-spec-nodes)))\n\n  (egglog-send\n   subproc\n   `(datatype MTy\n              ,@(num-typed-nodes pform)\n              ,@(var-typed-nodes pform)\n              (Approx M MTy)\n              ,@(platform-impl-nodes pform))\n   `(constructor do-lower (M String) MTy :unextractable)\n   `(constructor do-lift (MTy) M :unextractable)\n   `(ruleset lower)\n   `(ruleset lift)\n   `(ruleset unsound)\n   `(function bad-merge? () bool :merge (or old new))\n   `(ruleset bad-merge-rule)\n   `(set (bad-merge?) false)\n   `(rule ((= (Num c1) (Num c2)) (!= c1 c2)) ((set (bad-merge?) true)) :ruleset bad-merge-rule))\n\n  (void))\n\n(define (egglog-step-commands step pform)\n  (match step\n    ['lift (append (list (approx-lifting-rule)) (impl-lifting-rules pform) (num-lifting-rules))]\n    ['lower (append (impl-lowering-rules pform) (num-lowering-rules))]\n    ['unsound (egglog-rewrite-rules (*sound-removal-rules*) 'unsound)]\n    ['rewrite\n     (append (list `(ruleset rewrite))\n             (const-fold-rules)\n             (egglog-rewrite-rules (*rules*) 'rewrite))]))\n\n(define (const-fold-rules)\n  `((ruleset const-fold)\n    (let $0 ,(real->bigrat 0)\n      )\n    (let $1 ,(real->bigrat 1)\n      )\n    (rewrite (Add (Num x) (Num y)) (Num (+ x y)) :ruleset const-fold)\n    (rewrite (Sub (Num x) (Num y)) (Num (- x y)) :ruleset const-fold)\n    (rewrite (Mul (Num x) (Num y)) (Num (* x y)) :ruleset const-fold)\n    ; TODO : Non-total operator\n    (rule ((= e (Div (Num x) (Num y))) (!= $0 y)) ((union e (Num (/ x y)))) :ruleset const-fold)\n    (rewrite (Neg (Num x)) (Num (neg x)) :ruleset const-fold)\n    ;; Power rules -> only case missing is 0^0 making it non-total\n    ;; 0^y where y > 0\n    (rule ((= e (Pow (Num x) (Num y))) (= $0 x) (> y $0)) ((union e (Num $0))) :ruleset const-fold)\n    ;; x^0 where x != 0\n    (rule ((= e (Pow (Num x) (Num y))) (= $0 y) (!= $0 x)) ((union e (Num $1))) :ruleset const-fold)\n    ;; x^y when y is a whole number and y > 0 and x != 0\n    (rule ((= e (Pow (Num x) (Num y))) (> y $0) (!= $0 x) (= y (round y)))\n          ((union e (Num (pow x y))))\n          :ruleset\n          const-fold)\n    ;; New rule according to Rust : x^y where y is not a whole number\n    (rule ((= e (Pow (Num x) (Num y))) (> y $0) (!= $0 x) (!= y (round y)))\n          ((union e (Num (pow x (round y)))))\n          :ruleset\n          const-fold)\n    ;; Sqrt rules -> Non-total but egglog implementation handles it\n    (rule ((= e (Sqrt (Num n))) (sqrt n)) ((union e (Num (sqrt n)))) :ruleset const-fold)\n    (rewrite (Log (Num $1)) (Num $0) :ruleset const-fold)\n    (rewrite (Cbrt (Num $1)) (Num $1) :ruleset const-fold)\n    (rewrite (Fabs (Num x)) (Num (abs x)) :ruleset const-fold)\n    (rewrite (Floor (Num x)) (Num (floor x)) :ruleset const-fold)\n    (rewrite (Ceil (Num x)) (Num (ceil x)) :ruleset const-fold)\n    (rewrite (Round (Num x)) (Num (round x)) :ruleset const-fold)))\n\n(define (platform-spec-nodes)\n  (for ([op '(sound-/ sound-log sound-pow)])\n    (hash-set! (id->e1) op (serialize-op op))\n    (hash-set! (e1->id) (serialize-op op) op))\n  (hash-set! (id->e1) 'array 'Array)\n  (hash-set! (e1->id) 'Array 'array)\n  (hash-set! (e1->id) 'Array3 'array)\n  (list* '(Num BigRat :cost 4294967295)\n         '(Var String :cost 4294967295)\n         '(Sound-/ M M M :cost 4294967295)\n         '(Sound-Log M M :cost 4294967295)\n         '(Sound-Pow M M M :cost 4294967295)\n         '(Array M M :cost 4294967295)\n         '(Array3 M M M :cost 4294967295)\n         (for/list ([op (in-list (all-operators))]\n                    #:unless (eq? op 'array))\n           (define arity (length (operator-info op 'itype)))\n           (hash-set! (id->e1) op (serialize-op op))\n           (hash-set! (e1->id) (serialize-op op) op)\n           `(,(serialize-op op) ,@(make-list arity 'M) :cost 4294967295))))\n\n(define (platform-impl-nodes pform)\n  (for/list ([impl (in-list (platform-impls pform))])\n    (define arity (length (impl-info impl 'itype)))\n    (define typed-name (string->symbol (format \"~aTy\" (serialize-impl impl))))\n    (hash-set! (id->e2) impl typed-name)\n    (hash-set! (e2->id) typed-name impl)\n    (define cost (normalize-cost (impl-info impl 'cost)))\n    `(,typed-name ,@(make-list arity 'MTy) :cost ,cost)))\n\n(define (typed-num-id repr-name)\n  (string->symbol (format \"Num~a\" repr-name)))\n\n(define (typed-var-id repr-name)\n  (string->symbol (format \"Var~a\" repr-name)))\n\n(define (num-typed-nodes pform)\n  (for/list ([repr (in-list (all-repr-names))]\n             #:when (not (eq? repr 'bool)))\n    (define cost (normalize-cost (platform-repr-cost pform (get-representation repr))))\n    `(,(typed-num-id repr) BigRat :cost ,cost)))\n\n(define (var-typed-nodes pform)\n  (for/list ([repr (in-list (all-repr-names))])\n    (define cost (normalize-cost (platform-repr-cost pform (get-representation repr))))\n    `(,(typed-var-id repr) String :cost ,cost)))\n\n(define (num-lowering-rules)\n  (for/list ([repr (in-list (all-repr-names))]\n             #:when (not (eq? repr 'bool)))\n    `(rule ((= e (Num n)))\n           ((union (do-lower e ,(symbol->string repr)) (,(typed-num-id repr) n)))\n           :ruleset\n           lower)))\n\n(define (num-lifting-rules)\n  (for/list ([repr (in-list (all-repr-names))]\n             #:when (not (eq? repr 'bool)))\n    `(rule ((= e (,(typed-num-id repr) n))) ((union (do-lift e) (Num n))) :ruleset lift)))\n\n(define (approx-lifting-rule)\n  `(rule ((= e (Approx spec impl))) ((union (do-lift e) spec)) :ruleset lift))\n\n(define (impl-lowering-rules pform)\n  (for/list ([impl (in-list (platform-impls pform))])\n    (define spec-expr (impl-info impl 'spec))\n    `(rule ((= e ,(expr->egglog-spec-serialized spec-expr \"\"))\n            ,@(for/list ([v (in-list (impl-info impl 'vars))]\n                         [vt (in-list (impl-info impl 'itype))])\n                `(= ,(string->symbol (string-append \"t\" (symbol->string v)))\n                    (do-lower ,v ,(symbol->string (representation-name vt))))))\n           ((union (do-lower e ,(symbol->string (representation-name (impl-info impl 'otype))))\n                   (,(string->symbol (string-append (symbol->string (serialize-impl impl)) \"Ty\"))\n                    ,@(for/list ([v (in-list (impl-info impl 'vars))])\n                        (string->symbol (string-append \"t\" (symbol->string v)))))))\n           :ruleset\n           lower)))\n\n(define (impl-lifting-rules pform)\n  (for/list ([impl (in-list (platform-impls pform))])\n    (define spec-expr (impl-info impl 'spec))\n    `(rule ((= e\n               (,(string->symbol (string-append (symbol->string (serialize-impl impl)) \"Ty\"))\n                ,@(impl-info impl 'vars)))\n            ,@(for/list ([v (in-list (impl-info impl 'vars))]\n                         [vt (in-list (impl-info impl 'itype))])\n                `(= ,(string->symbol (string-append \"s\" (symbol->string v))) (do-lift ,v))))\n           ((union (do-lift e) ,(expr->egglog-spec-serialized spec-expr \"s\")))\n           :ruleset\n           lift)))\n\n(define (serialize-spec-op op arity)\n  (match* (op arity)\n    [('array 2) 'Array]\n    [('array 3) 'Array3]\n    [(_ _) (hash-ref (id->e1) op)]))\n\n(define (expr->egglog-spec-serialized expr s)\n  (let loop ([expr expr])\n    (match expr\n      [(? number?) `(Num ,(real->bigrat expr))]\n      [(? symbol?) (string->symbol (string-append s (symbol->string expr)))]\n      [(list op args ...)\n       `(,(if (hash-has-key? (id->e1) op)\n              (serialize-spec-op op (length args))\n              (hash-ref (id->e2) op))\n         ,@(map loop args))])))\n\n(define (serialize-op op)\n  (if (hash-has-key? op-string-names op)\n      (hash-ref op-string-names op)\n      (string->symbol (string-titlecase (symbol->string op)))))\n\n(define (serialize-impl impl)\n  (define impl-split (string-split (symbol->string impl) \".\"))\n  (define op (string->symbol (car impl-split)))\n  (define type\n    (if (null? (cdr impl-split))\n        \"\"\n        (string-join (cdr impl-split) \"\")))\n  (string->symbol (string-append (symbol->string (serialize-op op)) type)))\n\n(define (expr->e1-pattern expr)\n  (let loop ([expr expr])\n    (match expr\n      [(? number?) `(Num ,(real->bigrat expr))]\n      [(? symbol?) expr]\n      [(list op args ...) `(,(serialize-spec-op op (length args)) ,@(map loop args))])))\n\n(define (egglog-rewrite-rules rules tag)\n  (for/list ([rule (in-list rules)]\n             #:when (not (symbol? (rule-input rule))))\n    `(rewrite ,(expr->e1-pattern (rule-input rule))\n              ,(expr->e1-pattern (rule-output rule))\n              :ruleset\n              ,tag)))\n\n(define (egglog-add-exprs batch brfs ctx subproc)\n  (define mappings (build-vector (batch-length batch) values))\n  (define bindings (make-hash))\n  (define vars (make-hash))\n  (define (remap x spec?)\n    (cond\n      [(hash-has-key? vars x)\n       (if spec?\n           (string->symbol (format \"?s~a\" (hash-ref vars x)))\n           (string->symbol (format \"?t~a\" (hash-ref vars x))))]\n      [else (vector-ref mappings x)]))\n\n  ; node -> egglog node binding\n  ; inserts an expression into the e-graph, returning binding variable.\n  (define (insert-node! node n root?)\n    (define binding\n      (if root?\n          (string->symbol (format \"?r~a\" n))\n          (string->symbol (format \"?b~a\" n))))\n    (hash-set! bindings binding node)\n    binding)\n\n  (define root-bindings '())\n  ; Inserting nodes bottom-up\n  (define root-mask (make-vector (batch-length batch) #f))\n\n  ;; Batchref -> Boolean\n  (define spec?\n    (batch-recurse\n     batch\n     (lambda (brf recurse)\n       (define node (deref brf))\n       (match node\n         [(? literal?) #f] ;; If literal, not a spec\n         [(? number?) #t] ;; If number, it's a spec\n         [(? symbol?)\n          #f] ;; If symbol, assume not a spec could be either (find way to distinguish) : PREPROCESS\n         [(hole _ _) #f] ;; If hole, not a spec\n         [(approx _ _) #f] ;; If approx, not a spec\n         [`(if ,cond ,ift ,iff)\n          (recurse cond)] ;; If the condition or any branch is a spec, then this is a spec\n         [(list appl args ...)\n          (if (hash-has-key? (id->e1) appl)\n              #t ;; appl with op -> Is a spec\n              #f)])))) ;; appl impl -> Not a spec\n\n  (for ([brf (in-list brfs)])\n    (vector-set! root-mask (batchref-idx brf) #t))\n  (for ([node (in-batch batch)]\n        [root? (in-vector root-mask)]\n        [n (in-naturals)])\n    (define node*\n      (match node\n        [(literal v repr) `(,(typed-num-id repr) ,(real->bigrat v))]\n        [(? number?) `(Num ,(real->bigrat node))]\n        [(? symbol?) #f]\n        [(approx spec impl) `(Approx ,(remap spec #t) ,(remap impl #f))]\n        [(list impl args ...)\n         `(,(hash-ref (if (spec? (batchref batch n))\n                          (id->e1)\n                          (id->e2))\n                      impl)\n           ,@(for/list ([arg (in-list args)])\n               (remap arg (spec? (batchref batch n)))))]\n\n        [(hole ty spec) `(do-lower ,(remap spec #t) ,(symbol->string ty))]))\n\n    (if node*\n        (vector-set! mappings n (insert-node! node* n root?))\n        (hash-set! vars n node))\n    (when root?\n      (set! root-bindings (cons (vector-ref mappings n) root-bindings))))\n\n  ; Var-lowering-rules\n  (for ([var (in-list (context-vars ctx))]\n        [repr (in-list (context-var-reprs ctx))])\n    (egglog-send subproc\n                 `(rule ((= e (Var ,(symbol->string var))))\n                        ((union (do-lower e ,(symbol->string (representation-name repr)))\n                                (,(typed-var-id (representation-name repr)) ,(symbol->string var))))\n                        :ruleset\n                        lower)))\n\n  ; Var-lifting-rules\n  (for ([var (in-list (context-vars ctx))]\n        [repr (in-list (context-var-reprs ctx))])\n    (egglog-send subproc\n                 `(rule ((= e (,(typed-var-id (representation-name repr)) ,(symbol->string var))))\n                        ((union (do-lift e) (Var ,(symbol->string var))))\n                        :ruleset\n                        lift)))\n\n  (define all-bindings '())\n  (define binding->constructor (make-hash)) ; map from binding name to constructor name\n\n  (define constructor-num 1)\n\n  ; ; Var-spec-bindings\n  (for ([var (in-list (context-vars ctx))])\n    ; Get the binding names for the program\n    (define binding-name (string->symbol (format \"?s~a\" var)))\n    (define constructor-name (string->symbol (format \"const~a\" constructor-num)))\n    (hash-set! binding->constructor binding-name constructor-name)\n\n    ; Define the actual binding\n    (define curr-var-spec-binding `(let ,binding-name (Var ,(symbol->string var))))\n\n    ; Send the constructor definition\n    (egglog-send subproc `(constructor ,constructor-name () M :unextractable))\n\n    ; Add the binding and constructor union to all-bindings for the future rule\n    (set! all-bindings (cons curr-var-spec-binding all-bindings))\n    (set! all-bindings (cons `(union (,constructor-name) ,binding-name) all-bindings))\n\n    (set! constructor-num (add1 constructor-num)))\n\n  ; Var-typed-bindings\n  (for ([var (in-list (context-vars ctx))]\n        [repr (in-list (context-var-reprs ctx))])\n    ; Get the binding names for the program\n    (define binding-name (string->symbol (format \"?t~a\" var)))\n    (define constructor-name (string->symbol (format \"const~a\" constructor-num)))\n    (hash-set! binding->constructor binding-name constructor-name)\n\n    ; Define the actual binding\n    (define curr-var-typed-binding\n      `(let ,binding-name (,(typed-var-id (representation-name repr)) ,(symbol->string var))))\n\n    ; Send the constructor definition\n    (egglog-send subproc `(constructor ,constructor-name () MTy :unextractable))\n\n    ; Add the binding and constructor union to all-bindings for the future rule\n    (set! all-bindings (cons curr-var-typed-binding all-bindings))\n    (set! all-bindings (cons `(union (,constructor-name) ,binding-name) all-bindings))\n\n    (set! constructor-num (add1 constructor-num)))\n\n  ; Binding Exprs\n  (for ([root? (in-vector root-mask)]\n        [n (in-naturals)]\n        #:when (not (hash-has-key? vars n)))\n\n    (define binding-name\n      (if root?\n          (string->symbol (format \"?r~a\" n))\n          (string->symbol (format \"?b~a\" n))))\n\n    (define constructor-name (string->symbol (format \"const~a\" constructor-num)))\n    (hash-set! binding->constructor binding-name constructor-name)\n\n    (define actual-binding (hash-ref bindings binding-name))\n\n    (define curr-datatype\n      (match actual-binding\n        [(cons 'do-lower _) 'MTy]\n        [(cons 'do-lift _) 'M]\n\n        ;; TODO : fix this way of getting spec or impl\n        [_ (if root? 'MTy 'M)]))\n\n    (define curr-binding-exprs `(let ,binding-name ,actual-binding))\n\n    (egglog-send subproc `(constructor ,constructor-name () ,curr-datatype :unextractable))\n\n    (set! all-bindings (cons curr-binding-exprs all-bindings))\n    (set! all-bindings (cons `(union (,constructor-name) ,binding-name) all-bindings))\n\n    (set! constructor-num (add1 constructor-num)))\n\n  (define curr-bindings\n    (for/list ([brf brfs])\n      (define root (batchref-idx brf))\n      (define curr-binding-name\n        (if (hash-has-key? vars root)\n            (if (spec? brf)\n                (string->symbol (format \"?s~a\" (hash-ref vars root)))\n                (string->symbol (format \"?t~a\" (hash-ref vars root))))\n            (string->symbol (format \"?r~a\" root))))\n\n      (hash-ref binding->constructor curr-binding-name)))\n\n  (values (reverse all-bindings) curr-bindings))\n\n(define (egglog-unsound-detected-subprocess tag subproc)\n  (define node-limit (*node-limit*))\n  (define iter-limit (*default-egglog-iter-limit*))\n\n  ;; Use egglog's :until guard with get-size! to stop when node limit is reached.\n  ;; After each iteration, we check for unsound merges via bad-merge-rule.\n  ;; The schedule runs until:\n  ;;   1. Node limit is reached (get-size! >= node-limit)\n  ;;   2. Saturation (no more progress)\n  ;;   3. Iter limit is reached\n  ;;   4. Unsoundness is detected (bad-merge? becomes true)\n\n  (egglog-send subproc\n               `(run-schedule (repeat ,iter-limit\n                                      (seq (run ,tag :until (<= ,node-limit (get-size!)))\n                                           (run const-fold :until (<= ,node-limit (get-size!)))\n                                           (run bad-merge-rule :until (bad-merge?))))))\n  (void))\n\n(define (egglog-num? id)\n  (string-prefix? (symbol->string id) \"Num\"))\n\n(define (egglog-num-repr id)\n  (string->symbol (substring (symbol->string id) 3)))\n\n(define (egglog-var? id)\n  (string-prefix? (symbol->string id) \"Var\"))\n\n(define (e1->expr expr)\n  (match expr\n    [`(Num (bigrat (from-string ,n) (from-string ,d))) (/ (string->number n) (string->number d))]\n    [`(Var ,v) (string->symbol v)]\n    [`(,op ,args ...) `(,(hash-ref (e1->id) op) ,@(map e1->expr args))]))\n\n(define (e2->expr expr)\n  (match expr\n    [`(,(? egglog-num? num) (bigrat (from-string ,n) (from-string ,d)))\n     (literal (/ (string->number n) (string->number d)) (egglog-num-repr num))]\n    [`(,(? egglog-var? var) ,v) (string->symbol v)]\n    ; Approx stores a spec expression in E1/M and an implementation in E2/MTy.\n    [`(Approx ,spec ,impl) (approx (e1->expr spec) (e2->expr impl))]\n    [`(,impl ,args ...) `(,(hash-ref (e2->id) impl) ,@(map e2->expr args))]))\n"
  },
  {
    "path": "src/core/egglog-subprocess.rkt",
    "content": "#lang racket\n\n(require \"../config.rkt\")\n\n(provide (struct-out egglog-subprocess)\n         create-new-egglog-subprocess\n         egglog-send\n         egglog-extract\n         egglog-multi-extract\n         egglog-subprocess-close)\n\n;; Struct to hold egglog subprocess handles\n(struct egglog-subprocess (process output input error dump-file) #:transparent)\n\n;; Close all ports and wait for/kill the subprocess\n(define (egglog-subprocess-close subproc)\n  (close-output-port (egglog-subprocess-input subproc))\n  (close-input-port (egglog-subprocess-output subproc))\n  (subprocess-wait (egglog-subprocess-process subproc))\n  (unless (eq? (subprocess-status (egglog-subprocess-process subproc)) 'done)\n    (subprocess-kill (egglog-subprocess-process subproc) #f)))\n\n;; High-level function that writes the program to a file, runs it then returns output\n;;\n;; If the flag is set to dump the egglog file, creates a new dump file in dump-egglog/ directory\n(define (create-new-egglog-subprocess [label #f])\n  (define egglog-path\n    (or (find-executable-path \"egglog-experimental\")\n        (find-executable-path \"egglog\")\n        (error \"egglog-experimental executable not found in PATH\")))\n\n  (define-values (egglog-process egglog-output egglog-in err)\n    (subprocess #f #f (current-error-port) egglog-path \"--mode=interactive\"))\n\n  ;; Create dump file if flag is set\n  (define dump-file\n    (cond\n      [(flag-set? 'dump 'egglog)\n       (define dump-dir \"dump-egglog\")\n       (unless (directory-exists? dump-dir)\n         (make-directory dump-dir))\n       (define name\n         (for/first ([i (in-naturals)]\n                     #:unless\n                     (file-exists? (build-path dump-dir (format \"~a~a.egg\" (if label label \"\") i))))\n           (build-path dump-dir (format \"~a~a.egg\" (if label label \"\") i))))\n       (open-output-file name #:exists 'replace)]\n      [else #f]))\n\n  (egglog-subprocess egglog-process egglog-output egglog-in err dump-file))\n\n(define (egglog-send subproc . commands)\n  (match-define (egglog-subprocess egglog-process egglog-output egglog-in err dump-file) subproc)\n\n  (when dump-file\n    (for ([expr commands])\n      (pretty-print expr dump-file 1))\n    (flush-output dump-file))\n\n  (for/list ([command (in-list commands)])\n    (writeln command egglog-in)\n    (flush-output egglog-in)\n\n    (let loop ([out '()])\n      (define next (read-line egglog-output))\n      (if (equal? next \"(done)\")\n          (reverse out)\n          (loop (cons next out))))))\n\n;; Send extract commands and read results\n(define (egglog-extract subproc extract-command)\n  (match-define (list \"(\" results ... \")\") (first (egglog-send subproc extract-command)))\n  (for/list ([result (in-list results)])\n    (read (open-input-string result))))\n\n(define (egglog-multi-extract subproc extract-command)\n  (define raw-lines (first (egglog-send subproc extract-command)))\n  (define combined (string-join raw-lines \" \"))\n  (define parsed (read (open-input-string combined)))\n  (for/list ([result-list (in-list parsed)])\n    (for/list ([result (in-list result-list)])\n      result)))\n"
  },
  {
    "path": "src/core/explain.rkt",
    "content": "#lang racket\n\n(require racket/set\n         math/bigfloat\n         math/flonum\n         racket/hash)\n(require \"../utils/common.rkt\"\n         \"../syntax/float.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/syntax.rkt\"\n         \"../syntax/platform.rkt\"\n         \"../syntax/batch.rkt\"\n         \"localize.rkt\"\n         \"points.rkt\"\n         \"programs.rkt\"\n         \"sampling.rkt\")\n\n(provide explain)\n\n(define *top-3* (make-parameter #f))\n\n(define (take-top-n lst)\n  (if (*top-3*)\n      (take-n 3 lst)\n      lst))\n\n(define (take-n n lst)\n  (match lst\n    ['() '()]\n    [(cons x xs)\n     (if (= n 0)\n         '()\n         (cons x (take-n (- n 1) xs)))]))\n\n(define (constant? expr)\n  (cond\n    [(list? expr) (andmap constant? (rest expr))]\n    [(symbol? expr) #f]\n    [else #t]))\n\n(define (actual-errors expr ctx pcontext)\n  (match-define (cons subexprs pt-errorss)\n    (apply map\n           list\n           (hash->list (first (compute-local-errors (list (all-subexpressions expr)) ctx pcontext)))))\n\n  (define pt-worst-subexpr\n    (append* (reap [sow]\n                   (for ([pt-errors (in-list pt-errorss)]\n                         [(pt _) (in-pcontext pcontext)])\n                     (define sub-error (map cons subexprs pt-errors))\n                     (define filtered-sub-error (filter (lambda (p) (> (cdr p) 16)) sub-error))\n                     (define mapped-sub-error (map (lambda (p) (cons (car p) pt)) filtered-sub-error))\n                     (unless (empty? mapped-sub-error)\n                       (sow mapped-sub-error))))))\n\n  (for/hash ([group (in-list (group-by car pt-worst-subexpr))])\n    (define key (caar group))\n    (values key (map cdr group))))\n\n(define (same-sign? a b)\n  (or (and (bfpositive? a) (bfpositive? b)) (and (bfnegative? a) (bfnegative? b))))\n\n(define all-explanations (list 'uflow-rescue 'u/u 'u/n 'o/o 'n/o 'o*u 'u*o 'n*u 'cancellation))\n(define cond-thres (bf 100))\n(define maybe-cond-thres (bf 32))\n\n(define (compile-expr expr ctx)\n  (define subexprs (all-subexpressions expr #:reverse? #t))\n  (define spec-list (map prog->spec subexprs))\n  (define ctxs\n    (for/list ([subexpr (in-list subexprs)])\n      (struct-copy context ctx [repr (repr-of subexpr ctx)])))\n\n  (define repr-hash\n    (make-immutable-hash (map (lambda (e ctx) (cons e (context-repr ctx))) subexprs ctxs)))\n\n  (define-values (batch brfs) (progs->batch spec-list))\n  (define subexprs-fn\n    (parameterize ([*max-mpfr-prec* 128])\n      (eval-progs-real batch brfs ctxs)))\n  (values subexprs repr-hash subexprs-fn))\n\n(define (predict-errors ctx pctx subexprs-list repr-hash subexprs-fn)\n  (define error-count-hash (make-hash (map (lambda (x) (cons x '())) subexprs-list)))\n  (define uflow-hash (make-hash))\n  (define oflow-hash (make-hash))\n\n  (define expls->points (make-hash))\n  (define maybe-expls->points (make-hash))\n\n  (for ([(pt _) (in-pcontext pctx)])\n    (define (silence expr)\n      (define subexprs (all-subexpressions expr #:reverse? #t))\n      (for* ([subexpr (in-list subexprs)]\n             #:when (list? subexpr)\n             [expl (in-list all-explanations)])\n        (define key (cons subexpr expl))\n        (when (hash-has-key? expls->points key)\n          (hash-update! expls->points key (lambda (x) (set-remove x pt))))\n        (when (hash-has-key? maybe-expls->points key)\n          (hash-update! maybe-expls->points key (lambda (x) (set-remove x pt))))))\n\n    (define (mark-erroneous! expr expl)\n      (hash-update! error-count-hash expr (lambda (x) (set-add x pt)))\n      (hash-update! expls->points (cons expr expl) (lambda (x) (set-add x pt)) '()))\n\n    (define (mark-maybe! expr [expl 'sensitivity])\n      (hash-update! maybe-expls->points (cons expr expl) (lambda (x) (set-add x pt)) '()))\n\n    (define exacts (subexprs-fn pt))\n\n    (define exacts-hash (make-immutable-hash (map cons subexprs-list exacts)))\n    (define (exacts-ref subexpr)\n      (define exacts-val (hash-ref exacts-hash subexpr))\n      ((representation-repr->bf (hash-ref repr-hash subexpr)) exacts-val))\n\n    (for/list ([subexpr (in-list subexprs-list)])\n      (define subexpr-val (exacts-ref subexpr))\n\n      (define (update-flow-hash flow-hash pred? . children)\n        (define child-set\n          (foldl (lambda (a b) (hash-union a b #:combine +))\n                 (make-immutable-hash)\n                 (map (lambda (a) (hash-ref flow-hash a (make-immutable-hash))) children)))\n        (define parent-set (hash-ref flow-hash subexpr (make-immutable-hash)))\n        (define parent+child-set (hash-union parent-set child-set #:combine (lambda (_ v) v)))\n        (define new-parent-set\n          (if (and (bigfloat? subexpr-val) (pred? subexpr-val))\n              (hash-update parent+child-set subexpr add1 0)\n              parent+child-set))\n        (hash-set! flow-hash subexpr new-parent-set))\n\n      (match subexpr\n        [(list _ x-ex y-ex z-ex)\n         (update-flow-hash oflow-hash bfinfinite? x-ex y-ex z-ex)\n         (update-flow-hash uflow-hash bfzero? x-ex y-ex z-ex)]\n        [(list _ x-ex y-ex)\n         (update-flow-hash oflow-hash bfinfinite? x-ex y-ex)\n         (update-flow-hash uflow-hash bfzero? x-ex y-ex)]\n        [(list _ x-ex)\n         (update-flow-hash oflow-hash bfinfinite? x-ex)\n         (update-flow-hash uflow-hash bfzero? x-ex)]\n        [_ #f])\n\n      (match subexpr\n        [(list (or '+.f64 '+.f32) x-ex y-ex)\n         #:when (or (list? x-ex) (list? y-ex))\n         (define x (exacts-ref x-ex))\n         (define y (exacts-ref y-ex))\n         (define x+y (bigfloat->flonum (bf+ x y)))\n         (define cond-x (bfabs (bf/ x subexpr-val)))\n         (define cond-y (bfabs (bf/ y subexpr-val)))\n\n         (define x.eps (+ 127 (bigfloat-exponent x)))\n         (define y.eps (+ 127 (bigfloat-exponent y)))\n\n         (cond\n           [(> (- x.eps y.eps) 100) (silence y-ex)]\n           [(> (- y.eps x.eps) 100) (silence x-ex)]\n           [else (void)])\n\n         (cond\n           ; Condition number hallucination\n           ; Both R(x + y) and R(x) + R(y) underflow\n           ; This causes the condition number to jump up,\n           ; with no real error\n           [(and (= x+y 0.0) (bfzero? subexpr-val)) #f]\n\n           ; nan rescue:\n           ; R(+-inf) + R(-+inf) = nan, but should actually\n           ; be inf\n           [(and (bfinfinite? x) (bfinfinite? y) (not (same-sign? x y)) (not (bfnan? subexpr-val)))\n            (mark-erroneous! subexpr 'nan-rescue)]\n\n           ; inf rescue:\n           ; R(inf) + y = non inf value (inf rescue)\n           [(and (bfinfinite? x) (not (bfinfinite? subexpr-val)))\n            (mark-erroneous! subexpr 'oflow-left)]\n           [(and (bfinfinite? y) (not (bfinfinite? subexpr-val)))\n            (mark-erroneous! subexpr 'oflow-right)]\n\n           ; High condition number:\n           ; CN(+, x, y) = |x / x + y|\n           [(or (bf> cond-x cond-thres) (bf> cond-y cond-thres))\n            (mark-erroneous! subexpr 'cancellation)]\n\n           [(or (bf> cond-x maybe-cond-thres) (bf> cond-y maybe-cond-thres))\n            (mark-maybe! subexpr 'cancellation)]\n           [else #f])]\n\n        [(list (or '-.f64 '-.f32) x-ex y-ex)\n         #:when (or (list? x-ex) (list? y-ex))\n         (define x (exacts-ref x-ex))\n         (define y (exacts-ref y-ex))\n         (define x-y (bigfloat->flonum (bf- x y)))\n         (define cond-x (bfabs (bf/ x subexpr-val)))\n         (define cond-y (bfabs (bf/ y subexpr-val)))\n\n         (define x.eps (+ 127 (bigfloat-exponent x)))\n         (define y.eps (+ 127 (bigfloat-exponent y)))\n\n         (cond\n           [(> (- x.eps y.eps) 100) (silence y-ex)]\n           [(> (- y.eps x.eps) 100) (silence x-ex)]\n           [else (void)])\n\n         (cond\n           ; Condition number hallucination:\n           ; When x - y correctly underflows, CN is high\n           ; even though the answer is correct\n           [(and (= x-y 0.0) (bfzero? subexpr-val)) #f]\n\n           ; nan rescue:\n           ; inf - inf = nan but should actually get an inf\n           [(and (bfinfinite? x) (bfinfinite? y) (same-sign? x y) (not (bfnan? subexpr-val)))\n            (mark-erroneous! subexpr 'nan-rescue)]\n\n           ; inf rescue\n           ; If x or y overflow and the other arg rescues\n           ; it\n           [(and (bfinfinite? x) (not (bfinfinite? subexpr-val)))\n            (mark-erroneous! subexpr 'oflow-left)]\n           [(and (bfinfinite? y) (not (bfinfinite? subexpr-val)))\n            (mark-erroneous! subexpr 'oflow-right)]\n\n           ; High condition number:\n           ; CN(+, x, y) = |x / x - y|\n           [(or (bf> cond-x cond-thres) (bf> cond-y cond-thres))\n            (mark-erroneous! subexpr 'cancellation)]\n\n           [(or (bf> cond-x maybe-cond-thres) (bf> cond-y maybe-cond-thres))\n            (mark-maybe! subexpr 'cancellation)]\n           [else #f])]\n\n        [(list (or 'sin.f64 'sin.f32) x-ex)\n         #:when (list? x-ex)\n         (define x (exacts-ref x-ex))\n         (define cot-x (bfabs (bfcot x)))\n         (define cond-no (bf* (bfabs x) cot-x))\n         (cond\n           [(and (bfinfinite? x) (not (bfnan? subexpr-val))) (mark-erroneous! subexpr 'oflow-rescue)]\n           [(and (bf> cond-no cond-thres) (bf> (bfabs x) cond-thres))\n            (mark-erroneous! subexpr 'sensitivity)]\n           [(and (bf> cond-no cond-thres) (bf> cot-x cond-thres))\n            (mark-erroneous! subexpr 'cancellation)]\n\n           [(and (bf> cond-no maybe-cond-thres) (bf> (bfabs x) maybe-cond-thres))\n            (mark-maybe! subexpr 'sensitivity)]\n           [(and (bf> cond-no maybe-cond-thres) (bf> cot-x maybe-cond-thres))\n            (mark-maybe! subexpr 'cancellation)]\n           [else #f])]\n\n        [(list (or 'cos.f64 'cos.f32) x-ex)\n         #:when (list? x-ex)\n         (define x (exacts-ref x-ex))\n         (define cond-no (bfabs (bf* x (bftan x))))\n\n         (cond\n           [(and (bfinfinite? x) (not (bfnan? subexpr-val))) (mark-erroneous! subexpr 'oflow-rescue)]\n           [(bf> cond-no cond-thres) (mark-erroneous! subexpr 'sensitivity)]\n           [(bf> cond-no maybe-cond-thres) (mark-maybe! subexpr 'sensitivity)]\n           [else #f])]\n\n        [(list (or 'tan.f64 'tan.f32) x-ex)\n         #:when (list? x-ex)\n         (define x (exacts-ref x-ex))\n         (define tot-x (bfabs (bf+ (bfcot x) (bftan x))))\n         (define cond-no (bf* (bfabs x) tot-x))\n\n         (cond\n           [(and (bfinfinite? x) (not (bfnan? subexpr-val))) (mark-erroneous! subexpr 'oflow-rescue)]\n           [(and (bf> cond-no cond-thres) (bf> (bfabs x) cond-thres))\n            (mark-erroneous! subexpr 'sensitivity)]\n           [(and (bf> cond-no cond-thres) (bf> tot-x cond-thres))\n            (mark-erroneous! subexpr 'cancellation)]\n\n           [(and (bf> cond-no maybe-cond-thres) (bf> (bfabs x) maybe-cond-thres))\n            (mark-maybe! subexpr 'sensitivity)]\n           [(and (bf> cond-no maybe-cond-thres) (bf> tot-x maybe-cond-thres))\n            (mark-maybe! subexpr 'cancellation)]\n           [else #f])]\n\n        [(list (or 'sqrt.f64 'sqrt.f32) x-ex)\n         #:when (list? x-ex)\n         (define x (exacts-ref x-ex))\n\n         (cond\n           ;; Underflow rescue:\n           [(and (bfzero? x) (not (bf= subexpr-val x))) (mark-erroneous! subexpr 'uflow-rescue)]\n\n           ;; Overflow rescue:\n           [(and (bfinfinite? x) (not (bf= subexpr-val x))) (mark-erroneous! subexpr 'oflow-rescue)])]\n\n        [(list (or 'cbrt.f64 'cbrt.f32) x-ex)\n         #:when (list? x-ex)\n         (define x (exacts-ref x-ex))\n\n         (cond\n           ;; Underflow rescue:\n           [(and (bfzero? x) (not (bf= subexpr-val x))) (mark-erroneous! subexpr 'uflow-rescue)]\n\n           ;; Overflow rescue:\n           [(and (bfinfinite? x) (not (bf= subexpr-val x))) (mark-erroneous! subexpr 'oflow-rescue)])]\n\n        [(list (or '/.f64 '/.f32) x-ex y-ex)\n         #:when (or (list? x-ex) (list? y-ex))\n         (define x (exacts-ref x-ex))\n         (define y (exacts-ref y-ex))\n\n         (cond\n           ;; if the numerator underflows and the denominator:\n           ;; - underflows, nan could be rescued\n           [(and (bfzero? x) (bfzero? y) (not (bfnan? subexpr-val))) (mark-erroneous! subexpr 'u/u)]\n           ;; - is small enough, 0 underflow could be rescued\n           [(and (bfzero? x) (not (bfzero? subexpr-val))) (mark-erroneous! subexpr 'u/n)]\n           ;; - overflows, no rescue is possible\n\n           ;; if the numerator overflows and the denominator:\n           ;; - overflows, nan could be rescued\n           [(and (bfinfinite? x) (bfinfinite? y) (not (bfnan? subexpr-val)))\n            (mark-erroneous! subexpr 'o/o)]\n           ;; - is large enough, inf overflow can be rescued\n           [(and (bfinfinite? x) (not (bfinfinite? subexpr-val))) (mark-erroneous! subexpr 'o/n)]\n           ;; - underflow, no rescue is possible\n\n           ;; if the numerator is normal and the denominator:\n           ;; - overflows, then a rescue is possible\n           [(and (bfinfinite? y) (not (bfzero? subexpr-val))) (mark-erroneous! subexpr 'n/o)]\n           ;; - underflows, then a rescue is possible\n           [(and (bfzero? y) (not (bfinfinite? subexpr-val))) (mark-erroneous! subexpr 'n/u)]\n           ;; - is normal, then no rescue is possible\n           [else #f])]\n\n        [(list (or '*.f64 '*.f32) x-ex y-ex)\n         #:when (or (list? x-ex) [list? y-ex])\n         (define x (exacts-ref x-ex))\n         (define y (exacts-ref y-ex))\n\n         (cond\n           ;; if one operand underflows and the other overflows, then nan must\n           ;; be rescued.\n           [(and (bfinfinite? x) (bfzero? y) (not (bfnan? subexpr-val)))\n            (mark-erroneous! subexpr 'o*u)]\n           [(and (bfzero? x) (bfinfinite? y) (not (bfnan? subexpr-val)))\n            (mark-erroneous! subexpr 'u*o)]\n\n           ;; If one operand is normal and the other overflows then, inf rescue\n           ;; could occur\n           [(and (or (bfinfinite? x) (bfinfinite? y)) (not (bfinfinite? subexpr-val)))\n            (mark-erroneous! subexpr 'n*o)]\n\n           [(and (or (bfzero? x) (bfzero? y)) (not (bfzero? subexpr-val)))\n            (mark-erroneous! subexpr 'n*u)]\n\n           ;; If both normal then no error\n           [else #f])]\n\n        [(list (or 'log.f64 'log.f32) x-ex)\n         #:when (list? x-ex)\n         (define x (exacts-ref x-ex))\n         (define cond-num (bfabs (bf/ 1.bf subexpr-val)))\n         (cond\n           ; Condition number hallucination:\n           ; Condition number is high when x = 1,\n           ; but x is exactly 1, so there is no error\n           ; [(and (bf= x 1.bf) (bfzero? subexpr-val)) #f]\n\n           ; overflow rescue:\n           [(bfinfinite? x) (mark-erroneous! subexpr 'oflow-rescue)]\n\n           ; underflow rescue:\n           [(bfzero? x) (mark-erroneous! subexpr 'uflow-rescue)]\n\n           ; High Condition Number:\n           ; CN(log, x) = |1 / log(x)|\n           [(bf> cond-num cond-thres) (mark-erroneous! subexpr 'sensitivity)]\n\n           [(bf> cond-num maybe-cond-thres) (mark-maybe! subexpr 'sensitivity)]\n\n           [else #f])]\n\n        [(list (or 'exp.f64 'exp.f32) x-ex)\n         #:when (list? x-ex)\n         (define x (exacts-ref x-ex))\n         (define exp-x (bigfloat->flonum (bfexp x)))\n\n         (cond\n           ; Condition Number Hallucination:\n           ; When x is large enough that exp(x) overflows,\n           ; condition number is also high.\n           [(and (infinite? exp-x) (bfinfinite? subexpr-val)) #f]\n\n           ; Condition Number Hallucination:\n           ; When x is large enough (negative) that exp(x)\n           ; underflows, condition number is also high\n           [(and (zero? exp-x) (bfzero? subexpr-val)) #f]\n\n           ; High Condition Number:\n           ; CN(exp, x) = |x|\n           [(bf> (bfabs x) cond-thres) (mark-erroneous! subexpr 'sensitivity)]\n\n           [(bf> (bfabs x) maybe-cond-thres) (mark-maybe! subexpr 'sensitivity)]\n\n           [else #f])]\n\n        ; FIXME need to rework from scratch\n        [(list (or 'pow.f64 'pow.f32) x-ex y-ex)\n         #:when (or (list? x-ex) (list? y-ex))\n         (define x (exacts-ref x-ex))\n         (define y (exacts-ref y-ex))\n         (define x^y (bigfloat->flonum (bfexpt x y)))\n         (define cond-x (bfabs y))\n         (define cond-y (bfabs (bf* y (bflog x))))\n\n         (cond\n           ;; Hallucination:\n           ;; x has a large exponent and y is 1. The ylogx is large but there is\n           ;; no error because the answer is exactly x\n           ;; [(and (bf= y 1.bf)\n           ;; (bf= x subexpr-val)) #f]\n\n           ;; Hallucination:\n           ;; y is large but x is exactly 1\n           ;; [(and (= (bigfloat->flonum x) 1.0)\n           ;; (= (bigfloat->flonum subexpr-val) 1.0))\n           ;; #f]\n\n           ;; Hallucination:\n           ;; y is large but x is zero\n           [(and (bfzero? x) (bfzero? subexpr-val)) #f]\n\n           ;; Hallucination:\n           ;; if x is large enough that x^y overflows, the condition number also\n           ;; is very large, but the answer correctly overflows\n           [(and (bf> y 1.bf) (infinite? x^y) (bfinfinite? subexpr-val)) #f]\n\n           ;; if x is small enough and y is large enough that x^y underflows,\n           ;; the condition number also gets very large, but the answer\n           ;; correctly underflows\n           [(and (bf> y 1.bf) (zero? x^y) (bfzero? subexpr-val)) #f]\n\n           [(and (bf< y -1.bf) (zero? x^y) (bfzero? subexpr-val)) #f]\n\n           [(and (bf< y -1.bf) (infinite? x^y) (bfinfinite? subexpr-val)) #f]\n\n           [(and (bfzero? x) (not (bf= subexpr-val x))) (mark-erroneous! subexpr 'uflow-rescue)]\n\n           [(and (bfinfinite? x) (not (bf= subexpr-val x))) (mark-erroneous! subexpr 'oflow-rescue)]\n\n           [(and (or (bf> cond-x cond-thres) (bf> cond-y cond-thres)) (not (constant? y-ex)))\n            (mark-erroneous! subexpr 'sensitivity)]\n\n           [(and (or (bf> cond-x maybe-cond-thres) (bf> cond-y maybe-cond-thres))\n                 (not (constant? y-ex)))\n            (mark-maybe! subexpr 'sensitivity)]\n\n           [else #f])]\n\n        [(list (or 'acos.f64 'acos.f32) x-ex)\n         #:when (list? x-ex)\n         (define x (exacts-ref x-ex))\n         (define cond-x (bfabs (bf/ x (bf* (bfsqrt (bf- 1.bf (bf* x x))) subexpr-val))))\n\n         (cond\n           ; Condition number hallucinations:\n           ; acos(1) == 0\n           ;; [(and (bf= x 1.bf) (bfzero? subexpr-val)) #f]\n\n           ; acos(-1) == pi\n           ;; [(bf= x -1.bf)  #f]\n\n           ; High Condition Number:\n           ; CN(acos, x) = |x / (√(1 - x^2)acos(x))|\n           [(bf> cond-x cond-thres) (mark-erroneous! subexpr 'sensitivity)]\n\n           [(bf> cond-x maybe-cond-thres) (mark-maybe! subexpr 'sensitivity)]\n\n           [else #f])]\n\n        [(list (or 'asin.f64 'asin.f32) x-ex)\n         #:when (list? x-ex)\n         (define x (exacts-ref x-ex))\n         (define cond-x (bfabs (bf/ x (bf* (bfsqrt (bf- 1.bf (bf* x x))) subexpr-val))))\n\n         (cond\n           ; Condition Number hallucinations:\n           ; asin(1) == pi/2\n           ;; [(bf= (bfabs x) 1.bf) #f]\n           ;; [(and (bfzero? x) (bfzero? subexpr-val)) #f]\n           ; High Condition Number:\n           ; CN(acos, x) = |x / (√(1 - x^2)asin(x))|\n           [(bf> cond-x cond-thres) (mark-erroneous! subexpr 'sensitivity)]\n\n           [(bf> cond-x maybe-cond-thres) (mark-maybe! subexpr 'sensitivity)]\n\n           [else #f])]\n        [_ #f])))\n  (values error-count-hash expls->points maybe-expls->points oflow-hash uflow-hash))\n\n(define (generate-timelines expr\n                            ctx\n                            pctx\n                            error-count-hash\n                            expls->points\n                            maybe-expls->points\n                            oflow-hash\n                            uflow-hash)\n\n  (define tcount-hash (actual-errors expr ctx pctx))\n\n  (define repr (repr-of expr ctx))\n  (define (values->json vs repr)\n    (map (lambda (value) (value->json value repr)) (vector->list vs)))\n\n  (define fperrors\n    (for/list ([subexpr (in-list (set-union (hash-keys tcount-hash) (hash-keys error-count-hash)))])\n      (define pset (hash-ref error-count-hash subexpr '()))\n      (define tset (hash-ref tcount-hash subexpr '()))\n      (define opred (set-subtract pset tset))\n      (define upred (set-subtract tset pset))\n\n      (list (~a subexpr)\n            (length tset)\n            (length opred)\n            (and (not (empty? opred)) (values->json (first opred) repr))\n            (length upred)\n            (and (not (empty? upred)) (values->json (first upred) repr)))))\n\n  (define true-error-hash\n    (for/hash ([(key _) (in-pcontext pctx)]\n               [value (in-flvector (errors expr pctx ctx))])\n      (values key value)))\n\n  (define explanations-table\n    (for/list ([(key val) (in-dict expls->points)]\n               #:unless (empty? val))\n      (define subexpr (car key))\n      (define expl (cdr key))\n      (define err-count (length val))\n      (define maybe-count (length (hash-ref maybe-expls->points key '())))\n      (define flow-list (make-flow-table oflow-hash uflow-hash subexpr expl))\n\n      (define locations (get-locations expr subexpr))\n\n      (list (~a (car subexpr)) (~a subexpr) (~a expl) err-count maybe-count flow-list locations)))\n\n  (define sorted-explanations-table (take-top-n (sort explanations-table > #:key fourth)))\n\n  (define (expls-to-points expls->points)\n    (define expls-points-list (hash->list expls->points))\n    (define sorted-list (sort expls-points-list > #:key (lambda (x) (length (rest x)))))\n    (define points-per-expl-test (map rest sorted-list))\n    (define top-3 (take-top-n points-per-expl-test))\n    (define points-err (apply set-union '() top-3))\n    (for/hash ([point (in-list points-err)])\n      (values point true)))\n\n  (define predicted-total-error (expls-to-points expls->points))\n  (define maybe-predicted-total-error (expls-to-points maybe-expls->points))\n\n  (define confusion-matrix (calculate-confusion true-error-hash predicted-total-error pctx))\n\n  (define maybe-confusion-matrix\n    (calculate-confusion-maybe true-error-hash\n                               predicted-total-error\n                               maybe-predicted-total-error\n                               pctx))\n  (define has-any-error?\n    (for/or ([(pt _) (in-pcontext pctx)])\n      (> (hash-ref true-error-hash pt) 16)))\n  (define predicted-any-error?\n    (for/or ([(pt _) (in-pcontext pctx)])\n      (hash-ref predicted-total-error pt false)))\n  (define maybe-any-error?\n    (for/or ([(pt _) (in-pcontext pctx)])\n      (hash-ref maybe-predicted-total-error pt false)))\n\n  (define total-confusion-matrix\n    (list (if (and has-any-error? predicted-any-error?) 1 0)\n          (if (and has-any-error? (not predicted-any-error?) maybe-any-error?) 1 0)\n          (if (and has-any-error? (not predicted-any-error?) (not maybe-any-error?)) 1 0)\n          (if (and (not has-any-error?) predicted-any-error?) 1 0)\n          (if (and (not has-any-error?) (not predicted-any-error?) maybe-any-error?) 1 0)\n          (if (and (not has-any-error?) (not predicted-any-error?) (not maybe-any-error?)) 1 0)))\n\n  (define points->expl (make-hash))\n\n  (for* ([points (in-dict-values expls->points)]\n         [pt (in-list points)])\n    (hash-update! points->expl pt add1 0))\n\n  (define freqs (make-hash))\n\n  (for ([(pt _) (in-pcontext pctx)])\n    (define freq (hash-ref points->expl pt 0))\n    (hash-update! freqs freq add1 0))\n\n  (values fperrors\n          sorted-explanations-table\n          confusion-matrix\n          maybe-confusion-matrix\n          total-confusion-matrix\n          freqs))\n\n(define (explain expr ctx pctx)\n  (define-values (subexprs-list repr-hash subexprs-fn) (compile-expr expr ctx))\n\n  (define-values (error-count-hash expls->points maybe-expls->points oflow-hash uflow-hash)\n    (predict-errors ctx pctx subexprs-list repr-hash subexprs-fn))\n  (generate-timelines expr\n                      ctx\n                      pctx\n                      error-count-hash\n                      expls->points\n                      maybe-expls->points\n                      oflow-hash\n                      uflow-hash))\n\n(define (flow-list flow-hash expr type)\n  (for/list ([(k v) (in-dict (hash-ref flow-hash expr))])\n    (list (~a k) type v)))\n\n(define (make-flow-table oflow-hash uflow-hash expr expl)\n  (match (list expl expr)\n    [(list 'oflow-rescue _) (flow-list oflow-hash expr \"overflow\")]\n    [(list 'uflow-rescue _) (flow-list uflow-hash expr \"underflow\")]\n    [(list 'u/u (list _ num den))\n     (append (flow-list uflow-hash num \"underflow\") (flow-list uflow-hash den \"underflow\"))]\n    [(list 'u/n (list _ num _)) (flow-list uflow-hash num \"underflow\")]\n    [(list 'o/o (list _ num den))\n     (append (flow-list oflow-hash num \"overflow\") (flow-list oflow-hash den \"overflow\"))]\n    [(list 'o/n (list _ num _)) (flow-list oflow-hash num \"overflow\")]\n    [(list 'n/o (list _ _ den)) (flow-list oflow-hash den \"overflow\")]\n    [(list 'n/u (list _ _ den)) (flow-list uflow-hash den \"underflow\")]\n    [(list 'o*u (list _ left right))\n     (append (flow-list oflow-hash left \"overflow\") (flow-list uflow-hash right \"underflow\"))]\n    [(list 'u*o (list _ left right))\n     (append (flow-list uflow-hash left \"underflow\") (flow-list oflow-hash right \"overflow\"))]\n    [(list 'nan-rescue (list _ left right))\n     (append (flow-list oflow-hash left \"overflow\") (flow-list oflow-hash right \"overflow\"))]\n    [(list 'oflow-left (list left _)) (flow-list oflow-hash left \"overflow\")]\n    [(list 'oflow-right (list _ right)) (flow-list oflow-hash right \"overflow\")]\n    [_ '()]))\n\n(define (calculate-confusion actual-error predicted-error pcontext)\n  (define outcomes\n    (for/list ([(pt _) (in-pcontext pcontext)])\n      (define error-actual? (> (hash-ref actual-error pt) 16))\n      (define error-predicted? (hash-ref predicted-error pt false))\n      #;(when (and error-predicted? (not error-actual?))\n          (eprintf \"~a\\n\" pt))\n      (cons error-actual? error-predicted?)))\n\n  (define groups (group-by identity outcomes))\n  (define counts\n    (for/hash ([group (in-list groups)])\n      (values (first group) (length group))))\n\n  (define true-pos (hash-ref counts '(#t . #t) 0))\n  (define false-pos (hash-ref counts '(#f . #t) 0))\n  (define true-neg (hash-ref counts '(#f . #f) 0))\n  (define false-neg (hash-ref counts '(#t . #f) 0))\n\n  (list true-pos false-neg false-pos true-neg))\n\n(define (calculate-confusion-maybe actual-error predicted-error maybe-error pcontext)\n  (define outcomes\n    (for/list ([(pt _) (in-pcontext pcontext)])\n      (define error-actual? (> (hash-ref actual-error pt) 16))\n      (define error-predicted? (hash-ref predicted-error pt false))\n      (define maybe-error-predicted? (hash-ref maybe-error pt false))\n      (cons error-actual?\n            (cond\n              [error-predicted? 'true]\n              [maybe-error-predicted? 'maybe]\n              [else 'false]))))\n\n  (define groups (group-by identity outcomes))\n  (define counts\n    (for/hash ([group (in-list groups)])\n      (values (first group) (length group))))\n\n  (define true-pos (hash-ref counts '(#t . true) 0))\n  (define false-pos (hash-ref counts '(#f . true) 0))\n  (define false-neg (hash-ref counts '(#t . false) 0))\n  (define true-neg (hash-ref counts '(#f . false) 0))\n  (define true-maybe (hash-ref counts '(#t . maybe) 0))\n  (define false-maybe (hash-ref counts '(#f . maybe) 0))\n\n  (list true-pos true-maybe false-neg false-pos false-maybe true-neg))\n"
  },
  {
    "path": "src/core/localize.rkt",
    "content": "#lang racket\n\n(require math/bigfloat\n         math/flonum\n         racket/hash)\n(require \"../utils/common.rkt\"\n         \"../syntax/float.rkt\"\n         \"../syntax/sugar.rkt\"\n         \"../syntax/syntax.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/platform.rkt\"\n         \"../syntax/batch.rkt\"\n         \"compiler.rkt\"\n         \"points.rkt\"\n         \"programs.rkt\"\n         \"../syntax/rival.rkt\")\n\n(module+ test\n  (require rackunit\n           \"../syntax/syntax.rkt\"\n           \"../syntax/sugar.rkt\"))\n\n(provide compute-local-errors\n         eval-progs-real\n         local-error-as-tree)\n\n(define (eval-progs-real batch brfs ctxs)\n  (define compiler (make-real-compiler batch brfs ctxs))\n  (define bad-pt\n    (for/list ([ctx* (in-list ctxs)])\n      ((representation-bf->repr (context-repr ctx*)) +nan.bf)))\n  (define (<eval-prog-real> pt)\n    (define-values (_ exs) (real-apply compiler pt))\n    (or exs bad-pt))\n  <eval-prog-real>)\n\n;; The local error of an expression f(x, y) is\n;;\n;;   R[f(x, y)] - f(R[x], R[y])\n;;\n;; where the `-` is interpreted as ULP difference and `E` means\n;; exact real evaluation rounded to target repr.\n;;\n;; Local error is high when `f` is highly sensitive to rounding error\n;; in its inputs `x` and `y`.\n\n(define (local-error exact node ulps get-exact)\n  (match node\n    [(? literal?) 1]\n    [(? symbol?) 1]\n    [(approx _ impl) (ulps exact (get-exact impl))]\n    [`(if ,c ,ift ,iff) 1]\n    [(list f args ...)\n     (define argapprox (map get-exact args))\n     (define approx (apply (impl-info f 'fl) argapprox))\n     (ulps exact approx)]))\n\n(define (make-matrix roots pcontext)\n  (for/vector #:length (vector-length roots)\n              ([node (in-vector roots)])\n    (make-vector (pcontext-length pcontext))))\n\n; Compute local error or each sampled point at each node in `prog`.\n(define (compute-local-errors subexprss ctx pcontext)\n  (define exprs-list (append* subexprss)) ; unroll subexprss\n  (define reprs-list (map (curryr repr-of ctx) exprs-list))\n  (define ulps-list (map repr-ulps reprs-list))\n  (define ctx-list\n    (for/list ([subexpr (in-list exprs-list)]\n               [repr (in-list reprs-list)])\n      (struct-copy context ctx [repr repr])))\n\n  (define-values (expr-batch brfs) (progs->batch exprs-list))\n  (define roots (list->vector (map batchref-idx brfs)))\n\n  (define-values (spec-batch spec-brfs) (progs->batch (map prog->spec exprs-list)))\n  (define subexprs-fn (eval-progs-real spec-batch spec-brfs ctx-list))\n\n  (define errs (make-matrix roots pcontext))\n\n  (for ([(pt ex) (in-pcontext pcontext)]\n        [pt-idx (in-naturals)])\n    (define exacts (list->vector (subexprs-fn pt)))\n    (define (get-exact brf)\n      (vector-ref exacts (vector-member (batchref-idx brf) roots)))\n    (for ([expr (in-list exprs-list)]\n          [brf brfs]\n          [ulps (in-list ulps-list)]\n          [exact (in-vector exacts)]\n          [expr-idx (in-naturals)])\n      (define err (local-error exact (deref brf) ulps get-exact))\n      (vector-set! (vector-ref errs expr-idx) pt-idx err)))\n\n  (define n 0)\n  (for/list ([subexprs (in-list subexprss)])\n    (for*/hash ([subexpr (in-list subexprs)])\n      (begin0 (values subexpr (vector->list (vector-ref errs n)))\n        (set! n (add1 n))))))\n\n;; The absolute error of expression `e` is R[e - R[e]].\n;; However, it's possible that R[e] is infinity or NaN;\n;; in this case, computing the absolute error won't work\n;; since those aren't real numbers. To fix this, we replace all\n;; non-finite R[e] with 0.\n(define (remove-infinities pt reprs)\n  (for/vector ([val (in-vector pt)]\n               [repr (in-list reprs)])\n    (define bf-val ((representation-repr->bf repr) val))\n    (if (implies (bigfloat? bf-val) (bfrational? bf-val))\n        val\n        ((representation-bf->repr repr) 0.bf))))\n\n;; Compute local error or each sampled point at each node in `prog`.\n(define (compute-errors subexprss ctx pcontext)\n  ;; We compute the actual (float) result\n  (define exprs-list (append* subexprss)) ; unroll subexprss\n  (define actual-value-fn (compile-progs exprs-list ctx))\n\n  ;; And the real result\n  (define spec-list (map prog->spec exprs-list))\n  (define reprs-list (map (curryr repr-of ctx) exprs-list))\n  (define ulps-list (map repr-ulps reprs-list))\n  (define ctx-list\n    (for/list ([subexpr (in-list exprs-list)]\n               [repr (in-list reprs-list)])\n      (struct-copy context ctx [repr repr])))\n  (define-values (spec-batch spec-brfs) (progs->batch spec-list))\n  (define subexprs-fn (eval-progs-real spec-batch spec-brfs ctx-list))\n\n  ;; And the absolute difference between the two\n  (define exact-var-names\n    (for/list ([expr (in-list exprs-list)])\n      (gensym 'exact)))\n  (define delta-ctx\n    (context (append (context-vars ctx) exact-var-names)\n             (get-representation 'binary64)\n             (append (context-var-reprs ctx) reprs-list)))\n  (define compare-specs\n    (for/list ([spec (in-list spec-list)]\n               [expr (in-list exprs-list)]\n               [repr (in-list reprs-list)]\n               [var (in-list exact-var-names)])\n      (match (representation-type repr)\n        ['bool 0] ; We can't subtract booleans so ignore them\n        ['real `(fabs (- ,spec ,var))]\n        [_ 0])))\n  (define-values (compare-batch compare-brfs) (progs->batch compare-specs))\n  (define delta-fn (eval-progs-real compare-batch compare-brfs (map (const delta-ctx) compare-specs)))\n\n  (define-values (expr-batch brfs) (progs->batch exprs-list))\n  (define roots (list->vector (map batchref-idx brfs)))\n\n  (define ulp-errs (make-matrix roots pcontext))\n  (define exacts-out (make-matrix roots pcontext))\n  (define approx-out (make-matrix roots pcontext))\n  (define true-error-out (make-matrix roots pcontext))\n\n  (define spec-vec (list->vector spec-list))\n  (define ctx-vec (list->vector ctx-list))\n  (for ([(pt ex) (in-pcontext pcontext)]\n        [pt-idx (in-naturals)])\n\n    (define exacts (list->vector (subexprs-fn pt)))\n    (define (get-exact brf)\n      (vector-ref exacts (vector-member (batchref-idx brf) roots)))\n\n    (define actuals (actual-value-fn pt))\n    (define pt* (vector-append pt (remove-infinities actuals reprs-list)))\n    (define deltas (list->vector (delta-fn pt*)))\n\n    (for ([ulps (in-list ulps-list)]\n          [brf brfs]\n          [exact (in-vector exacts)]\n          [actual (in-vector actuals)]\n          [delta (in-vector deltas)]\n          [expr-idx (in-naturals)])\n      (define ulp-err (local-error exact (deref brf) ulps get-exact))\n      (vector-set! (vector-ref exacts-out expr-idx) pt-idx exact)\n      (vector-set! (vector-ref approx-out expr-idx) pt-idx actual)\n      (vector-set! (vector-ref ulp-errs expr-idx) pt-idx ulp-err)\n      (vector-set! (vector-ref true-error-out expr-idx) pt-idx delta)))\n\n  (define n 0)\n  (for/list ([subexprs (in-list subexprss)])\n    (for*/hash ([subexpr (in-list subexprs)])\n      (begin0 (values subexpr\n                      (hasheq 'ulp-errs\n                              (vector->list (vector-ref ulp-errs n))\n                              'exact-values\n                              (vector->list (vector-ref exacts-out n))\n                              'approx-values\n                              (vector->list (vector-ref approx-out n))\n                              'absolute-error\n                              (vector->list (vector-ref true-error-out n))))\n        (set! n (add1 n))))))\n\n(define (expr-fpcore-operator expr ctx)\n  (match (prog->fpcore expr ctx)\n    [(list '! props ... (list op args ...)) op]\n    [(list op args ...) op]\n    [(? number? c) (exact->inexact c)]\n    [(? symbol? c) c]))\n\n(define (expr->json-tree expr ctx decorate)\n  (define (make-json-tree subexpr)\n    (define args\n      (if (list? subexpr)\n          (rest subexpr)\n          '()))\n    (hash-union\n     (hasheq 'e (~s (expr-fpcore-operator subexpr ctx)) 'children (map make-json-tree args))\n     (decorate subexpr)))\n  (make-json-tree expr))\n\n;; Compute the local error of every subexpression of `prog`\n;; and returns the error information as an S-expr in the\n;; same shape as `prog`\n(define (local-error-as-tree expr ctx pcontext)\n  (define data-hash (first (compute-errors (list (all-subexpressions expr)) ctx pcontext)))\n\n  (define (translate-booleans value)\n    (match value\n      [#t 'true]\n      [#f 'false]\n      [v v]))\n\n  (define (expr-data expr)\n    (define data (hash-ref data-hash expr))\n    (define abs-error (~s (first (hash-ref data 'absolute-error))))\n    (define ulp-error (~s (ulps->bits (first (hash-ref data 'ulp-errs))))) ; unused by Odyssey\n    (define ulp-errs (hash-ref data 'ulp-errs))\n    (define avg-error\n      (format-bits (errors-score (for/flvector #:length (length ulp-errs)\n                                               ([err (in-list ulp-errs)])\n                                               (ulps->bits err)))))\n    (define exact-error (~s (translate-booleans (first (hash-ref data 'exact-values)))))\n    (define actual-error (~s (translate-booleans (first (hash-ref data 'approx-values)))))\n    (define percent-accurate\n      (cond\n        [(nan? (first (hash-ref data 'absolute-error)))\n         'invalid] ; HACK: should specify if invalid or unsamplable\n        [else\n         (define repr (repr-of expr ctx))\n         (define total-bits (representation-total-bits repr))\n         (define bits-error (ulps->bits (first (hash-ref data 'ulp-errs))))\n         (* 100 (- 1 (/ bits-error total-bits)))]))\n    (hasheq 'ulps-error\n            ulp-error\n            'avg-error\n            avg-error\n            'exact-value\n            exact-error\n            'actual-value\n            actual-error\n            'percent-accuracy\n            (~s percent-accurate)\n            'abs-error-difference\n            (match (first (hash-ref data 'absolute-error))\n              [(? zero?) \"equal\"]\n              [(? nan?) \"invalid\"]\n              [_ abs-error])))\n\n  (expr->json-tree expr ctx expr-data))\n"
  },
  {
    "path": "src/core/mainloop.rkt",
    "content": "#lang racket\n\n(require \"../config.rkt\"\n         \"../core/alternative.rkt\"\n         \"../utils/common.rkt\"\n         \"../utils/timeline.rkt\"\n         \"../syntax/platform.rkt\"\n         \"../syntax/syntax.rkt\"\n         \"../syntax/types.rkt\"\n         \"alt-table.rkt\"\n         \"bsearch.rkt\"\n         \"../syntax/batch.rkt\"\n         \"derivations.rkt\"\n         \"patch.rkt\"\n         \"points.rkt\"\n         \"compiler.rkt\"\n         \"preprocess.rkt\"\n         \"programs.rkt\"\n         \"regimes.rkt\"\n         \"batch-reduce.rkt\")\n\n(provide run-improve!\n         sort-alts)\n\n;; The Herbie main loop goes through a simple iterative process:\n;;\n;; - Choose all unfinished candidates\n;; - Generating new candidates based on them\n;; - Evaluate all the new and old candidates and prune to the best\n;;\n;; Each stage is stored in this global variable for REPL debugging.\n\n(define/reset ^table^ #f)\n\n;; Starting program for the current run\n(define *start-brf* (make-parameter #f))\n(define *pcontext* (make-parameter #f))\n(define *preprocessing* (make-parameter '()))\n\n(define *global-batch* (make-parameter #f))\n\n;; These high-level functions give the high-level workflow of Herbie:\n;; - Initial steps: explain, preprocessing, initialize the alt table\n;; - the loop: choose some alts, localize, run the patch table, and finalize\n;; - Final steps: regimes, derivations, and remove preprocessing\n\n(define (run-improve! initial specification context pcontext)\n  (timeline-event! 'preprocess)\n  (define preprocessing\n    (if (flag-set? 'setup 'preprocess)\n        (find-preprocessing specification context)\n        '()))\n  (timeline-push! 'symmetry (map ~a preprocessing))\n  (define pcontext* (preprocess-pcontext context pcontext preprocessing))\n  (*pcontext* pcontext*)\n\n  (parameterize ([*global-batch* (batch-empty)])\n    (define global-spec-batch (batch-empty))\n    (define spec-reducer (batch-reduce global-spec-batch))\n\n    (*preprocessing* preprocessing)\n    (define initial-brf (batch-add! (*global-batch*) initial))\n    (*start-brf* initial-brf)\n    (define start-alt (alt initial-brf 'start '()))\n    (^table^ (make-alt-table (*global-batch*) pcontext start-alt context))\n\n    (for ([_ (in-range (*num-iterations*))]\n          #:break (atab-completed? (^table^)))\n      (run-iteration! global-spec-batch spec-reducer))\n    (define alternatives (extract!))\n    (timeline-event! 'preprocess)\n    (for/list ([altn alternatives])\n      (define expr (alt-expr altn))\n      (define expr* (compile-useful-preprocessing expr context pcontext (*preprocessing*)))\n      (alt expr* 'add-preprocessing (list altn)))))\n\n(define (extract!)\n  (timeline-push-alts! '())\n  (define all-alts (atab-all-alts (^table^)))\n  (define joined-alts (make-regime! (*global-batch*) all-alts (*start-brf*)))\n  (define annotated-alts (add-derivations! joined-alts))\n  (define unbatched-alts (unbatchify-alts (*global-batch*) annotated-alts))\n\n  (timeline-push! 'stop (if (atab-completed? (^table^)) \"done\" \"fuel\") 1)\n  (map car (sort-alts unbatched-alts)))\n\n;; The rest of the file is various helper / glue functions used by\n;; Herbie. These often wrap other Herbie components, but add logging\n;; and timeline data.\n\n(define (dump-intermediates! batch altns)\n  (define dump-dir \"dump-intermediates\")\n  (unless (directory-exists? dump-dir)\n    (make-directory dump-dir))\n  (define name\n    (for/first ([i (in-naturals)]\n                #:unless (file-exists? (build-path dump-dir (format \"~a.rktd\" i))))\n      (build-path dump-dir (format \"~a.rktd\" i))))\n  (define exprs (batch-exprs batch))\n  (call-with-output-file name\n                         #:exists 'replace\n                         (lambda (out)\n                           (for ([altn (in-list altns)])\n                             (writeln (exprs (alt-expr altn)) out)))))\n\n(define (batch-score-alts altns)\n  (map errors-score (batch-errors (*global-batch*) (map alt-expr altns) (*pcontext*) (*context*))))\n\n(define (timeline-push-alts! next-alts)\n  (define pending-alts (atab-not-done-alts (^table^)))\n  (define active-alts (atab-active-alts (^table^)))\n  (define scores (batch-score-alts active-alts))\n  (define batch-jsexpr (batch->jsexpr (*global-batch*) (map alt-expr active-alts)))\n  (define roots (hash-ref batch-jsexpr 'roots))\n  (define repr (context-repr (*context*)))\n  (timeline-push! 'batch batch-jsexpr)\n  (for ([alt (in-list active-alts)]\n        [score (in-list scores)]\n        [root (in-list roots)])\n    (timeline-push! 'alts\n                    root\n                    (cond\n                      [(set-member? next-alts alt) \"next\"]\n                      [(set-member? pending-alts alt) \"fresh\"]\n                      [else \"done\"])\n                    score\n                    (~a (representation-name repr)))))\n\n(define (set-intersect-size keys set)\n  (for/sum ([key (in-list keys)] #:when (set-member? set key)) 1))\n\n(define (expr-recurse-impl expr f)\n  (match expr\n    [(approx _ impl) (f impl)]\n    [_ (expr-recurse expr f)]))\n\n;; Converts a patch to full alt with valid history\n(define (reconstruct! starting-alts new-alts)\n  (timeline-event! 'reconstruct)\n\n  (define (group-equivalent-alts alts)\n    (define fn (compile-batch (*global-batch*) (map alt-expr alts) (*context*)))\n    (define signatures (make-vector (length alts) '()))\n    (define batch-cost (alt-batch-costs (*global-batch*) (*context*)))\n\n    (for ([pt (in-vector (pcontext-points (*pcontext*)))])\n      (define outs (fn pt))\n      (for ([out (in-vector outs)]\n            [idx (in-naturals)])\n        (vector-set! signatures idx (cons out (vector-ref signatures idx)))))\n\n    (define (best-alt alt1 alt2)\n      (define cost1 (batch-cost (alt-expr alt1)))\n      (define cost2 (batch-cost (alt-expr alt2)))\n      (if (or (< cost1 cost2) (and (= cost1 cost2) (expr<? (alt-expr alt1) (alt-expr alt2))))\n          alt1\n          alt2))\n\n    (define groups (make-hash))\n    (for ([altn (in-list alts)]\n          [signature (in-vector signatures)])\n      (define key (cons (get-starting-expr altn) signature))\n      (hash-update! groups key (curry best-alt altn) altn))\n\n    (hash-values groups))\n\n  (define (compute-referrers parents root)\n    (define seen (mutable-seteq))\n    (define (recurse! cur)\n      (unless (set-member? seen cur)\n        (set-add! seen cur)\n        (for-each recurse! (vector-ref parents cur))))\n    (recurse! (batchref-idx root))\n    seen)\n\n  (define (reconstruct-alt altn orig can-refer)\n    (define (loop altn)\n      (match altn\n        [(alt start-expr 'patch '()) (values orig start-expr)]\n        [(alt cur-expr event (list prev))\n         (define-values (prev-altn start-expr) (loop prev))\n         (define event*\n           (match event\n             [(list 'evaluate) (list 'evaluate start-expr)]\n             [(list 'taylor name var) (list 'taylor start-expr name var)]\n             [(list 'rr input proof) (list 'rr (alt-expr prev) cur-expr input proof)]))\n         (define expr* (batch-replace-subexpr batch (alt-expr orig) start-expr cur-expr can-refer))\n         (values (alt expr* event* (list prev-altn)) start-expr)]))\n    (define-values (result-alt _) (loop altn))\n    result-alt)\n\n  (define batch (*global-batch*))\n  (define parents (make-vector (batch-length batch) '()))\n  (define (walk-body brf recurse)\n    (define idx (batchref-idx brf))\n    (expr-recurse-impl (deref brf)\n                       (lambda (child)\n                         (define child-idx (batchref-idx child))\n                         (vector-set! parents child-idx (cons idx (vector-ref parents child-idx)))\n                         (recurse child)))\n    (void))\n  (for-each (batch-recurse batch walk-body) (map alt-expr starting-alts))\n  (define new-alts* (group-equivalent-alts new-alts))\n  (timeline-push! 'count (length new-alts) (length new-alts*))\n  (define grouped-alts (group-by get-starting-expr new-alts*))\n\n  (remove-duplicates\n   (for*/list ([start-alts (in-list grouped-alts)]\n               [can-refer (in-value (compute-referrers parents (get-starting-expr (car start-alts))))]\n               [altn (in-list start-alts)]\n               [full-altn (in-list starting-alts)]\n               #:when (set-member? can-refer (batchref-idx (alt-expr full-altn))))\n     (reconstruct-alt altn full-altn can-refer))\n   #:key (compose batchref-idx alt-expr)))\n\n;; Finish iteration\n(define (finalize-iter! picked-alts patched)\n  (when (flag-set? 'dump 'intermediates)\n    (dump-intermediates! (*global-batch*) patched))\n  (timeline-event! 'eval)\n  (define orig-all-alts (atab-active-alts (^table^)))\n  (define orig-fresh-alts (atab-not-done-alts (^table^)))\n  (define orig-done-alts (set-subtract orig-all-alts (atab-not-done-alts (^table^))))\n\n  (define-values (errss costs) (atab-eval-altns (^table^) (*global-batch*) patched (*context*)))\n  (timeline-event! 'prune)\n  (^table^ (atab-add-altns (^table^) patched errss costs (*context*)))\n  (define final-fresh-set (list->seteq (atab-not-done-alts (^table^))))\n  (define final-active-set (list->seteq (atab-active-alts (^table^))))\n  (define final-done-set (set-subtract final-active-set final-fresh-set))\n  (timeline-push! 'count\n                  (+ (length patched) (length orig-fresh-alts) (length orig-done-alts))\n                  (+ (set-count final-fresh-set) (set-count final-done-set)))\n\n  (define data\n    (hash 'new\n          (list (length patched) (set-intersect-size patched final-fresh-set))\n          'fresh\n          (list (length orig-fresh-alts) (set-intersect-size orig-fresh-alts final-fresh-set))\n          'done\n          (list (- (length orig-done-alts) (length picked-alts))\n                (- (set-intersect-size orig-done-alts final-done-set)\n                   (set-intersect-size picked-alts final-done-set)))\n          'picked\n          (list (length picked-alts) (set-intersect-size picked-alts final-done-set))))\n  (timeline-push! 'kept data)\n\n  (define repr (context-repr (*context*)))\n  (timeline-push! 'min-error\n                  (errors-score (atab-min-errors (^table^)))\n                  (format \"~a\" (representation-name repr)))\n  (void))\n\n(define (run-iteration! global-spec-batch spec-reducer)\n  (define pending-alts (atab-not-done-alts (^table^)))\n  (timeline-push-alts! pending-alts)\n  (^table^ (atab-set-picked (^table^) pending-alts))\n\n  (define brfs (map alt-expr pending-alts))\n  (define brfs* (batch-reachable (*global-batch*) brfs #:condition node-is-impl?))\n\n  (define results (generate-candidates (*global-batch*) brfs* global-spec-batch spec-reducer))\n  (define patched (reconstruct! pending-alts results))\n  (finalize-iter! pending-alts patched)\n  (void))\n\n(define (make-regime! batch alts start-prog)\n  (define ctx (*context*))\n  (define repr (context-repr ctx))\n  (define alt-costs (alt-batch-costs batch ctx))\n\n  (cond\n    [(and (flag-set? 'reduce 'regimes)\n          (> (length alts) 1)\n          (equal? (representation-type repr) 'real)\n          (not (null? (context-vars ctx)))\n          (get-fpcore-impl 'if '() (list <bool> repr repr))\n          (get-fpcore-impl '<= '() (list repr repr)))\n     (define opts\n       (pareto-regimes batch\n                       (sort alts < #:key (compose alt-costs alt-expr))\n                       start-prog\n                       ctx\n                       (*pcontext*)))\n     (for/list ([opt (in-list opts)])\n       (match-define (option splitindices opt-alts _ brf) opt)\n       (timeline-event! 'bsearch)\n       (define exprs (batch-exprs batch))\n       (define branch-expr (exprs brf))\n       (define use-binary?\n         (and (flag-set? 'reduce 'binary-search)\n              (> (length splitindices) 1)\n              (critical-subexpression? (exprs start-prog) branch-expr)\n              (for/and ([alt (in-list opt-alts)])\n                (critical-subexpression? (exprs (alt-expr alt)) branch-expr))))\n       (cond\n         [(= (length splitindices) 1) (list-ref opt-alts (si-cidx (first splitindices)))]\n         [use-binary? (combine-alts/binary batch opt start-prog ctx (*pcontext*))]\n         [else (combine-alts batch opt ctx)]))]\n    [else\n     (define scores (batch-score-alts alts))\n     (list (cdr (argmin car (map (λ (a s) (cons s a)) alts scores))))]))\n\n(define (add-derivations! alts)\n  (cond\n    [(flag-set? 'generate 'proofs)\n     (timeline-event! 'derivations)\n     (add-derivations alts)]\n    [else alts]))\n\n(define (sort-alts alts [errss (exprs-errors (map alt-expr alts) (*pcontext*) (*context*))])\n  ;; sort everything by error + cost\n  (define repr (context-repr (*context*)))\n  (define alts-to-be-sorted (map cons alts errss))\n  (sort alts-to-be-sorted\n        (lambda (x y)\n          (or (< (errors-score (cdr x)) (errors-score (cdr y))) ; sort by error\n              (and (equal? (errors-score (cdr x))\n                           (errors-score (cdr y))) ; if error is equal sort by cost\n                   (< (alt-cost (car x) repr) (alt-cost (car y) repr)))))))\n"
  },
  {
    "path": "src/core/patch.rkt",
    "content": "#lang racket\n\n(require \"../syntax/platform.rkt\"\n         \"../syntax/syntax.rkt\"\n         \"../syntax/types.rkt\"\n         \"../core/alternative.rkt\"\n         \"../utils/common.rkt\"\n         \"../syntax/float.rkt\"\n         \"../utils/timeline.rkt\"\n         \"../syntax/batch.rkt\"\n         \"egg-herbie.rkt\"\n         \"egglog-herbie.rkt\"\n         \"programs.rkt\"\n         \"rules.rkt\"\n         \"../syntax/rival.rkt\"\n         \"taylor.rkt\")\n\n(provide generate-candidates\n         get-starting-expr)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;; Taylor ;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define transforms-to-try\n  (let ([invert-x (λ (x) `(/ 1 ,x))]\n        [exp-x (λ (x) `(exp ,x))]\n        [log-x (λ (x) `(log ,x))]\n        [ninvert-x (λ (x) `(/ 1 (neg ,x)))])\n    `((0 ,identity ,identity) (inf ,invert-x ,invert-x)\n                              (-inf ,ninvert-x ,ninvert-x)\n                              #;(exp ,exp-x ,log-x)\n                              #;(log ,log-x ,exp-x))))\n\n(define (taylor-alts altns global-batch spec-batch reducer)\n  (define vars\n    (for/list ([var (in-list (context-vars (*context*)))]\n               #:when (equal? (representation-type (context-lookup (*context*) var)) 'real))\n      var))\n  (define brfs (map alt-expr altns))\n  (define reprs (map (batch-reprs global-batch (*context*)) brfs))\n  ;; Specs\n  (define spec-brfs (batch-to-spec! global-batch brfs)) ;; These specs will go into (approx spec impl)\n  (define free-vars (map (batch-free-vars global-batch) spec-brfs))\n  (define spec-brfs*\n    (map (batch-copy-only! spec-batch global-batch)\n         spec-brfs)) ;; copy from global-batch to spec-batch\n  (define copier (batch-copy-only! global-batch spec-batch)) ;; copy from spec-batch to global-batch\n\n  (reap [sow]\n        (parameterize ([reduce reducer] ;; reduces over spec-batch\n                       [add (λ (x) (batch-add! spec-batch x))]) ;; adds to spec-batch\n          ;; Zero expansion\n          (for ([spec-brf (in-list spec-brfs)]\n                [repr (in-list reprs)]\n                [altn (in-list altns)]\n                #:unless (array-representation? repr))\n            (define genexpr0 (batch-add! global-batch 0))\n            (define gen0 (approx spec-brf (hole (representation-name repr) genexpr0)))\n            (define brf0 (batch-add! global-batch gen0))\n            (sow (alt brf0 `(taylor zero undef-var) (list altn))))\n\n          ;; Taylor expansions\n          ;; List<List<(cons offset coeffs)>>\n          (define taylor-coeffs (taylor-coefficients spec-batch spec-brfs* vars transforms-to-try))\n          (define idx 0)\n          (for* ([var (in-list vars)]\n                 [transform-type transforms-to-try])\n            (match-define (list name f finv) transform-type)\n            (define timeline-stop! (timeline-start! 'series (~a var) (~a name)))\n            (define taylor-coeffs* (list-ref taylor-coeffs idx))\n            (define genexprs (approximate taylor-coeffs* spec-batch var #:transform (cons f finv)))\n            (for ([genexpr (in-list genexprs)]\n                  [spec-brf (in-list spec-brfs)]\n                  [repr (in-list reprs)]\n                  [altn (in-list altns)]\n                  [fv (in-list free-vars)]\n                  #:when (set-member? fv var)) ;; check whether var exists in expr at all\n              (for ([i (in-range (*taylor-order-limit*))])\n                ;; adding a new expansion to the global batch\n                (define gen (approx spec-brf (hole (representation-name repr) (copier (genexpr)))))\n                (define brf (batch-add! global-batch gen))\n                (sow (alt brf `(taylor ,name ,var) (list altn)))))\n            (set! idx (add1 idx))\n            (timeline-stop!)))))\n\n(define (run-taylor altns global-batch spec-batch reducer)\n  (timeline-event! 'series)\n  (define (key x)\n    (define expr (deref (alt-expr x)))\n    (if (approx? expr)\n        (approx-impl expr)\n        expr))\n\n  (define approxs (remove-duplicates (taylor-alts altns global-batch spec-batch reducer) #:key key))\n  (define approxs* (remove-duplicates (run-lowering approxs global-batch) #:key key))\n\n  (timeline-push! 'inputs (batch->jsexpr global-batch (map alt-expr altns)))\n  (timeline-push! 'outputs (batch->jsexpr global-batch (map alt-expr approxs*)))\n  (timeline-push! 'count (length altns) (length approxs*))\n  approxs*)\n\n(define (run-lowering altns global-batch)\n  (define schedule '(lower))\n\n  ; run egg\n  (define brfs (map alt-expr altns))\n  (define reprs (map (batch-reprs global-batch (*context*)) brfs))\n\n  (define runner\n    (cond\n      [(flag-set? 'generate 'egglog)\n       (define batch* (batch-empty))\n       (define copy-f (batch-copy-only! batch* global-batch))\n       (define brfs* (map copy-f brfs))\n       (make-egglog-runner batch* brfs* reprs schedule (*context*))]\n      [else (make-egraph global-batch brfs reprs schedule (*context*))]))\n\n  (define batchrefss\n    (if (flag-set? 'generate 'egglog)\n        (run-egglog runner global-batch 'taylor #:extract 1)\n        (egraph-best runner global-batch)))\n\n  ; apply changelists\n  (reap [sow]\n        (for ([batchrefs (in-list batchrefss)]\n              [altn (in-list altns)])\n          (for ([batchref* (in-list batchrefs)])\n            (sow (alt batchref* (list 'rr runner #f) (list altn)))))))\n\n(define (run-evaluate altns global-batch)\n  (timeline-event! 'sample)\n  (define all-brfs (map alt-expr altns))\n  (define spec-brfs (batch-to-spec! global-batch all-brfs))\n  (define free-vars (batch-free-vars global-batch))\n  (define repr-of (batch-reprs global-batch (*context*)))\n  (define real-pairs\n    (for/list ([altn (in-list altns)]\n               [spec-brf (in-list spec-brfs)]\n               #:when (set-empty? (free-vars spec-brf))\n               #:unless (literal? (deref (alt-expr altn)))\n               #:when (equal? (representation-type (repr-of (alt-expr altn))) 'real))\n      (cons altn spec-brf)))\n  (define real-altns (map car real-pairs))\n  (define real-spec-brfs (map cdr real-pairs))\n\n  (define brfs (map alt-expr real-altns))\n  (define reprs (map repr-of brfs))\n  (define contexts\n    (for/list ([repr (in-list reprs)])\n      (context '() repr '())))\n\n  (define-values (status pts)\n    (if (null? real-spec-brfs)\n        (values 'invalid #f)\n        (let ([real-compiler (make-real-compiler global-batch real-spec-brfs contexts)])\n          (real-apply real-compiler (vector)))))\n  (define literals\n    (for/list ([pt (in-list (if (equal? status 'valid)\n                                pts\n                                '()))]\n               [ctx (in-list contexts)]\n               #:when (equal? status 'valid))\n      (define repr (context-repr ctx))\n      (literal (repr->real pt repr) (representation-name repr))))\n\n  (define final-altns\n    (for/list ([literal (in-list literals)]\n               [altn (in-list real-altns)]\n               #:when (equal? status 'valid))\n      (define brf (batch-add! global-batch literal))\n      (alt brf '(evaluate) (list altn))))\n\n  (timeline-push! 'inputs (batch->jsexpr global-batch real-spec-brfs))\n  (timeline-push! 'outputs (map ~a literals))\n  final-altns)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;; Recursive Rewrite ;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define (run-rr altns global-batch)\n  (timeline-event! 'rewrite)\n\n  ; egg schedule (4-phases for mathematical rewrites, sound-X removal, and implementation selection)\n  (define schedule '(lift rewrite unsound lower))\n\n  (define brfs (map alt-expr altns))\n  (define reprs (map (batch-reprs global-batch (*context*)) brfs))\n\n  (define runner\n    (cond\n      [(flag-set? 'generate 'egglog)\n       (define batch* (batch-empty))\n       (define copy-f (batch-copy-only! batch* global-batch))\n       (define brfs* (map copy-f brfs))\n       (make-egglog-runner batch* brfs* reprs schedule (*context*))]\n      [else (make-egraph global-batch brfs reprs schedule (*context*))]))\n\n  (define batchrefss\n    (if (flag-set? 'generate 'egglog)\n        (run-egglog runner global-batch 'rewrite #:extract 1000000) ; \"infinity\"\n        (egraph-variations runner global-batch)))\n\n  ; apply changelists\n  (define rewritten\n    (reap [sow]\n          (for ([batchrefs (in-list batchrefss)]\n                [altn (in-list altns)])\n            (for ([batchref* (in-list batchrefs)])\n              (sow (alt batchref* (list 'rr runner #f) (list altn)))))))\n\n  (timeline-push! 'inputs (batch->jsexpr global-batch (map alt-expr altns)))\n  (timeline-push! 'outputs (batch->jsexpr global-batch (map alt-expr rewritten)))\n  (timeline-push! 'count (length altns) (length rewritten))\n\n  rewritten)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;; Public API ;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define (get-starting-expr altn)\n  (match (alt-prevs altn)\n    [(list) (alt-expr altn)]\n    [(list prev) (get-starting-expr prev)]))\n\n(define (generate-candidates batch brfs spec-batch reducer)\n  ; Starting alternatives\n  (define start-altns\n    (for/list ([brf brfs])\n      (alt brf 'patch '())))\n\n  (define evaluations\n    (if (flag-set? 'generate 'evaluate)\n        (run-evaluate start-altns batch)\n        '()))\n\n  ; Series expand\n  (define approximations\n    (if (flag-set? 'generate 'taylor)\n        (run-taylor start-altns batch spec-batch reducer)\n        '()))\n\n  ; Recursive rewrite\n  (define rewritten\n    (if (flag-set? 'generate 'rr)\n        (run-rr start-altns batch)\n        '()))\n\n  (remove-duplicates (append evaluations rewritten approximations)\n                     #:key (λ (altn) (cons (alt-expr altn) (get-starting-expr altn)))))\n"
  },
  {
    "path": "src/core/points.rkt",
    "content": "#lang racket\n\n(require math/flonum\n         \"../syntax/float.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/batch.rkt\"\n         \"compiler.rkt\")\n\n(provide in-pcontext\n         mk-pcontext\n         for/pcontext\n         pcontext?\n         pcontext-points\n         split-pcontext\n         pcontext-length\n         errors\n         batchref-errors\n         batch-errors\n         exprs-errors\n         errors-score)\n\n;; pcontexts are Herbie's standard data structure for storing\n;; ground-truth information. They contain 1) a set of sampled input\n;; points; and 2) a ground-truth output for each input.\n\n(struct pcontext (points exacts) #:prefab)\n\n(define (in-pcontext pcontext)\n  (in-parallel (in-vector (pcontext-points pcontext)) (in-vector (pcontext-exacts pcontext))))\n\n(define (pcontext-length pcontext)\n  (vector-length (pcontext-points pcontext)))\n\n(define/contract (mk-pcontext points exacts)\n  (-> (non-empty-listof vector?) (non-empty-listof any/c) pcontext?)\n  (pcontext (list->vector points) (list->vector exacts)))\n\n(define-syntax-rule (for/pcontext ([(pt ex) pcontext] other ...) body ...)\n  (let-values ([(pts* exs*)\n                (for/lists (pts* exs*) ([(pt ex) (in-pcontext pcontext)] other ...) body ...)])\n    (mk-pcontext pts* exs*)))\n\n(define (split-pcontext pctx num-a num-b)\n  (match-define (pcontext pts exs) pctx)\n  (unless (= (+ num-a num-b) (vector-length pts))\n    (error 'split-pcontext\n           \"Cannot split pcontext of size ~a into ~a and ~a\"\n           (vector-length pts)\n           num-a\n           num-b))\n  (define-values (pts-a pts-b) (vector-split-at pts num-a))\n  (define-values (exs-a exs-b) (vector-split-at exs num-a))\n  (values (pcontext pts-a exs-a) (pcontext pts-b exs-b)))\n\n;; Herbie's standard error measure is the average bits of error across\n;; all points in a pcontext.\n\n(define (average . s)\n  (/ (apply + s) (length s)))\n\n(define (errors-score e)\n  (/ (flvector-sum e) (flvector-length e)))\n\n(define (errors expr pcontext ctx)\n  (first (exprs-errors (list expr) pcontext ctx)))\n\n(define (batchref-errors brf pcontext ctx)\n  (first (batch-errors (batchref-batch brf) (list brf) pcontext ctx)))\n\n(define (exprs-errors exprs pcontext ctx)\n  (define fn (compile-progs exprs ctx))\n  (define num-exprs (length exprs))\n  (generate-errors fn pcontext ctx num-exprs))\n\n(define (batch-errors batch brfs pcontext ctx)\n  (define fn (compile-batch batch brfs ctx))\n  (define num-exprs (length brfs))\n  (generate-errors fn pcontext ctx num-exprs))\n\n(define (generate-errors fn pcontext ctx num-exprs)\n  (define repr (context-repr ctx))\n  (define ulps (repr-ulps repr))\n  (define max-ulps (+ 1 (expt 2 (representation-total-bits repr))))\n  (define invalid-bits (real->double-flonum (representation-total-bits repr)))\n  (define num-points (pcontext-length pcontext))\n  (define results (build-vector num-exprs (lambda (_) (make-flvector num-points invalid-bits))))\n  (for ([point (in-vector (pcontext-points pcontext))]\n        [exact (in-vector (pcontext-exacts pcontext))]\n        [pidx (in-naturals)])\n    (define outs (fn point))\n    (for ([out (in-vector outs)]\n          [result (in-vector results)])\n      (define err-ulps (ulps out exact))\n      (flvector-set! result\n                     pidx\n                     (if (= err-ulps max-ulps)\n                         invalid-bits\n                         (ulps->bits err-ulps)))))\n  (vector->list results))\n"
  },
  {
    "path": "src/core/preprocess.rkt",
    "content": "#lang racket\n\n(require math/bigfloat)\n(require \"../syntax/platform.rkt\"\n         \"../syntax/syntax.rkt\"\n         \"../syntax/types.rkt\"\n         \"../utils/common.rkt\"\n         \"../syntax/float.rkt\"\n         \"../utils/timeline.rkt\"\n         \"../syntax/batch.rkt\"\n         \"egg-herbie.rkt\"\n         \"points.rkt\"\n         \"programs.rkt\"\n         \"rules.rkt\")\n\n(provide find-preprocessing\n         preprocess-pcontext\n         remove-unnecessary-preprocessing\n         compile-preprocessing\n         compile-useful-preprocessing)\n\n(define (has-fabs-impl? repr)\n  (get-fpcore-impl 'fabs (repr->prop repr) (list repr)))\n\n(define (has-fmin-fmax-impl? repr)\n  (and (get-fpcore-impl 'fmin (repr->prop repr) (list repr repr))\n       (get-fpcore-impl 'fmax (repr->prop repr) (list repr repr))))\n\n(define (has-copysign-impl? repr)\n  (and (get-fpcore-impl '* (repr->prop repr) (list repr repr))\n       (get-fpcore-impl 'copysign (repr->prop repr) (list repr repr))))\n\n;; The even identities: f(x) = f(-x)\n;; Requires `neg` and `fabs` operator implementations.\n(define (make-even-identities spec ctx)\n  (for/list ([var (in-list (context-vars ctx))]\n             [repr (in-list (context-var-reprs ctx))]\n             #:when (has-fabs-impl? repr))\n    (cons `(abs ,var) (replace-expression spec var `(neg ,var)))))\n\n;; The odd identities: f(x) = -f(-x)\n;; Requires `neg` and `fabs` operator implementations.\n(define (make-odd-identities spec ctx)\n  (for/list ([var (in-list (context-vars ctx))]\n             [repr (in-list (context-var-reprs ctx))]\n             #:when (and (has-fabs-impl? repr) (has-copysign-impl? (context-repr ctx))))\n    (cons `(negabs ,var) (replace-expression `(neg ,spec) var `(neg ,var)))))\n\n;; Sort identities: f(a, b) = f(b, a)\n(define (make-sort-identities spec ctx)\n  (define pairs (combinations (context-vars ctx) 2))\n  (for/list ([pair (in-list pairs)]\n             ;; Can only sort same-repr variables\n             #:when (equal? (context-lookup ctx (first pair)) (context-lookup ctx (second pair)))\n             #:when (has-fmin-fmax-impl? (context-lookup ctx (first pair))))\n    (match-define (list a b) pair)\n    (cons `(sort ,a ,b) (replace-vars `((,a . ,b) (,b . ,a)) spec))))\n\n;; See https://pavpanchekha.com/blog/symmetric-expressions.html\n(define (find-preprocessing expr ctx)\n  (define spec (prog->spec expr))\n\n  ;; identities\n  (define identities\n    (append (make-even-identities spec ctx)\n            (make-odd-identities spec ctx)\n            (make-sort-identities spec ctx)))\n\n  ;; make egg runner\n  (define-values (batch brfs) (progs->batch (cons spec (map cdr identities))))\n  (define runner (make-egraph batch brfs (make-list (length brfs) (context-repr ctx)) '(rewrite) ctx))\n\n  ;; collect equalities\n  (for/list ([(ident spec*) (in-dict identities)]\n             #:when (egraph-equal? runner spec spec*))\n    ident))\n\n(define (preprocess-pcontext context pcontext preprocessing)\n  (define preprocess\n    (apply compose\n           (map (curry instruction->operator context)\n                ;; Function composition applies the rightmost function first\n                (reverse preprocessing))))\n  (for/pcontext ([(x y) pcontext]) (preprocess x y)))\n\n(define (vector-update v i f)\n  (define copy (make-vector (vector-length v)))\n  (vector-copy! copy 0 v)\n  (vector-set! copy i (f (vector-ref copy i)))\n  copy)\n\n(define (vector-set* v indices vals)\n  (define copy (make-vector (vector-length v)))\n  (vector-copy! copy 0 v)\n  (for ([i (in-list indices)]\n        [v (in-list vals)])\n    (vector-set! copy i v))\n  copy)\n\n(define (instruction->operator context instruction)\n  (define variables (context-vars context))\n  (define sort* (curryr sort (curryr </total (context-repr context))))\n  (match instruction\n    [(list 'sort a b)\n     (define indices (indexes-where variables (curry set-member? (list a b))))\n     (define repr (context-lookup context a))\n     (lambda (x y)\n       (define subsequence (map (curry vector-ref x) indices))\n       (define sorted (sort subsequence (curryr </total repr)))\n       (values (vector-set* x indices sorted) y))]\n    [(list 'abs variable)\n     (define index (index-of variables variable))\n     (define var-repr (context-lookup context variable))\n     (define fabs (impl-info (get-fpcore-impl 'fabs (repr->prop var-repr) (list var-repr)) 'fl))\n     (lambda (x y) (values (vector-update x index fabs) y))]\n    [(list 'negabs variable)\n     (define index (index-of variables variable))\n     (define var-repr (context-lookup context variable))\n     (define repr (context-repr context))\n     (define fabs (impl-info (get-fpcore-impl 'fabs (repr->prop var-repr) (list var-repr)) 'fl))\n     (define mul (impl-info (get-fpcore-impl '* (repr->prop repr) (list repr repr)) 'fl))\n     (define copysign (impl-info (get-fpcore-impl 'copysign (repr->prop repr) (list repr repr)) 'fl))\n     (define repr1 ((representation-bf->repr repr) 1.bf))\n     (lambda (x y)\n       (values (vector-update x index fabs) (mul (copysign repr1 (vector-ref x index)) y)))]))\n\n; until fixed point, iterate through preprocessing attempting to drop preprocessing with no effect on error\n(define (remove-unnecessary-preprocessing expression\n                                          context\n                                          pcontext\n                                          preprocessing\n                                          #:removed [removed empty])\n  (define-values (result newly-removed)\n    (let loop ([preprocessing preprocessing]\n               [i 0]\n               [removed removed])\n      (cond\n        [(>= i (length preprocessing)) (values preprocessing removed)]\n        [(preprocessing-<=? expression context pcontext (drop-at preprocessing i) preprocessing)\n         (loop (drop-at preprocessing i) i (cons (list-ref preprocessing i) removed))]\n        [else (loop preprocessing (+ i 1) removed)])))\n  (cond\n    [(< (length result) (length preprocessing))\n     (remove-unnecessary-preprocessing expression context pcontext result #:removed newly-removed)]\n    [else\n     (timeline-push! 'symmetry (map ~a result))\n     result]))\n\n(define (preprocessing-<=? expression context pcontext preprocessing1 preprocessing2)\n  (define pcontext1 (preprocess-pcontext context pcontext preprocessing1))\n  (define pcontext2 (preprocess-pcontext context pcontext preprocessing2))\n  (<= (errors-score (errors expression pcontext1 context))\n      (errors-score (errors expression pcontext2 context))))\n\n(define (compile-preprocessing expression context preprocessing)\n  (match preprocessing\n    ; Not handled yet\n    [(list 'sort a b)\n     (define repr (context-lookup context a))\n     (define fmin (get-fpcore-impl 'fmin (repr->prop repr) (list repr repr)))\n     (define fmax (get-fpcore-impl 'fmax (repr->prop repr) (list repr repr)))\n     (replace-vars (list (list a fmin a b) (list b fmax a b)) expression)]\n    [(list 'abs var)\n     (define repr (context-lookup context var))\n     (define fabs (get-fpcore-impl 'fabs (repr->prop repr) (list repr)))\n     (define replacement (list fabs var))\n     (replace-expression expression var replacement)]\n    [(list 'negabs var)\n     (define repr (context-lookup context var))\n     (define fabs (get-fpcore-impl 'fabs (repr->prop repr) (list repr)))\n     (define replacement (list fabs var))\n     (define mul (get-fpcore-impl '* (repr->prop repr) (list repr repr)))\n     (define copysign (get-fpcore-impl 'copysign (repr->prop repr) (list repr repr)))\n     `(,mul (,copysign ,(literal 1 (representation-name repr)) ,var)\n            ,(replace-expression expression var replacement))]))\n\n(define (compile-useful-preprocessing expression context pcontext preprocessing)\n  (define useful-preprocessing\n    (remove-unnecessary-preprocessing expression context pcontext preprocessing))\n  (for/fold ([expr expression]) ([prep (in-list (reverse useful-preprocessing))])\n    (compile-preprocessing expr context prep)))\n"
  },
  {
    "path": "src/core/programs.rkt",
    "content": "#lang racket\n\n(require \"../utils/common.rkt\"\n         \"../syntax/syntax.rkt\"\n         \"../syntax/platform.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/batch.rkt\")\n\n(provide expr?\n         expr<?\n         all-subexpressions\n         ops-in-expr\n         spec-prog?\n         impl-prog?\n         node-is-impl?\n         repr-of\n         batch-reprs\n         get-locations\n         free-variables\n         replace-expression\n         batch-replace-expression!\n         batch-replace-subexpr\n         replace-vars)\n\n;; Programs are just lisp lists plus atoms\n\n(define expr? (or/c list? symbol? boolean? real? literal? approx?))\n\n(define (node-is-impl? node)\n  (match node\n    [(? number?) #f]\n    [(list (? operator-exists? op) args ...) #f]\n    [_ #t]))\n\n;; Returns repr name\n;; Fast version does not recurse into functions applications\n(define (repr-of expr ctx)\n  (match expr\n    [(literal val precision) (get-representation precision)]\n    [(? symbol?) (context-lookup ctx expr)]\n    [(approx _ impl) (repr-of impl ctx)]\n    [(hole precision spec) (get-representation precision)]\n    [(list op args ...) (impl-info op 'otype)]))\n\n(define (batch-reprs batch ctx)\n  (batch-recurse batch\n                 (lambda (brf recurse)\n                   (define node (deref brf))\n                   (match node\n                     [(literal val precision) (get-representation precision)]\n                     [(? symbol?) (context-lookup ctx node)]\n                     [(approx _ impl) (recurse impl)]\n                     [(hole precision spec) (get-representation precision)]\n                     [(list op args ...) (impl-info op 'otype)]))))\n\n(define (all-subexpressions expr #:reverse? [reverse? #f])\n  (define subexprs\n    (reap [sow]\n          (let loop ([expr expr])\n            (sow expr)\n            (match expr\n              [(? number?) (void)]\n              [(? literal?) (void)]\n              [(? symbol?) (void)]\n              [(approx _ impl) (loop impl)]\n              [`(if ,c ,t ,f)\n               (loop c)\n               (loop t)\n               (loop f)]\n              [(list _ args ...)\n               (for ([arg args])\n                 (loop arg))]))))\n  (remove-duplicates (if reverse?\n                         (reverse subexprs)\n                         subexprs)))\n\n(define (ops-in-expr expr)\n  (remove-duplicates (filter-map (lambda (e) (and (pair? e) (first e))) (all-subexpressions expr))))\n\n;; Is the expression in LSpec (real expressions)?\n(define (spec-prog? expr)\n  (match expr\n    [(? symbol?) #t]\n    [(? number?) #t]\n    [(list 'if cond ift iff) (and (spec-prog? cond) (spec-prog? ift) (spec-prog? iff))]\n    [(list (? operator-exists?) args ...) (andmap spec-prog? args)]\n    [_ #f]))\n\n;; Is the expression in LImpl (floating-point implementations)?\n(define (impl-prog? expr)\n  (match expr\n    [(? symbol?) #t]\n    [(? literal?) #t]\n    [(approx spec impl) (and (spec-prog? spec) (impl-prog? impl))]\n    [(list (? impl-exists?) args ...) (andmap impl-prog? args)]\n    [_ #f]))\n\n;; Total order on expressions\n\n(define (expr-cmp a b)\n  (match* (a b)\n    [((? batchref?) (? batchref?)) (expr-cmp (deref a) (deref b))]\n    [((? batchref?) _) (expr-cmp (deref a) b)]\n    [(_ (? batchref?)) (expr-cmp a (deref b))]\n    [((? list?) (? list?))\n     (define len-a (length a))\n     (define len-b (length b))\n     (cond\n       [(< len-a len-b) -1]\n       [(> len-a len-b) 1]\n       [else\n        (let loop ([a a]\n                   [b b])\n          (cond\n            [(null? a) 0]\n            [else\n             (define cmp (expr-cmp (car a) (car b)))\n             (if (zero? cmp)\n                 (loop (cdr a) (cdr b))\n                 cmp)]))])]\n    [((? list?) _) 1]\n    [(_ (? list?)) -1]\n    [((? approx?) (? approx?))\n     (define cmp-spec (expr-cmp (approx-spec a) (approx-spec b)))\n     (if (zero? cmp-spec)\n         (expr-cmp (approx-impl a) (approx-impl b))\n         cmp-spec)]\n    [((? approx?) _) 1]\n    [(_ (? approx?)) -1]\n    [((? hole?) (? hole?))\n     (define cmp-spec (expr-cmp (hole-spec a) (hole-spec b)))\n     (if (zero? cmp-spec)\n         (expr-cmp (hole-precision a) (hole-precision b))\n         cmp-spec)]\n    [((? hole?) _) 1]\n    [(_ (? hole?)) -1]\n    [((? symbol?) (? symbol?))\n     (cond\n       [(symbol<? a b) -1]\n       [(symbol=? a b) 0]\n       [else 1])]\n    [((? symbol?) _) 1]\n    [(_ (? symbol?)) -1]\n    ;; Need both cases because `reduce` uses plain numbers\n    [((or (? literal? (app literal-value a)) (? number? a)) (or (? literal? (app literal-value b))\n                                                                (? number? b)))\n     (cond\n       [(< a b) -1]\n       [(= a b) 0]\n       [else 1])]))\n\n(define (expr<? a b)\n  (negative? (expr-cmp a b)))\n\n;; Converting constants\n\n(define (free-variables prog)\n  (match prog\n    [(? literal?) '()]\n    [(? number?) '()]\n    [(? symbol?) (list prog)]\n    [(approx _ impl) (free-variables impl)]\n    [(list _ args ...) (remove-duplicates (append-map free-variables args))]))\n\n(define (replace-vars dict expr)\n  (let loop ([expr expr])\n    (match expr\n      [(? literal?) expr]\n      [(? number?) expr]\n      [(? symbol?) (dict-ref dict expr expr)]\n      [(approx impl spec) (approx (loop impl) (loop spec))]\n      [(list op args ...) (cons op (map loop args))])))\n\n(define (get-locations expr subexpr)\n  (reap [sow]\n        (let loop ([expr expr]\n                   [loc '()])\n          (match expr\n            [(== subexpr) (sow (reverse loc))]\n            [(? literal?) (void)]\n            [(? symbol?) (void)]\n            [(approx _ impl) (loop impl (cons 2 loc))]\n            [(list _ args ...)\n             (for ([arg (in-list args)]\n                   [i (in-naturals 1)])\n               (loop arg (cons i loc)))]))))\n\n(define/contract (replace-expression expr from to)\n  (-> expr? expr? expr? expr?)\n  (let loop ([expr expr])\n    (match expr\n      [(== from) to]\n      [(? number?) expr]\n      [(? literal?) expr]\n      [(? symbol?) expr]\n      [(approx spec impl) (approx (loop spec) (loop impl))]\n      [(list op args ...) (cons op (map loop args))])))\n\n(define (batch-replace-expression! batch from to)\n  (define from* (deref (batch-add! batch from))) ;; a hack on how not to use deref for \"from\"\n  (define (f node)\n    (match node\n      [(== from*) to]\n      [(? number?) node]\n      [(? literal?) node]\n      [(? symbol?) node]\n      [(approx spec impl) (approx spec impl)]\n      [(list op args ...) (cons op args)]))\n  (batch-recurse batch\n                 (λ (brf recurse)\n                   (define node (deref brf))\n                   (define node* (f node))\n                   (let loop ([node* node*])\n                     (match node*\n                       [(? batchref? brf) (recurse brf)]\n                       [_ (batch-push! batch (expr-recurse node* (compose batchref-idx loop)))])))))\n\n;; Replace all occurrences of `from` with `to` in expression `expr`, returning a new batchref\n;; Only recurses into impl parts, not specs\n(define (batch-replace-subexpr batch expr from to [can-refer #f])\n  (define cache (make-hasheq))\n  (define from-idx (batchref-idx from))\n  (let loop ([brf expr])\n    (define idx (batchref-idx brf))\n    (cond\n      [(< idx from-idx) brf]\n      [(= idx from-idx) to]\n      [(and can-refer (not (set-member? can-refer idx))) brf]\n      [else\n       (hash-ref! cache\n                  idx\n                  (lambda ()\n                    (match (deref brf)\n                      [(approx spec impl)\n                       (define impl* (loop impl))\n                       (if (= (batchref-idx impl*) (batchref-idx impl))\n                           brf\n                           (batch-push! batch (approx (batchref-idx spec) (batchref-idx impl*))))]\n                      [node\n                       (define unchanged? #t)\n                       (define node*\n                         (expr-recurse node\n                                       (lambda (arg)\n                                         (define arg* (loop arg))\n                                         (unless (= (batchref-idx arg*) (batchref-idx arg))\n                                           (set! unchanged? #f))\n                                         (batchref-idx arg*))))\n                       (if unchanged?\n                           brf\n                           (batch-push! batch node*))])))])))\n\n(module+ test\n  (require rackunit)\n  (check-equal? (replace-expression '(- x (sin x)) 'x 1) '(- 1 (sin 1)))\n\n  (check-equal? (replace-expression '(/ (cos (* 2 x))\n                                        (* (pow cos 2) (* (fabs (* sin x)) (fabs (* sin x)))))\n                                    'cos\n                                    '(/ 1 cos))\n                '(/ (cos (* 2 x)) (* (pow (/ 1 cos) 2) (* (fabs (* sin x)) (fabs (* sin x)))))))\n"
  },
  {
    "path": "src/core/prove-rules.rkt",
    "content": "#lang racket\n\n(require rackunit)\n(require \"../utils/common.rkt\"\n         \"../syntax/matcher.rkt\"\n         \"programs.rkt\"\n         \"rules.rkt\")\n\n(provide rewrite-unsound?)\n\n(define (undefined-conditions x)\n  (reap [sow]\n        (for ([subexpr (in-list (all-subexpressions x))])\n          (match subexpr\n            [`(acos ,x) (sow `(< 1 (fabs ,x)))]\n            [`(acosh ,x) (sow `(< ,x 1))]\n            [`(asin ,x) (sow `(< 1 (fabs ,x)))]\n            [`(atanh ,x) (sow `(<= 1 (fabs ,x)))]\n            [`(fmod ,x ,y) (sow `(== ,y 0))]\n            [`(lgamma ,x) (sow `(and (<= ,x 0) (integer? ,x)))]\n            [`(log ,x) (sow `(<= ,x 0))]\n            [`(log10 ,x) (sow `(<= ,x 0))]\n            [`(log2 ,x) (sow `(<= ,x 0))]\n            [`(logb ,x) (sow `(== ,x 0))]\n            [`(remainder ,x ,y) (sow `(== ,y 0))]\n            [`(sqrt ,x) (sow `(< ,x 0))]\n            [`(tan ,x) (sow `(== (cos ,x) 0))]\n            [`(tgamma ,x) (sow `(and (<= ,x 0) (integer? ,x)))]\n            [`(pow ,a ,b)\n             (sow `(and (< ,a 0) (even-denominator? ,b)))\n             (sow `(and (== ,a 0) (< ,b 0)))]\n            [`(/ ,a ,b) (sow `(== ,b 0))]\n            [_ (void)]))))\n\n(define (reify c)\n  (if c\n      '(TRUE)\n      '(FALSE)))\n\n;; In general, the normal forms are:\n;; - Only use ==, < conditions\n;; - One side of a comparison is always a constant\n;; - For ==, the constant is on the right\n\n(define (rewrite-all expr a b)\n  ;; This is an ugly / slow way to do this but I guess it works\n  (define matches\n    (for/list ([subexpr (in-list (all-subexpressions expr))]\n               #:when (pattern-match a subexpr))\n      (cons subexpr (pattern-substitute b (pattern-match a subexpr)))))\n  (for/fold ([expr expr]) ([(from to) (in-dict matches)])\n    (replace-expression expr from to)))\n\n(define simplify-patterns\n  (list '[(cos (neg a)) . (cos a)]\n        '[(sin (neg a)) . (neg (sin a))]\n        '[(cos (+ a (PI))) . (neg (cos a))]\n        '[(cos (+ a (/ (PI) 2))) . (neg (sin a))]\n        '[(cos (acos a)) . a]\n        '[(cos (asin a)) . (sqrt (- 1 (* a a)))]\n        '[(fabs (neg a)) . (fabs a)]\n        '[(fabs (fabs a)) . (fabs a)]\n        '[(pow x 2) . (* x x)]))\n\n(define (simplify-expression expr)\n  (for/fold ([expr expr]) ([(a b) (in-dict simplify-patterns)])\n    (rewrite-all expr a b)))\n\n(define (simplify-condition term)\n  (match term\n    [`(== ,(? number? a) ,(? number? b)) (reify (= a b))]\n    [`(< ,(? number? a) ,(? number? b)) (reify (< a b))]\n    [`(> ,(? number? a) ,(? number? b)) (reify (> a b))]\n    [`(== (PI) ,(? number?)) '(FALSE)]\n    [`(== ,(? number? a) ,b) `(== ,b ,a)] ; canonicalize\n    [`(== (+ ,(? number? a) ,b) ,c) `(== (+ ,b ,a) ,c)] ; canonicalize\n    [`(== (- ,(? number? a) ,b) ,c) `(== (neg (- ,b ,a)) ,c)] ; canonicalize\n    [`(<= ,a ,b) `(or (< ,a ,b) (== ,a ,b))] ; canonicalize\n\n    [`(== (cbrt ,a) 0) `(== ,a 0)]\n    [`(== (sqrt ,a) 0) `(== ,a 0)]\n    [`(== (neg ,a) 0) `(== ,a 0)]\n    [`(== (fabs ,a) 0) `(== ,a 0)]\n    [`(== (* ,a ,b) 0) `(or (== ,a 0) (== ,b 0))]\n    [`(== (/ ,a ,b) 0) `(== ,a 0)]\n    [`(== (pow ,a ,b) 0) `(and (== ,a 0) (> ,b 0))]\n\n    [`(== (fabs ,a) 1) `(or (== ,a 1) (== ,a -1))]\n    [`(== (+ ,x 1) 0) `(== ,x -1)]\n    [`(== (- ,a 1) 0) `(== ,a 1)]\n    [`(== (* ,a ,a) 1) `(== (fabs ,a) 1)]\n\n    [`(< (* ,a ,a) 0) '(FALSE)]\n    [`(< (sqrt ,a) 0) '(FALSE)]\n    [`(< (fabs ,a) 0) '(FALSE)]\n    [`(,(or '< '==) (cosh ,a) ,(? (conjoin number? (curryr < 1)))) '(FALSE)]\n    [`(,(or '< '==) (exp ,a) ,(? (conjoin number? (curryr <= 0)))) '(FALSE)]\n    [`(,(or '< '==) (* ,a ,a) ,(? (conjoin number? (curryr < 0)))) '(FALSE)]\n    [`(,(or '< '==) (fabs ,a) ,(? (conjoin number? (curryr < 0)))) '(FALSE)]\n\n    [`(< (/ 1 ,a) 0) `(< ,a 0)]\n    [`(> (/ 1 ,a) 0) `(> ,a 0)]\n    [`(< (/ -1 ,a) 0) `(> ,a 0)]\n    [`(< (neg ,a) 0) `(> ,a 0)]\n    [`(> (neg ,a) 0) `(< ,a 0)]\n    [`(< (* 2 ,a) ,(? number? b)) `(< ,a ,(/ b 2))]\n    [`(< (+ 1 ,a) 0) `(< ,a -1)]\n    [`(< (/ ,x ,(? (conjoin number? positive?))) 0) `(< ,x 0)]\n    [`(< (+ ,x 1) 0) `(< ,x -1)]\n    [`(< (- ,a 1) ,(? number? b)) `(< ,a ,(+ b 1))]\n    [`(< (- 1 ,x) 0) `(< 1 ,x)]\n    [`(< (cbrt ,a) 0) `(< ,a 0)]\n\n    [`(< (* ,a ,a) 1) `(< (fabs ,a) 1)]\n    [`(< 1 (* ,a ,a)) `(< 1 (fabs ,a))]\n\n    [`(== (+ ,x (sqrt (+ (* ,x ,x) 1))) 0) '(FALSE)]\n    [`(== (+ ,x (sqrt (- (* ,x ,x) 1))) 0) '(FALSE)]\n    [`(< (+ ,x (sqrt (+ (* ,x ,x) 1))) 0) '(FALSE)]\n    [`(< (+ ,x (sqrt (- (* ,x ,x) 1))) 0) `(<= x -1)]\n\n    [`(< 1 (fabs (,(or 'cos 'sin) x))) '(FALSE)]\n\n    [`(== (/ (+ 1 ,x) (- 1 ,x)) 0) `(== ,x -1)]\n    [`(< (/ (+ 1 ,x) (- 1 ,x)) 0) `(< 1 (fabs x))]\n\n    [`(== (+ (cos ,a) (cos ,b)) 0) `(or (== (cos (/ (+ ,a ,b) 2)) 0) (== (cos (/ (- ,a ,b) 2)) 0))]\n    [`(== (cos (* 2 ,a)) 0) `(or (== (tan ,a) 1) (== (tan ,a) -1))]\n    [`(== (tan ,a) 0) `(== (sin ,a) 0)]\n\n    [`(even-denominator? (neg ,b)) `(even-denominator? ,b)]\n    [`(even-denominator? (+ ,b 1)) `(even-denominator? ,b)]\n    [`(even-denominator? (/ ,b 3)) `(even-denominator? ,b)]\n    [`(even-denominator? ,(? rational? a))\n     (if (even? (denominator a))\n         '(TRUE)\n         '(FALSE))]\n\n    [`(and ,sub ...)\n     (define subs (map (compose simplify-conditions list) sub))\n     (define conjunctions (apply cartesian-product subs))\n     (cons 'or\n           (for/list ([conj (in-list conjunctions)])\n             (match (set-remove conj '(TRUE))\n               ['(FALSE) '(TRUE)]\n               [(list a) a]\n               [(list as ...) (cons 'and as)])))]\n    [_ term]))\n\n(define (simplify-conditions xs)\n  (define simple1\n    (reap [sow]\n          (for ([x (remove-duplicates xs)])\n            (define out (simplify-condition (simplify-expression x)))\n            (match out\n              [`(or ,terms ...) (for-each sow terms)]\n              [`(FALSE) (void)]\n              [_ (sow out)]))))\n  (if (equal? simple1 xs)\n      xs\n      (simplify-conditions simple1)))\n\n;; The prover must prove: rhs-bad => lhs-bad\n;; IOW we can weaken the RHS or strengthen the LHS\n\n(define soundness-proofs\n  '((pow-plus (implies (< b -1) (< b 0)))\n    (pow-sqr (implies (even-denominator? (* 2 b)) (even-denominator? b)))\n    (hang-0p-tan (implies (== (cos (/ a 2)) 0) (== (cos a) -1)))\n    (hang-0p-tan-rev (implies (== (cos a) -1) (== (cos (/ a 2)) 0)))\n    (hang-0m-tan (implies (== (cos (/ (neg a) 2)) 0) (== (cos a) -1)))\n    (hang-0m-tan-rev (implies (== (cos a) -1) (== (cos (/ (neg a) 2)) 0)))\n    (tanh-sum (implies (== (* (tanh x) (tanh y)) -1) (FALSE)))\n    (tanh-def-a (implies (== (+ (exp x) (exp (neg x))) 0) (FALSE)))\n    (acosh-def (implies (< x -1) (< x 1))\n               (implies (== x -1) (< x 1))\n               (implies (< (fabs x) 1) (< x 1)))\n    (acosh-def-rev (implies (< x 1) (or (< x -1) (== x -1) (< (fabs x) 1))))\n    (sqrt-undiv (implies (< (/ x y) 0) (or (< x 0) (< y 0))))\n    (sqrt-unprod (implies (< (* x y) 0) (or (< x 0) (< y 0))))\n    (sqrt-pow2 (implies (and (< x 0) _) (< x 0)))\n    (tan-sum-rev (implies (== (cos (+ x y)) 0) (== (* (tan x) (tan y)) 1)))\n    (sum-log (implies (< (* x y) 0) (or (< x 0) (< y 0))))\n    (diff-log (implies (< (/ x y) 0) (or (< x 0) (< y 0))))\n    (exp-to-pow (implies (and a b) a))\n    (acosh-2-rev (implies (< (fabs x) 1) (< x 1)))\n    (tanh-acosh (implies (< (fabs x) 1) (< x 1)) (implies (== x 0) (< x 1)))\n    (sinh-acosh (implies (< (fabs x) 1) (< x 1)))\n    (hang-p0-tan (implies (== (cos (/ a 2)) 0) (== (sin a) 0)))\n    (hang-m0-tan (implies (== (cos (/ a 2)) 0) (== (sin a) 0)))\n    (pow-div (implies (< (- b c) 0) (or (< b 0) (> c 0)))\n             (implies (even-denominator? (- b c)) (or (even-denominator? b) (even-denominator? c))))\n    (pow-prod-up (implies (< (+ b c) 0) (or (< b 0) (< c 0)))\n                 (implies (even-denominator? (+ b c))\n                          (or (even-denominator? b) (even-denominator? c))))\n    (pow-prod-down (implies (< (* b c) 0) (or (< b 0) (< c 0))))\n    (log-pow-rev (implies (and a b) a) (implies (< (pow a b) 0) (< a 0)))))\n\n(define (execute-proof proof terms)\n  (for/fold ([terms (simplify-conditions terms)]) ([step (in-list proof)])\n    (match-define `(implies ,a ,b) step)\n    (simplify-conditions (map (curryr rewrite-all a b) terms))))\n\n(define (rewrite-unsound? lhs rhs [proof '()])\n  (define lhs-bad (simplify-conditions (undefined-conditions lhs)))\n  (define rhs-bad (execute-proof proof (undefined-conditions rhs)))\n  (define extra (set-remove (set-subtract rhs-bad lhs-bad) '(FALSE)))\n  (if (empty? extra)\n      (values #f #f)\n      (values lhs-bad extra)))\n\n(define (potentially-unsound)\n  (for ([rule (in-list (*rules*))])\n    (test-case (~a (rule-name rule))\n      (define proof (dict-ref soundness-proofs (rule-name rule) '()))\n      (define-values (lhs-bad rhs-bad) (rewrite-unsound? (rule-input rule) (rule-output rule) proof))\n      (when rhs-bad\n        (with-check-info (['lhs-bad lhs-bad]) (check-false rhs-bad))))))\n\n(module+ test\n  (potentially-unsound))\n"
  },
  {
    "path": "src/core/regimes.rkt",
    "content": "#lang racket\n\n;;;; Module principles\n;; - The core of this file is infer-option-prefixes.\n;;   It is a giant dynamic programming algorithm.\n;;   It is extremely performance-sensitive.\n;; - Therefore almost everything is vector-based with few copies.\n;;   Except exprs-to-branch-on. Converting it to vectors makes it slow.\n;; - Everything else is overhead and should be minimized.\n\n(require math/flonum\n         \"../core/alternative.rkt\"\n         \"../utils/common.rkt\"\n         \"../utils/pareto.rkt\"\n         \"../syntax/float.rkt\"\n         \"../utils/timeline.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/batch.rkt\"\n         \"compiler.rkt\"\n         \"points.rkt\"\n         \"programs.rkt\")\n(provide pareto-regimes\n         (struct-out option)\n         (struct-out si)\n         critical-subexpression?)\n\n(module+ test\n  (require rackunit\n           \"../syntax/syntax.rkt\"\n           \"../syntax/sugar.rkt\"))\n\n(struct option (split-indices alts pts expr)\n  #:transparent\n  #:methods gen:custom-write\n  [(define (write-proc opt port mode)\n     (fprintf port \"#<option ~a>\" (option-split-indices opt)))])\n\n;; CONSIDER: move start-prog and the \"branch-brfs\" computation into caller.\n(define (pareto-regimes batch sorted start-prog ctx pcontext)\n  (timeline-event! 'regimes)\n  (define alts-vec (list->vector sorted))\n  (define alt-count (vector-length alts-vec))\n  (define err-cols (batch-errors batch (map alt-expr sorted) pcontext ctx))\n  (define branch-brfs\n    (if (flag-set? 'reduce 'branch-expressions)\n        (exprs-to-branch-on batch start-prog ctx)\n        (map (curry batch-add! batch) (context-vars ctx))))\n\n  (define brf-vals (brf-values* batch branch-brfs ctx pcontext))\n  (define reprs (batch-reprs batch ctx))\n  (define pts-vec (pcontext-points pcontext))\n\n  ;; For timeline\n  (define batch-jsexpr (batch->jsexpr batch (append (map alt-expr sorted) branch-brfs)))\n  (timeline-push! 'batch batch-jsexpr)\n  (define branch-roots (drop (hash-ref batch-jsexpr 'roots) alt-count))\n  (define branch-root-map (make-immutable-hash (map cons branch-brfs branch-roots)))\n\n  (define option-curves\n    (for/list ([brf (in-list branch-brfs)]\n               [brf-vals-vec (in-list brf-vals)])\n      (define timeline-stop! (timeline-start! 'times (batch->jsexpr batch (list brf))))\n      (define repr (reprs brf))\n      (define curve (branch-options batch alts-vec err-cols pts-vec brf brf-vals-vec repr))\n      (define last-point (last curve))\n      (timeline-stop!)\n      (timeline-push! 'branch\n                      (hash-ref branch-root-map brf)\n                      (- (pareto-point-error last-point)\n                         (length (option-split-indices (pareto-point-data last-point))))\n                      (length (option-split-indices (pareto-point-data last-point)))\n                      (~a (representation-name repr)))\n      curve))\n  (define combined-option-curve\n    (for/fold ([curve '()]) ([branch-curve (in-list option-curves)])\n      (pareto-union curve branch-curve #:combine (lambda (old _new) old))))\n\n  ;; Timeline\n  (for/list ([ppt (in-list combined-option-curve)])\n    (define opt (pareto-point-data ppt))\n    (define output-brfs\n      (for/list ([sidx (in-list (option-split-indices opt))])\n        (alt-expr (list-ref (option-alts opt) (si-cidx sidx)))))\n    (timeline-push! 'inputs (batch->jsexpr batch (map alt-expr (option-alts opt))))\n    (timeline-push! 'count (length (option-alts opt)) (length (option-split-indices opt)))\n    (timeline-push! 'outputs (batch->jsexpr batch output-brfs))\n    (timeline-push! 'baseline (baseline-errors-score err-cols (pareto-point-cost ppt)))\n    (timeline-push! 'accuracy (- (pareto-point-error ppt) (length (option-split-indices opt))))\n    (timeline-push! 'oracle (oracle-errors-score err-cols (pareto-point-cost ppt)))\n    opt))\n\n(define (exprs-to-branch-on batch start-prog ctx)\n  (define exprs (batch-exprs batch))\n  (define start-expr (exprs start-prog))\n  ;; We can only binary search if the branch expression is critical\n  ;; for the start program and is real-typed.\n  (for/list ([subexpr (set-union (context-vars ctx) (all-subexpressions start-expr))]\n             #:when (critical-subexpression? start-expr subexpr)\n             #:when (equal? (representation-type (repr-of subexpr ctx)) 'real))\n    (batch-add! batch subexpr)))\n\n;; Requires that expr is not a λ expression\n(define (critical-subexpression? expr subexpr)\n  (define crit-vars (free-variables subexpr))\n  (define replaced-expr (replace-expression expr subexpr 1))\n  (define non-crit-vars (free-variables replaced-expr))\n  (and (not (null? crit-vars)) (null? (set-intersect crit-vars non-crit-vars))))\n\n(define (baseline-errors-score err-cols count)\n  (for/fold ([best +inf.0]) ([err-col (in-list (take err-cols count))])\n    (min best (errors-score err-col))))\n\n(define (oracle-errors-score err-cols count)\n  (define num-points (flvector-length (first err-cols)))\n  (/ (for/sum ([point-idx (in-range num-points)])\n              (for/fold ([best-err +inf.0]) ([err-col (in-list (take err-cols count))])\n                (min best-err (flvector-ref err-col point-idx))))\n     num-points))\n\n(define (brf-values* batch brfs ctx pcontext)\n  (define count (length brfs))\n  (define fn (compile-batch batch brfs ctx))\n  (define num-points (pcontext-length pcontext))\n  (define vals (build-vector count (lambda (_) (make-vector num-points))))\n  (for ([pt (in-vector (pcontext-points pcontext))]\n        [p (in-naturals)])\n    (for ([out (in-vector (fn pt))]\n          [i (in-naturals)])\n      (vector-set! (vector-ref vals i) p out)))\n  (vector->list vals))\n\n(define (branch-options batch alts-vec err-cols pts-vec brf brf-vals-vec repr)\n  (define sorted-indices\n    (vector-sort (build-vector (vector-length brf-vals-vec) values)\n                 (lambda (i j)\n                   (</total (vector-ref brf-vals-vec i) (vector-ref brf-vals-vec j) repr))))\n  (define pts*\n    (for/list ([i (in-vector sorted-indices)])\n      (vector-ref pts-vec i)))\n  (define can-split?\n    (cons #f\n          (for/list ([idx (in-vector sorted-indices 1)]\n                     [prev-idx (in-vector sorted-indices 0)])\n            (</total (vector-ref brf-vals-vec prev-idx) (vector-ref brf-vals-vec idx) repr))))\n\n  (define-values (splitss scores) (infer-option-prefixes err-cols sorted-indices can-split?))\n\n  (define points\n    (for/list ([count (in-range 1 (add1 (vector-length splitss)))])\n      (define split-indices (vector-ref splitss (sub1 count)))\n      (define alts (vector->list (vector-take alts-vec count)))\n      (define error (+ (/ (flvector-ref scores (sub1 count)) (vector-length sorted-indices)) 1))\n      (pareto-point count error (option split-indices alts pts* brf))))\n  (for/fold ([curve '()]) ([point (in-list points)])\n    (pareto-union curve (list point) #:combine (lambda (old _new) old))))\n\n(module+ test\n  (require \"../syntax/platform.rkt\"\n           \"../syntax/load-platform.rkt\")\n  (activate-platform! \"c\")\n  (define ctx (context '(x) <binary64> (list <binary64>)))\n  (define pctx (mk-pcontext '(#(0.5) #(4.0)) '(1.0 1.0)))\n  (define alts (map make-alt (list '(fmin.f64 x 1) '(fmax.f64 x 1))))\n  (define err-cols (list (flvector 53.0 0.0) (flvector 0.0 53.0)))\n  (define pts-vec (pcontext-points pctx))\n\n  (define (test-regimes expr goal)\n    (define-values (batch brfs) (progs->batch (list expr)))\n    (define brf (car brfs))\n    (define brf-vals (car (brf-values* batch (list brf) ctx pctx)))\n    (define reprs (batch-reprs batch ctx))\n    (check\n     (lambda (x y) (equal? (map si-cidx (option-split-indices x)) y))\n     (pareto-point-data\n      (first (branch-options batch (list->vector alts) err-cols pts-vec brf brf-vals (reprs brf))))\n     goal))\n\n  (define (test-regimes/prefixes expr goals)\n    (define-values (batch brfs) (progs->batch (list expr)))\n    (define brf (car brfs))\n    (define brf-vals (car (brf-values* batch (list brf) ctx pctx)))\n    (define reprs (batch-reprs batch ctx))\n    (define options\n      (map pareto-point-data\n           (reverse\n            (branch-options batch (list->vector alts) err-cols pts-vec brf brf-vals (reprs brf)))))\n    (for ([goal (in-list goals)]\n          [opt (in-list options)])\n      (check (lambda (x y) (equal? (map si-cidx (option-split-indices x)) y)) opt goal)))\n\n  ;; This is a basic sanity test\n  (test-regimes 'x '(1 0))\n  (test-regimes/prefixes 'x '((0) (1 0)))\n\n  ;; This test ensures we handle equal points correctly. All points\n  ;; are equal along the `1` axis, so we should only get one\n  ;; splitpoint (the second, since it is better at the further point).\n  (test-regimes (literal 1 'binary64) '(0))\n\n  (test-regimes `(if.f64 (==.f64 x ,(literal 0.5 'binary64)) ,(literal 1 'binary64) (NAN.f64)) '(1 0))\n\n  (check-equal? (baseline-errors-score err-cols 2) 26.5)\n  (check-equal? (oracle-errors-score err-cols 2) 0.0))\n\n(define (valid-splitindices? can-split? split-indices)\n  (and (for/and ([pidx (map si-pidx (drop-right split-indices 1))])\n         (and (> pidx 0) (list-ref can-split? pidx)))\n       (= (si-pidx (last split-indices)) (length can-split?))))\n\n(module core typed/racket\n  (provide (struct-out si)\n           infer-option-prefixes)\n  (require math/flonum)\n\n  ;; Struct representing a splitindex\n  ;; cidx = Candidate index: the index candidate program that should be used to the left of this splitindex\n  ;; pidx = Point index: The index of the point to the left of which we should split.\n  (struct si ([cidx : Integer] [pidx : Integer]) #:prefab)\n\n  (: resort-errors (-> FlVector (Vectorof Integer) FlVector))\n  (define (resort-errors alt-errors sorted-indices)\n    (for/flvector #:length (vector-length sorted-indices)\n                  ([point-idx (in-vector sorted-indices)])\n                  (flvector-ref alt-errors point-idx)))\n\n  ;; This is the core main loop of the regimes algorithm.\n  ;; Takes in alt-major error columns, point-sorting indices, and a list of\n  ;; split indices to determine when it's ok to split for another alt.\n  ;; Returns a list of split indices saying which alt to use for which\n  ;; range of points. Starting at 1 going up to num-points.\n  ;; Alts are indexed 0 and points are index 1.\n  (: infer-option-prefixes\n     (-> (Listof FlVector)\n         (Vectorof Integer)\n         (Listof Boolean)\n         (Values (Vectorof (Listof si)) FlVector)))\n  (define (infer-option-prefixes err-cols sorted-indices can-split)\n    (define can-split-vec (list->vector can-split))\n    (define number-of-alts (length err-cols))\n    (: flvec-psums (Vectorof FlVector))\n    (define flvec-psums\n      (for/vector #:length number-of-alts\n                  ([err-col (in-list err-cols)])\n        :\n        FlVector\n        (flvector-sums (resort-errors err-col sorted-indices))))\n\n    ;; Set up data needed for algorithm\n    (define number-of-points (vector-length can-split-vec))\n    ;; min-weight is used as penalty to favor not adding split points\n    (define min-weight (fl number-of-points))\n\n    (: result-error-sums (Vectorof FlVector))\n    (: result-alt-idxs (Vectorof (Vectorof Integer)))\n    (: result-prev-idxs (Vectorof (Vectorof Integer)))\n    (define result-error-sums\n      (for/vector #:length number-of-alts\n                  ([alt-idx (in-range number-of-alts)])\n        :\n        FlVector\n        (make-flvector number-of-points +inf.0)))\n    (define result-alt-idxs\n      (for/vector #:length number-of-alts\n                  ([alt-idx (in-range number-of-alts)])\n        :\n        (Vectorof Integer)\n        (make-vector number-of-points 0)))\n    (define result-prev-idxs\n      (for/vector #:length number-of-alts\n                  ([alt-idx (in-range number-of-alts)])\n        :\n        (Vectorof Integer)\n        (make-vector number-of-points number-of-points)))\n\n    ;; Vectors used to determine the best final segment for each possible split\n    ;; when adding alts in increasing cost order.\n    (: best-alt-idxs (Vectorof Integer))\n    (: best-alt-costs FlVector)\n    (define best-alt-idxs (make-vector number-of-points number-of-alts))\n    (define best-alt-costs (make-flvector number-of-points))\n\n    (for ([point-idx (in-range number-of-points)])\n      (define current-best-alt 0)\n      (define current-best-cost +inf.0)\n\n      (for ([prev-split-idx (in-range number-of-points)])\n        (vector-set! best-alt-idxs prev-split-idx number-of-alts)\n        (flvector-set! best-alt-costs prev-split-idx +inf.0))\n\n      (for ([alt-idx (in-range number-of-alts)])\n        (define alt-error-sums (vector-ref flvec-psums alt-idx))\n        (define single-alt-error (flvector-ref alt-error-sums point-idx))\n        (when (< single-alt-error current-best-cost)\n          (set! current-best-cost single-alt-error)\n          (set! current-best-alt alt-idx))\n\n        (define current-alt-error current-best-cost)\n        (define current-alt-idx current-best-alt)\n        (define current-prev-idx number-of-points)\n\n        ;; Update the best last segment for each split point with the newly\n        ;; available alt.\n        (for ([prev-split-idx (in-range point-idx)]\n              [prev-alt-error-sum (in-flvector alt-error-sums)]\n              [can-split (in-vector can-split-vec 1)]\n              #:when can-split)\n          (define best-alt-idx (vector-ref best-alt-idxs prev-split-idx))\n          (define best-alt-cost (flvector-ref best-alt-costs prev-split-idx))\n          (define segment-error (- single-alt-error prev-alt-error-sum))\n          (when (or (= best-alt-idx number-of-alts) (< segment-error best-alt-cost))\n            (flvector-set! best-alt-costs prev-split-idx segment-error)\n            (vector-set! best-alt-idxs prev-split-idx alt-idx)))\n\n        ;; Compare against the best already-computed prefix result for this alt\n        ;; budget.\n        (define alt-result-error-sums (vector-ref result-error-sums alt-idx))\n        (for ([prev-split-idx (in-range point-idx)]\n              [r-error-sum (in-flvector alt-result-error-sums)]\n              [best-alt-idx (in-vector best-alt-idxs)]\n              [best-alt-cost (in-flvector best-alt-costs)]\n              [can-split (in-vector can-split-vec 1)]\n              #:when can-split)\n          (define alt-error-sum (+ r-error-sum best-alt-cost min-weight))\n          (define set-cond\n            (cond\n              [(< alt-error-sum current-alt-error) #t]\n              [(and (= alt-error-sum current-alt-error) (> current-alt-idx best-alt-idx)) #t]\n              [(and (= alt-error-sum current-alt-error)\n                    (= current-alt-idx best-alt-idx)\n                    (> current-prev-idx prev-split-idx))\n               #t]\n              [else #f]))\n          (when set-cond\n            (set! current-alt-error alt-error-sum)\n            (set! current-alt-idx best-alt-idx)\n            (set! current-prev-idx prev-split-idx)))\n\n        (flvector-set! (vector-ref result-error-sums alt-idx) point-idx current-alt-error)\n        (vector-set! (vector-ref result-alt-idxs alt-idx) point-idx current-alt-idx)\n        (vector-set! (vector-ref result-prev-idxs alt-idx) point-idx current-prev-idx)))\n\n    (define splitss\n      (for/vector #:length number-of-alts\n                  ([alt-idx (in-range number-of-alts)])\n        :\n        (Listof si)\n        (let loop ([i (- number-of-points 1)]\n                   [rest (ann null (Listof si))])\n          (define alt-idx* (vector-ref (vector-ref result-alt-idxs alt-idx) i))\n          (define next (vector-ref (vector-ref result-prev-idxs alt-idx) i))\n          (define sis (cons (si alt-idx* (+ i 1)) rest))\n          (if (< next i)\n              (loop next sis)\n              sis))))\n\n    (define scores\n      (for/flvector #:length number-of-alts\n                    ([alt-idx (in-range number-of-alts)])\n                    (flvector-ref (vector-ref result-error-sums alt-idx) (sub1 number-of-points))))\n    (values splitss scores)))\n\n(require (submod \".\" core))\n"
  },
  {
    "path": "src/core/rules.rkt",
    "content": "#lang racket\n\n;; Arithmetic identities for rewriting programs.\n\n(require \"../utils/common.rkt\"\n         \"../syntax/syntax.rkt\")\n\n(provide *rules*\n         *sound-removal-rules*\n         (struct-out rule))\n\n;; A rule represents \"find-and-replacing\" `input` by `output`. Both\n;; are patterns, meaning that symbols represent pattern variables.\n(struct rule (name input output tags)\n  #:methods gen:custom-write\n  [(define (write-proc rule port mode)\n     (fprintf port \"#<rule ~a>\" (rule-name rule)))])\n\n(define *all-rules* '())\n\n(define (rule-enabled? rule)\n  (ormap (curry flag-set? 'rules) (rule-tags rule)))\n\n(define (*rules*)\n  (filter rule-enabled? *all-rules*))\n\n(define-syntax-rule (define-rule rname group input output)\n  (set! *all-rules* (cons (rule 'rname 'input 'output '(group)) *all-rules*)))\n\n(define-syntax-rule (define-rules group\n                      [rname input output flags ...] ...)\n  (begin\n    (define-rule rname group input output flags ...) ...))\n\n; Commutativity\n(define-rules arithmetic\n  [+-commutative (+ a b) (+ b a)]\n  [*-commutative (* a b) (* b a)])\n\n; Associativity\n(define-rules arithmetic\n  [associate-+r+ (+ a (+ b c)) (+ (+ a b) c)]\n  [associate-+l+ (+ (+ a b) c) (+ a (+ b c))]\n  [associate-+r- (+ a (- b c)) (- (+ a b) c)]\n  [associate-+l- (+ (- a b) c) (- a (- b c))]\n  [associate--r+ (- a (+ b c)) (- (- a b) c)]\n  [associate--l+ (- (+ a b) c) (+ a (- b c))]\n  [associate--l- (- (- a b) c) (- a (+ b c))]\n  [associate--r- (- a (- b c)) (+ (- a b) c)]\n  [associate-*r* (* a (* b c)) (* (* a b) c)]\n  [associate-*l* (* (* a b) c) (* a (* b c))]\n  [associate-*r/ (* a (/ b c)) (/ (* a b) c)]\n  [associate-*l/ (* (/ a b) c) (/ (* a c) b)]\n  [associate-/r* (/ a (* b c)) (/ (/ a b) c)]\n  [associate-/r/ (/ a (/ b c)) (* (/ a b) c)]\n  [associate-/l/ (/ (/ b c) a) (/ b (* c a))]\n  [associate-/l* (/ (* b c) a) (* b (/ c a))])\n\n; Identity\n(define-rules arithmetic\n  [remove-double-div (/ 1 (/ 1 a)) a]\n  [rgt-mult-inverse (* a (/ 1 a)) 1]\n  [lft-mult-inverse (* (/ 1 a) a) 1]\n  [+-inverses (- a a) 0]\n  [div0 (/ 0 a) 0]\n  [mul0-lft (* 0 a) 0]\n  [mul0-rgt (* a 0) 0]\n  [*-inverses (/ a a) 1]\n  [+-lft-identity (+ 0 a) a]\n  [+-rgt-identity (+ a 0) a]\n  [--rgt-identity (- a 0) a]\n  [sub0-neg (- 0 a) (neg a)]\n  [remove-double-neg (neg (neg a)) a]\n  [*-lft-identity (* 1 a) a]\n  [*-rgt-identity (* a 1) a]\n  [/-rgt-identity (/ a 1) a]\n  [mul-1-neg (* -1 a) (neg a)])\n\n; Counting\n(define-rules arithmetic\n  [count-2 (+ x x) (* 2 x)]\n  [2-split 2 (+ 1 1)]\n  [count-2-rev (* 2 x) (+ x x)]\n  [1-split 1 (* 2 1/2)])\n\n; Distributivity\n(define-rules arithmetic\n  [distribute-lft-in (* a (+ b c)) (+ (* a b) (* a c))]\n  [distribute-rgt-in (* a (+ b c)) (+ (* b a) (* c a))]\n  [distribute-lft-out (+ (* a b) (* a c)) (* a (+ b c))]\n  [distribute-lft-out-- (- (* a b) (* a c)) (* a (- b c))]\n  [distribute-rgt-out (+ (* b a) (* c a)) (* a (+ b c))]\n  [distribute-rgt-out-- (- (* b a) (* c a)) (* a (- b c))]\n  [distribute-lft1-in (+ (* b a) a) (* (+ b 1) a)]\n  [distribute-rgt1-in (+ a (* c a)) (* (+ c 1) a)])\n\n; Safe Distributiviity\n(define-rules arithmetic\n  [distribute-lft-neg-in (neg (* a b)) (* (neg a) b)]\n  [distribute-rgt-neg-in (neg (* a b)) (* a (neg b))]\n  [distribute-lft-neg-out (* (neg a) b) (neg (* a b))]\n  [distribute-rgt-neg-out (* a (neg b)) (neg (* a b))]\n  [distribute-neg-in (neg (+ a b)) (+ (neg a) (neg b))]\n  [distribute-neg-out (+ (neg a) (neg b)) (neg (+ a b))]\n  [distribute-frac-neg (/ (neg a) b) (neg (/ a b))]\n  [distribute-frac-neg2 (/ a (neg b)) (neg (/ a b))]\n  [distribute-neg-frac (neg (/ a b)) (/ (neg a) b)]\n  [distribute-neg-frac2 (neg (/ a b)) (/ a (neg b))]\n  [fp-cancel-sign-sub (- a (* (neg b) c)) (+ a (* b c))]\n  [fp-cancel-sub-sign (+ a (* (neg b) c)) (- a (* b c))]\n  [fp-cancel-sign-sub-inv (+ a (* b c)) (- a (* (neg b) c))]\n  [fp-cancel-sub-sign-inv (- a (* b c)) (+ a (* (neg b) c))])\n\n(define-rules arithmetic\n  [sub-flip (- a b) (+ a (neg b))]\n  [sub-flip-reverse (+ a (neg b)) (- a b)]\n  [sub-negate (neg (- b a)) (- a b)]\n  [sub-negate-rev (- a b) (neg (- b a))]\n  [add-flip (+ a b) (- a (neg b))]\n  [add-flip-rev (- a (neg b)) (+ a b)])\n\n; Difference of squares\n(define-rules polynomials\n  [swap-sqr (* (* a b) (* a b)) (* (* a a) (* b b))]\n  [unswap-sqr (* (* a a) (* b b)) (* (* a b) (* a b))]\n  [difference-of-squares (- (* a a) (* b b)) (* (+ a b) (- a b))]\n  [difference-of-sqr-1 (- (* a a) 1) (* (+ a 1) (- a 1))]\n  [difference-of-sqr--1 (+ (* a a) -1) (* (+ a 1) (- a 1))]\n  [pow-sqr (* (pow a b) (pow a b)) (pow a (* 2 b))]\n  [sum-square-pow (pow (+ a b) 2) (+ (+ (pow a 2) (* 2 (* a b))) (pow b 2))]\n  [sub-square-pow (pow (- a b) 2) (+ (- (pow a 2) (* 2 (* a b))) (pow b 2))]\n  [sum-square-pow-rev (+ (+ (pow a 2) (* 2 (* a b))) (pow b 2)) (pow (+ a b) 2)]\n  [sub-square-pow-rev (+ (- (pow a 2) (* 2 (* a b))) (pow b 2)) (pow (- a b) 2)]\n  [difference-of-sqr-1-rev (* (+ a 1) (- a 1)) (- (* a a) 1)]\n  [difference-of-sqr--1-rev (* (+ a 1) (- a 1)) (+ (* a a) -1)]\n  [difference-of-squares-rev (* (+ a b) (- a b)) (- (* a a) (* b b))])\n\n; Mul/div flip\n(define-rules arithmetic\n  [mult-flip (/ a b) (* a (/ 1 b))]\n  [mult-flip-rev (* a (/ 1 b)) (/ a b)]\n  [div-flip (/ a b) (sound-/ 1 (sound-/ b a 0) (/ a b))]\n  [div-flip-rev (/ 1 (/ b a)) (/ a b)])\n\n; Fractions\n(define-rules arithmetic\n  #;[sum-to-mult (+ a b) (* (+ 1 (/ b a)) a) #:unsound] ; unsound @ a = 0, b = 1\n  [sum-to-mult-rev (* (+ 1 (/ b a)) a) (+ a b)]\n  #;[sub-to-mult (- a b) (* (- 1 (/ b a)) a) #:unsound] ; unsound @ a = 0, b = 1\n  [sub-to-mult-rev (* (- 1 (/ b a)) a) (- a b)]\n  [add-to-fraction (+ c (/ b a)) (/ (+ (* c a) b) a)]\n  [add-to-fraction-rev (/ (+ (* c a) b) a) (+ c (/ b a))]\n  [sub-to-fraction (- c (/ b a)) (/ (- (* c a) b) a)]\n  [sub-to-fraction-rev (/ (- (* c a) b) a) (- c (/ b a))]\n  [common-denominator (+ (/ a b) (/ c d)) (/ (+ (* a d) (* c b)) (* b d))])\n\n(define-rules polynomials\n  #;[sqr-pow (pow a b) (* (pow a (/ b 2)) (pow a (/ b 2))) #:unsound] ; unsound @ a = -1, b = 1\n  [flip-+ (+ (sqrt a) (sqrt b)) (sound-/ (- a b) (- (sqrt a) (sqrt b)) (+ (sqrt a) (sqrt b)))]\n  [flip-- (- (sqrt a) (sqrt b)) (sound-/ (- a b) (+ (sqrt a) (sqrt b)) (- (sqrt a) (sqrt b)))])\n\n; Difference of cubes\n(define-rules polynomials\n  [sum-cubes (+ (pow a 3) (pow b 3)) (* (+ (* a a) (- (* b b) (* a b))) (+ a b))]\n  [difference-cubes (- (pow a 3) (pow b 3)) (* (+ (* a a) (+ (* b b) (* a b))) (- a b))]\n  [difference-cubes-rev (* (+ (* a a) (+ (* b b) (* a b))) (- a b)) (- (pow a 3) (pow b 3))]\n  [sum-cubes-rev (* (+ (* a a) (- (* b b) (* a b))) (+ a b)) (+ (pow a 3) (pow b 3))])\n\n(define-rules polynomials\n  [flip3-+\n   (+ (cbrt a) (cbrt b))\n   (sound-/ (+ a b)\n            (+ (* (cbrt a) (cbrt a)) (- (* (cbrt b) (cbrt b)) (* (cbrt a) (cbrt b))))\n            (+ (cbrt a) (cbrt b)))]\n  [flip3--\n   (- (cbrt a) (cbrt b))\n   (sound-/ (- a b)\n            (+ (* (cbrt a) (cbrt a)) (+ (* (cbrt b) (cbrt b)) (* (cbrt a) (cbrt b))))\n            (- (cbrt a) (cbrt b)))])\n\n; Dealing with fractions\n(define-rules fractions\n  [div-sub (/ (- a b) c) (- (/ a c) (/ b c))]\n  [times-frac (/ (* a b) (* c d)) (* (/ a c) (/ b d))]\n  [div-add (/ (+ a b) c) (+ (/ a c) (/ b c))]\n  [div-add-rev (+ (/ a c) (/ b c)) (/ (+ a b) c)]\n  [sub-div (- (/ a c) (/ b c)) (/ (- a b) c)]\n  [frac-add (+ (/ a b) (/ c d)) (/ (+ (* a d) (* b c)) (* b d))]\n  [frac-sub (- (/ a b) (/ c d)) (/ (- (* a d) (* b c)) (* b d))]\n  [frac-times (* (/ a b) (/ c d)) (/ (* a c) (* b d))]\n  [frac-2neg (/ a b) (/ (neg a) (neg b))]\n  [frac-2neg-rev (/ (neg a) (neg b)) (/ a b)])\n\n; Square root\n(define-rules arithmetic\n  [rem-square-sqrt (* (sqrt x) (sqrt x)) x]\n  [rem-sqrt-square (sqrt (* x x)) (fabs x)]\n  [rem-sqrt-square-rev (fabs x) (sqrt (* x x))]\n  [sqr-neg (* (neg x) (neg x)) (* x x)]\n  [sqr-abs (* (fabs x) (fabs x)) (* x x)]\n  [sqr-abs-rev (* x x) (* (fabs x) (fabs x))]\n  [sqr-neg-rev (* x x) (* (neg x) (neg x))]\n  [sqrt-cbrt (sqrt (cbrt x)) (cbrt (sqrt x))]\n  [cbrt-sqrt (cbrt (sqrt x)) (sqrt (cbrt x))])\n\n; Absolute value\n(define-rules arithmetic\n  [fabs-fabs (fabs (fabs x)) (fabs x)]\n  [fabs-sub (fabs (- a b)) (fabs (- b a))]\n  [fabs-add (fabs (+ (fabs a) (fabs b))) (+ (fabs a) (fabs b))]\n  [fabs-neg (fabs (neg x)) (fabs x)]\n  [fabs-sqr (fabs (* x x)) (* x x)]\n  [fabs-mul (fabs (* a b)) (* (fabs a) (fabs b))]\n  [fabs-div (fabs (/ a b)) (/ (fabs a) (fabs b))]\n  [neg-fabs (fabs x) (fabs (neg x))]\n  [mul-fabs (* (fabs a) (fabs b)) (fabs (* a b))]\n  [div-fabs (/ (fabs a) (fabs b)) (fabs (/ a b))]\n  [sqrt-fabs (fabs (sqrt a)) (sqrt a)]\n  [sqrt-fabs-rev (sqrt a) (fabs (sqrt a))]\n  [fabs-lhs-div (/ (fabs x) x) (copysign 1 x)]\n  [fabs-rhs-div (/ x (fabs x)) (copysign 1 x)]\n  [fabs-cbrt (fabs (/ (cbrt a) a)) (/ (cbrt a) a)]\n  [fabs-cbrt-rev (/ (cbrt a) a) (fabs (/ (cbrt a) a))])\n\n; Copysign\n(define-rules arithmetic\n  [copysign-neg (copysign a (neg b)) (neg (copysign a b))]\n  [neg-copysign (neg (copysign a b)) (copysign a (neg b))]\n  [copysign-other-neg (copysign (neg a) b) (copysign a b)]\n  [copysign-fabs (copysign a (fabs b)) (fabs a)]\n  [copysign-other-fabs (copysign (fabs a) b) (copysign a b)]\n  [fabs-copysign (fabs (copysign a b)) (fabs a)])\n\n; Square root\n(define-rules arithmetic\n  [sqrt-pow2 (pow (sqrt x) y) (pow x (/ y 2))]\n  [sqrt-unprod (* (sqrt x) (sqrt y)) (sqrt (* x y))]\n  [sqrt-undiv (/ (sqrt x) (sqrt y)) (sqrt (/ x y))])\n\n(define-rules arithmetic\n  [sqrt-prod (sqrt (* x y)) (* (sqrt (fabs x)) (sqrt (fabs y)))]\n  [sqrt-div (sqrt (/ x y)) (/ (sqrt (fabs x)) (sqrt (fabs y)))]\n  #;[add-sqr-sqrt x (copysign (* (sqrt (fabs x)) (sqrt (fabs x))) x)])\n\n; Cubing\n(define-rules arithmetic\n  [rem-cube-cbrt (pow (cbrt x) 3) x]\n  [rem-cbrt-cube (cbrt (pow x 3)) x]\n  [rem-3cbrt-lft (* (* (cbrt x) (cbrt x)) (cbrt x)) x]\n  [rem-3cbrt-rft (* (cbrt x) (* (cbrt x) (cbrt x))) x]\n  [cube-neg (pow (neg x) 3) (neg (pow x 3))]\n  [cube-neg-rev (neg (pow x 3)) (pow (neg x) 3)]\n  [cube-prod (pow (* x y) 3) (* (pow x 3) (pow y 3))]\n  [cube-div (pow (/ x y) 3) (/ (pow x 3) (pow y 3))]\n  [cube-mult (pow x 3) (* x (* x x))]\n  [cube-prod-rev (* (pow x 3) (pow y 3)) (pow (* x y) 3)]\n  [cube-div-rev (/ (pow x 3) (pow y 3)) (pow (/ x y) 3)])\n\n; Cube root\n(define-rules arithmetic\n  [cbrt-prod (cbrt (* x y)) (* (cbrt x) (cbrt y))]\n  [cbrt-div (cbrt (/ x y)) (/ (cbrt x) (cbrt y))]\n  [cbrt-unprod (* (cbrt x) (cbrt y)) (cbrt (* x y))]\n  [cbrt-undiv (/ (cbrt x) (cbrt y)) (cbrt (/ x y))]\n  [pow-cbrt (pow (cbrt x) y) (pow x (/ y 3))]\n  [cbrt-pow (cbrt (pow x y)) (pow x (/ y 3))]\n  #;[add-cube-cbrt x (* (* (cbrt x) (cbrt x)) (cbrt x))]\n  #;[add-cbrt-cube x (cbrt (* (* x x) x))]\n  [cube-unmult (* x (* x x)) (pow x 3)]\n  [cbrt-neg (cbrt (neg x)) (neg (cbrt x))]\n  [cbrt-neg-rev (neg (cbrt x)) (cbrt (neg x))]\n  [cbrt-fabs (cbrt (fabs x)) (fabs (cbrt x))]\n  [cbrt-fabs-rev (fabs (cbrt x)) (cbrt (fabs x))]\n  [cbrt-div-cbrt (/ (cbrt x) (fabs (cbrt x))) (copysign 1 x)]\n  [cbrt-div-cbrt2 (/ (fabs (cbrt x)) (cbrt x)) (copysign 1 x)])\n\n; Min and max\n(define-rules arithmetic\n  [fmin-swap (fmin a b) (fmin b a)]\n  [fmax-swap (fmax a b) (fmax b a)])\n\n; Exponentials\n(define-rules exponents\n  #;[add-log-exp x (log (exp x))]\n  #;[add-exp-log x (exp (log x)) #:unsound] ; unsound @ x = -1\n  [rem-exp-log (exp (log x)) x]\n  [rem-log-exp (log (exp x)) x])\n\n(define-rules exponents\n  [exp-0 (exp 0) 1]\n  [exp-1-e (exp 1) (E)]\n  [1-exp 1 (exp 0)]\n  [e-exp-1 (E) (exp 1)]\n  [exp-fabs (exp x) (fabs (exp x))]\n  [fabs-exp (fabs (exp x)) (exp x)])\n\n(define-rules exponents\n  [exp-sum (exp (+ a b)) (* (exp a) (exp b))]\n  [exp-neg (exp (neg a)) (/ 1 (exp a))]\n  [exp-diff (exp (- a b)) (/ (exp a) (exp b))]\n  [prod-exp (* (exp a) (exp b)) (exp (+ a b))]\n  [rec-exp (/ 1 (exp a)) (exp (neg a))]\n  [div-exp (/ (exp a) (exp b)) (exp (- a b))]\n  [exp-prod (exp (* a b)) (pow (exp a) b)]\n  [exp-sqrt (exp (/ a 2)) (sqrt (exp a))]\n  [exp-cbrt (exp (/ a 3)) (cbrt (exp a))]\n  [exp-lft-sqr (exp (* a 2)) (* (exp a) (exp a))]\n  [exp-lft-cube (exp (* a 3)) (pow (exp a) 3)]\n  [exp-cbrt-rev (cbrt (exp a)) (exp (/ a 3))]\n  [exp-lft-cube-rev (pow (exp a) 3) (exp (* a 3))]\n  [exp-sqrt-rev (sqrt (exp a)) (exp (/ a 2))]\n  [exp-lft-sqr-rev (* (exp a) (exp a)) (exp (* a 2))])\n\n; Powers\n(define-rules exponents\n  [unpow-1 (pow a -1) (/ 1 a)]\n  [unpow1 (pow a 1) a]\n  [unpow0 (pow a 0) 1]\n  [pow-base-1 (pow 1 a) 1]\n  [pow1 a (pow a 1)]\n  [unpow1/2 (pow a 1/2) (sqrt a)]\n  [unpow2 (pow a 2) (* a a)]\n  [unpow3 (pow a 3) (* (* a a) a)]\n  [unpow1/3 (pow a 1/3) (cbrt a)]\n  [pow-base-0 (pow 0 a) 0]\n  [inv-pow (/ 1 a) (pow a -1)])\n\n(define-rules exponents\n  [pow1/2 (sqrt a) (pow a 1/2)]\n  [pow2 (* a a) (pow a 2)]\n  [pow1/3 (cbrt a) (pow a 1/3)]\n  [pow3 (* (* a a) a) (pow a 3)])\n\n(define-rules exponents\n  [exp-to-pow (exp (* (log a) b)) (pow a b)]\n  [pow-plus (* (pow a b) a) (pow a (+ b 1))]\n  [pow-exp (pow (exp a) b) (exp (* a b))]\n  [pow-prod-down (* (pow b a) (pow c a)) (pow (* b c) a)]\n  [pow-prod-up (* (pow a b) (pow a c)) (pow a (+ b c))]\n  [pow-flip (/ 1 (pow a b)) (pow a (neg b))]\n  [pow-div (/ (pow a b) (pow a c)) (pow a (- b c))])\n\n(define-rules exponents\n  [pow-plus-rev (pow a (+ b 1)) (* (sound-pow a b 1) a)]\n  [pow-neg (pow a (neg b)) (sound-/ 1 (sound-pow a b 0) 0)])\n\n(define-rules exponents\n  #;[pow-to-exp (pow a b) (exp (* (log a) b)) #:unsound] ; unsound @ a = -1, b = 1\n  #;[pow-add (pow a (+ b c)) (* (pow a b) (pow a c)) #:unsound] ; unsound @ a = -1, b = c = 1/2\n  #;[pow-sub (pow a (- b c)) (/ (pow a b) (pow a c)) #:unsound] ; unsound @ a = -1, b = c = 1/2\n  #;\n  [unpow-prod-down (pow (* b c) a) (* (pow b a) (pow c a)) #:unsound]) ; unsound @ a = 1/2, b = c = -1\n\n; Logarithms\n(define-rules exponents\n  [log-rec (log (/ 1 a)) (neg (log a))]\n  [log-E (log (E)) 1]\n  [log-pow-rev (* b (log a)) (log (pow a b))])\n\n(define-rules exponents\n  [log-prod (log (* a b)) (+ (log (fabs a)) (log (fabs b)))]\n  [log-div (log (/ a b)) (- (log (fabs a)) (log (fabs b)))]\n  [log-pow (log (pow a b)) (* b (sound-log (fabs a) 0))])\n\n(define-rules exponents\n  [sum-log (+ (log a) (log b)) (log (* a b))]\n  [diff-log (- (log a) (log b)) (log (/ a b))]\n  [neg-log (neg (log a)) (log (/ 1 a))])\n\n; Trigonometry\n(define-rules trigonometry\n  [sin-0 (sin 0) 0]\n  [cos-0 (cos 0) 1]\n  [tan-0 (tan 0) 0])\n\n(define-rules trigonometry\n  [sin-neg (sin (neg x)) (neg (sin x))]\n  [cos-neg (cos (neg x)) (cos x)]\n  [cos-fabs (cos (fabs x)) (cos x)]\n  [tan-neg (tan (neg x)) (neg (tan x))]\n  [cos-neg-rev (cos x) (cos (neg x))]\n  [cos-fabs-rev (cos x) (cos (fabs x))]\n  [sin-neg-rev (neg (sin x)) (sin (neg x))]\n  [tan-neg-rev (neg (tan x)) (tan (neg x))])\n\n(define-rules trignometry\n  [sqr-sin-b (* (sin x) (sin x)) (- 1 (* (cos x) (cos x)))]\n  [sqr-cos-b (* (cos x) (cos x)) (- 1 (* (sin x) (sin x)))]\n  [sqr-cos-b-rev (- 1 (* (sin x) (sin x))) (* (cos x) (cos x))]\n  [sqr-sin-b-rev (- 1 (* (cos x) (cos x))) (* (sin x) (sin x))])\n\n(define-rules trigonometry\n  [sin-asin (sin (asin x)) x]\n  [cos-acos (cos (acos x)) x]\n  [tan-atan (tan (atan x)) x]\n  [atan-tan (atan (tan x)) (remainder x (PI))]\n  [asin-sin (asin (sin x)) (- (fabs (remainder (+ x (/ (PI) 2)) (* 2 (PI)))) (/ (PI) 2))]\n  [acos-cos (acos (cos x)) (fabs (remainder x (* 2 (PI))))]\n  [acos-cos-rev (fabs (remainder x (* 2 (PI)))) (acos (cos x))]\n  [asin-sin-rev (- (fabs (remainder (+ x (/ (PI) 2)) (* 2 (PI)))) (/ (PI) 2)) (asin (sin x))])\n\n(define-rules trigonometry\n  [cos-sin-sum (+ (* (cos a) (cos a)) (* (sin a) (sin a))) 1]\n  [1-sub-cos (- 1 (* (cos a) (cos a))) (* (sin a) (sin a))]\n  [1-sub-sin (- 1 (* (sin a) (sin a))) (* (cos a) (cos a))]\n  [-1-add-cos (+ (* (cos a) (cos a)) -1) (neg (* (sin a) (sin a)))]\n  [-1-add-sin (+ (* (sin a) (sin a)) -1) (neg (* (cos a) (cos a)))]\n  [sub-1-cos (- (* (cos a) (cos a)) 1) (neg (* (sin a) (sin a)))]\n  [sub-1-sin (- (* (sin a) (sin a)) 1) (neg (* (cos a) (cos a)))]\n  [sin-PI/6 (sin (/ (PI) 6)) 1/2]\n  [sin-PI/4 (sin (/ (PI) 4)) (/ (sqrt 2) 2)]\n  [sin-PI/3 (sin (/ (PI) 3)) (/ (sqrt 3) 2)]\n  [sin-PI/2 (sin (/ (PI) 2)) 1]\n  [sin-PI (sin (PI)) 0]\n  [sin-+PI (sin (+ x (PI))) (neg (sin x))]\n  [sin-+PI/2 (sin (+ x (/ (PI) 2))) (cos x)]\n  [cos-PI/6 (cos (/ (PI) 6)) (/ (sqrt 3) 2)]\n  [cos-PI/4 (cos (/ (PI) 4)) (/ (sqrt 2) 2)]\n  [cos-PI/3 (cos (/ (PI) 3)) 1/2]\n  [cos-PI/2 (cos (/ (PI) 2)) 0]\n  [cos-PI (cos (PI)) -1]\n  [cos-+PI (cos (+ x (PI))) (neg (cos x))]\n  [cos-+PI/2 (cos (+ x (/ (PI) 2))) (neg (sin x))]\n  [tan-PI/6 (tan (/ (PI) 6)) (/ 1 (sqrt 3))]\n  [tan-PI/4 (tan (/ (PI) 4)) 1]\n  [tan-PI/3 (tan (/ (PI) 3)) (sqrt 3)]\n  [tan-PI (tan (PI)) 0]\n  [tan-+PI (tan (+ x (PI))) (tan x)]\n  [hang-0p-tan (/ (sin a) (+ 1 (cos a))) (tan (/ a 2))]\n  [hang-0m-tan (/ (neg (sin a)) (+ 1 (cos a))) (tan (/ (neg a) 2))]\n  [hang-p0-tan (/ (- 1 (cos a)) (sin a)) (tan (/ a 2))]\n  [hang-m0-tan (/ (- 1 (cos a)) (neg (sin a))) (tan (/ (neg a) 2))]\n  [hang-p-tan (/ (+ (sin a) (sin b)) (+ (cos a) (cos b))) (tan (/ (+ a b) 2))]\n  [hang-m-tan (/ (- (sin a) (sin b)) (+ (cos a) (cos b))) (tan (/ (- a b) 2))])\n\n(define-rules trigonometry\n  [1-sub-sin-rev (* (cos a) (cos a)) (- 1 (* (sin a) (sin a)))]\n  [hang-0m-tan-rev (tan (/ (neg a) 2)) (/ (neg (sin a)) (+ 1 (cos a)))]\n  [hang-0p-tan-rev (tan (/ a 2)) (/ (sin a) (+ 1 (cos a)))]\n  [tan-+PI-rev (tan x) (tan (+ x (PI)))]\n  [cos-+PI/2-rev (neg (sin x)) (cos (+ x (/ (PI) 2)))]\n  [sin-+PI/2-rev (cos x) (sin (+ x (/ (PI) 2)))]\n  [sin-+PI-rev (neg (sin x)) (sin (+ x (PI)))]\n  [cos-+PI-rev (neg (cos x)) (cos (+ x (PI)))]\n  [neg-tan-+PI/2-rev (/ -1 (tan x)) (tan (+ x (/ (PI) 2)))]\n  [tan-+PI/2-rev (/ 1 (tan x)) (tan (+ (neg x) (/ (PI) 2)))])\n\n(define-rules trigonometry\n  [sin-sum (sin (+ x y)) (+ (* (sin x) (cos y)) (* (cos x) (sin y)))]\n  [cos-sum (cos (+ x y)) (- (* (cos x) (cos y)) (* (sin x) (sin y)))]\n  [sin-diff (sin (- x y)) (- (* (sin x) (cos y)) (* (cos x) (sin y)))]\n  [cos-diff (cos (- x y)) (+ (* (cos x) (cos y)) (* (sin x) (sin y)))]\n  [sin-2 (sin (* 2 x)) (* 2 (* (sin x) (cos x)))]\n  [sin-3 (sin (* 3 x)) (- (* 3 (sin x)) (* 4 (pow (sin x) 3)))]\n  [2-sin (* 2 (* (sin x) (cos x))) (sin (* 2 x))]\n  [3-sin (- (* 3 (sin x)) (* 4 (pow (sin x) 3))) (sin (* 3 x))]\n  [cos-2 (cos (* 2 x)) (- (* (cos x) (cos x)) (* (sin x) (sin x)))]\n  [cos-3 (cos (* 3 x)) (- (* 4 (pow (cos x) 3)) (* 3 (cos x)))]\n  [2-cos (- (* (cos x) (cos x)) (* (sin x) (sin x))) (cos (* 2 x))]\n  [3-cos (- (* 4 (pow (cos x) 3)) (* 3 (cos x))) (cos (* 3 x))])\n\n(define-rules trigonometry\n  [cos-diff-rev (+ (* (cos x) (cos y)) (* (sin x) (sin y))) (cos (- x y))]\n  [sin-diff-rev (- (* (sin x) (cos y)) (* (cos x) (sin y))) (sin (- x y))]\n  [sin-sum-rev (+ (* (sin x) (cos y)) (* (cos x) (sin y))) (sin (+ x y))]\n  [tan-sum-rev (/ (+ (tan x) (tan y)) (- 1 (* (tan x) (tan y)))) (tan (+ x y))]\n  [cos-sum-rev (- (* (cos x) (cos y)) (* (sin x) (sin y))) (cos (+ x y))])\n\n(define-rules trigonometry\n  [sqr-sin-a (* (sin x) (sin x)) (- 1/2 (* 1/2 (cos (* 2 x))))]\n  [sqr-cos-a (* (cos x) (cos x)) (+ 1/2 (* 1/2 (cos (* 2 x))))]\n  [diff-sin (- (sin x) (sin y)) (* 2 (* (sin (/ (- x y) 2)) (cos (/ (+ x y) 2))))]\n  [diff-cos (- (cos x) (cos y)) (* -2 (* (sin (/ (- x y) 2)) (sin (/ (+ x y) 2))))]\n  [sum-sin (+ (sin x) (sin y)) (* 2 (* (sin (/ (+ x y) 2)) (cos (/ (- x y) 2))))]\n  [sum-cos (+ (cos x) (cos y)) (* 2 (* (cos (/ (+ x y) 2)) (cos (/ (- x y) 2))))]\n  [cos-mult (* (cos x) (cos y)) (/ (+ (cos (+ x y)) (cos (- x y))) 2)]\n  [sin-mult (* (sin x) (sin y)) (/ (- (cos (- x y)) (cos (+ x y))) 2)]\n  [sin-cos-mult (* (sin x) (cos y)) (/ (+ (sin (- x y)) (sin (+ x y))) 2)]\n  [diff-atan (- (atan x) (atan y)) (atan2 (- x y) (+ 1 (* x y)))]\n  [sum-atan (+ (atan x) (atan y)) (atan2 (+ x y) (- 1 (* x y)))]\n  [tan-quot (tan x) (/ (sin x) (cos x))]\n  [quot-tan (/ (sin x) (cos x)) (tan x)]\n  [2-tan (/ (* 2 (tan x)) (- 1 (* (tan x) (tan x)))) (tan (* 2 x))])\n\n(define-rules trigonometry\n  [diff-cos-rev (* -2 (* (sin (/ (- x y) 2)) (sin (/ (+ x y) 2)))) (- (cos x) (cos y))]\n  [diff-sin-rev (* 2 (* (sin (/ (- x y) 2)) (cos (/ (+ x y) 2)))) (- (sin x) (sin y))]\n  [diff-atan-rev (atan2 (- x y) (+ 1 (* x y))) (- (atan x) (atan y))]\n  [sum-sin-rev (* 2 (* (sin (/ (+ x y) 2)) (cos (/ (- x y) 2)))) (+ (sin x) (sin y))]\n  [sum-cos-rev (* 2 (* (cos (/ (+ x y) 2)) (cos (/ (- x y) 2)))) (+ (cos x) (cos y))]\n  [sum-atan-rev (atan2 (+ x y) (- 1 (* x y))) (+ (atan x) (atan y))]\n  [sqr-cos-a-rev (+ 1/2 (* 1/2 (cos (* 2 x)))) (* (cos x) (cos x))]\n  [sqr-sin-a-rev (- 1/2 (* 1/2 (cos (* 2 x)))) (* (sin x) (sin x))]\n  [cos-mult-rev (/ (+ (cos (+ x y)) (cos (- x y))) 2) (* (cos x) (cos y))]\n  [sin-mult-rev (/ (- (cos (- x y)) (cos (+ x y))) 2) (* (sin x) (sin y))]\n  [sin-cos-mult-rev (/ (+ (sin (- x y)) (sin (+ x y))) 2) (* (sin x) (cos y))])\n\n(define-rules trigonometry\n  [cos-asin (cos (asin x)) (sqrt (- 1 (* x x)))]\n  [tan-asin (tan (asin x)) (/ x (sqrt (- 1 (* x x))))]\n  [sin-acos (sin (acos x)) (sqrt (- 1 (* x x)))]\n  [tan-acos (tan (acos x)) (/ (sqrt (- 1 (* x x))) x)]\n  [sin-atan (sin (atan x)) (/ x (sqrt (+ 1 (* x x))))]\n  [cos-atan (cos (atan x)) (/ 1 (sqrt (+ 1 (* x x))))]\n  [asin-acos (asin x) (- (/ (PI) 2) (acos x))]\n  [acos-asin (acos x) (- (/ (PI) 2) (asin x))]\n  [asin-neg (asin (neg x)) (neg (asin x))]\n  [acos-neg (acos (neg x)) (- (PI) (acos x))]\n  [atan-neg (atan (neg x)) (neg (atan x))])\n\n(define-rules trigonometry\n  [acos-asin-rev (- (/ (PI) 2) (asin x)) (acos x)]\n  [asin-acos-rev (- (/ (PI) 2) (acos x)) (asin x)]\n  [asin-neg-rev (neg (asin x)) (asin (neg x))]\n  [atan-neg-rev (neg (atan x)) (atan (neg x))]\n  [acos-neg-rev (- (PI) (acos x)) (acos (neg x))]\n  [cos-atan-rev (/ 1 (sqrt (+ 1 (* x x)))) (cos (atan x))]\n  [tan-acos-rev (/ (sqrt (- 1 (* x x))) x) (tan (acos x))]\n  [tan-asin-rev (/ x (sqrt (- 1 (* x x)))) (tan (asin x))]\n  [cos-asin-rev (sqrt (- 1 (* x x))) (cos (asin x))]\n  [sin-atan-rev (/ x (sqrt (+ 1 (* x x)))) (sin (atan x))]\n  [sin-acos-rev (sqrt (- 1 (* x x))) (sin (acos x))])\n\n; Hyperbolic trigonometric functions\n(define-rules hyperbolic\n  [sinh-def (sinh x) (/ (- (exp x) (exp (neg x))) 2)]\n  [cosh-def (cosh x) (/ (+ (exp x) (exp (neg x))) 2)]\n  [tanh-def-a (tanh x) (/ (- (exp x) (exp (neg x))) (+ (exp x) (exp (neg x))))]\n  [tanh-def-b (tanh x) (/ (- (exp (* 2 x)) 1) (+ (exp (* 2 x)) 1))]\n  [tanh-def-c (tanh x) (/ (- 1 (exp (* -2 x))) (+ 1 (exp (* -2 x))))]\n  [sinh-cosh (- (* (cosh x) (cosh x)) (* (sinh x) (sinh x))) 1]\n  [sinh-+-cosh (+ (cosh x) (sinh x)) (exp x)]\n  [sinh---cosh (- (cosh x) (sinh x)) (exp (neg x))])\n\n(define-rules hyperbolic\n  [tanh-def-b-rev (/ (- (exp (* 2 x)) 1) (+ (exp (* 2 x)) 1)) (tanh x)]\n  [tanh-def-c-rev (/ (- 1 (exp (* -2 x))) (+ 1 (exp (* -2 x)))) (tanh x)]\n  [sinh-def-rev (/ (- (exp x) (exp (neg x))) 2) (sinh x)]\n  [cosh-def-rev (/ (+ (exp x) (exp (neg x))) 2) (cosh x)]\n  [sinh-+-cosh-rev (exp x) (+ (cosh x) (sinh x))]\n  [sinh---cosh-rev (exp (neg x)) (- (cosh x) (sinh x))])\n\n(define-rules hyperbolic\n  [sinh-undef (- (exp x) (exp (neg x))) (* 2 (sinh x))]\n  [cosh-undef (+ (exp x) (exp (neg x))) (* 2 (cosh x))]\n  [tanh-undef (/ (- (exp x) (exp (neg x))) (+ (exp x) (exp (neg x)))) (tanh x)] ;\n  [cosh-sum (cosh (+ x y)) (+ (* (cosh x) (cosh y)) (* (sinh x) (sinh y)))]\n  [cosh-diff (cosh (- x y)) (- (* (cosh x) (cosh y)) (* (sinh x) (sinh y)))]\n  [cosh-2 (cosh (* 2 x)) (+ (* (sinh x) (sinh x)) (* (cosh x) (cosh x)))]\n  [cosh-1/2 (cosh (/ x 2)) (sqrt (/ (+ (cosh x) 1) 2))]\n  [sinh-sum (sinh (+ x y)) (+ (* (sinh x) (cosh y)) (* (cosh x) (sinh y)))]\n  [sinh-diff (sinh (- x y)) (- (* (sinh x) (cosh y)) (* (cosh x) (sinh y)))]\n  [sinh-2 (sinh (* 2 x)) (* 2 (* (sinh x) (cosh x)))]\n  [sinh-1/2 (sinh (/ x 2)) (/ (sinh x) (sqrt (* 2 (+ (cosh x) 1))))]\n  [tanh-2 (tanh (* 2 x)) (/ (* 2 (tanh x)) (+ 1 (* (tanh x) (tanh x))))]\n  [tanh-1/2 (tanh (/ x 2)) (/ (sinh x) (+ (cosh x) 1))]\n  [sum-sinh (+ (sinh x) (sinh y)) (* 2 (* (sinh (/ (+ x y) 2)) (cosh (/ (- x y) 2))))]\n  [sum-cosh (+ (cosh x) (cosh y)) (* 2 (* (cosh (/ (+ x y) 2)) (cosh (/ (- x y) 2))))]\n  [diff-sinh (- (sinh x) (sinh y)) (* 2 (* (cosh (/ (+ x y) 2)) (sinh (/ (- x y) 2))))]\n  [diff-cosh (- (cosh x) (cosh y)) (* 2 (* (sinh (/ (+ x y) 2)) (sinh (/ (- x y) 2))))]\n  [tanh-sum (tanh (+ x y)) (/ (+ (tanh x) (tanh y)) (+ 1 (* (tanh x) (tanh y))))])\n\n(define-rules hyperbolic\n  [sinh-undef-rev (* 2 (sinh x)) (- (exp x) (exp (neg x)))]\n  [cosh-undef-rev (* 2 (cosh x)) (+ (exp x) (exp (neg x)))]\n  [diff-cosh-rev (* 2 (* (sinh (/ (+ x y) 2)) (sinh (/ (- x y) 2)))) (- (cosh x) (cosh y))]\n  [diff-sinh-rev (* 2 (* (cosh (/ (+ x y) 2)) (sinh (/ (- x y) 2)))) (- (sinh x) (sinh y))]\n  [cosh-diff-rev (- (* (cosh x) (cosh y)) (* (sinh x) (sinh y))) (cosh (- x y))]\n  [sinh-diff-rev (- (* (sinh x) (cosh y)) (* (cosh x) (sinh y))) (sinh (- x y))]\n  [tanh-1/2-rev (/ (sinh x) (+ (cosh x) 1)) (tanh (/ x 2))]\n  [tanh-1/2*-rev (/ (- (cosh x) 1) (sinh x)) (tanh (/ x 2))]\n  [tanh-2-rev (/ (* 2 (tanh x)) (+ 1 (* (tanh x) (tanh x)))) (tanh (* 2 x))]\n  [sinh-1/2-rev (/ (sinh x) (sqrt (* 2 (+ (cosh x) 1)))) (sinh (/ x 2))]\n  [cosh-1/2-rev (sqrt (/ (+ (cosh x) 1) 2)) (cosh (/ x 2))]\n  [sinh-2-rev (* 2 (* (sinh x) (cosh x))) (sinh (* 2 x))]\n  [cosh-2-rev (+ (* (sinh x) (sinh x)) (* (cosh x) (cosh x))) (cosh (* 2 x))]\n  [sinh-sum-rev (+ (* (sinh x) (cosh y)) (* (cosh x) (sinh y))) (sinh (+ x y))]\n  [tanh-sum-rev (/ (+ (tanh x) (tanh y)) (+ 1 (* (tanh x) (tanh y)))) (tanh (+ x y))]\n  [cosh-sum-rev (+ (* (cosh x) (cosh y)) (* (sinh x) (sinh y))) (cosh (+ x y))]\n  [sum-cosh-rev (* 2 (* (cosh (/ (+ x y) 2)) (cosh (/ (- x y) 2)))) (+ (cosh x) (cosh y))]\n  [sum-sinh-rev (* 2 (* (sinh (/ (+ x y) 2)) (cosh (/ (- x y) 2)))) (+ (sinh x) (sinh y))])\n\n(define-rules hyperbolic\n  [sinh-neg (sinh (neg x)) (neg (sinh x))]\n  [sinh-0 (sinh 0) 0]\n  [sinh-0-rev 0 (sinh 0)]\n  [cosh-neg (cosh (neg x)) (cosh x)]\n  [cosh-0 (cosh 0) 1]\n  [cosh-0-rev 1 (cosh 0)]\n  [cosh-neg-rev (cosh x) (cosh (neg x))]\n  [sinh-neg-rev (neg (sinh x)) (sinh (neg x))])\n\n(define-rules hyperbolic\n  [asinh-def (asinh x) (log (+ x (sqrt (+ (* x x) 1))))]\n  [acosh-def (acosh x) (log (+ x (sqrt (- (* x x) 1))))]\n  [atanh-def (atanh x) (/ (log (/ (+ 1 x) (- 1 x))) 2)]\n  [sinh-asinh (sinh (asinh x)) x]\n  [sinh-acosh (sinh (acosh x)) (sqrt (- (* x x) 1))]\n  [sinh-atanh (sinh (atanh x)) (/ x (sqrt (- 1 (* x x))))]\n  [cosh-asinh (cosh (asinh x)) (sqrt (+ (* x x) 1))]\n  [cosh-acosh (cosh (acosh x)) x]\n  [cosh-atanh (cosh (atanh x)) (/ 1 (sqrt (- 1 (* x x))))]\n  [tanh-asinh (tanh (asinh x)) (/ x (sqrt (+ 1 (* x x))))]\n  [tanh-acosh (tanh (acosh x)) (/ (sqrt (- (* x x) 1)) x)]\n  [tanh-atanh (tanh (atanh x)) x])\n\n(define-rules hyperbolic\n  [asinh-def-rev (log (+ x (sqrt (+ (* x x) 1)))) (asinh x)]\n  [atanh-def-rev (/ (log (/ (+ 1 x) (- 1 x))) 2) (atanh x)]\n  [acosh-def-rev (log (+ x (sqrt (- (* x x) 1)))) (acosh x)]\n  [tanh-asinh-rev (/ x (sqrt (+ 1 (* x x)))) (tanh (asinh x))]\n  [cosh-asinh-rev (sqrt (+ (* x x) 1)) (cosh (asinh x))]\n  [sinh-atanh-rev (/ x (sqrt (- 1 (* x x)))) (sinh (atanh x))]\n  [cosh-atanh-rev (/ 1 (sqrt (- 1 (* x x)))) (cosh (atanh x))]\n  [asinh-2 (acosh (+ (* 2 (* x x)) 1)) (* 2 (asinh (fabs x)))]\n  [acosh-2-rev (* 2 (acosh x)) (acosh (- (* 2 (* x x)) 1))])\n\n(define-rules special\n  [erf-0 (erf 0) 0]\n  [erf-neg (erf (neg x)) (neg (erf x))]\n  [erf-neg-rev (neg (erf x)) (erf (neg x))]\n  [erfc-0 (erfc 0) 1])\n\n(define-rules trigonometry\n  [asin-0 (asin 0) 0]\n  [asin-1 (asin 1) (/ (PI) 2)]\n  [asin--1 (asin -1) (neg (/ (PI) 2))]\n  [asin-1/2 (asin 1/2) (/ (PI) 6)]\n  [asin--1/2 (asin -1/2) (neg (/ (PI) 6))]\n  [asin-sqrt2/2 (asin (/ (sqrt 2) 2)) (/ (PI) 4)]\n  [asin--sqrt2/2 (asin (/ (neg (sqrt 2)) 2)) (neg (/ (PI) 4))]\n  [asin-sqrt3/2 (asin (/ (sqrt 3) 2)) (/ (PI) 3)]\n  [asin--sqrt3/2 (asin (/ (neg (sqrt 3)) 2)) (neg (/ (PI) 3))]\n  [acos-1 (acos 1) 0]\n  [acos-0 (acos 0) (/ (PI) 2)]\n  [acos--1 (acos -1) (PI)]\n  [acos-1/2 (acos 1/2) (/ (PI) 3)]\n  [acos--1/2 (acos -1/2) (/ (* 2 (PI)) 3)]\n  [acos-sqrt2/2 (acos (/ (sqrt 2) 2)) (/ (PI) 4)]\n  [acos--sqrt2/2 (acos (/ (neg (sqrt 2)) 2)) (/ (* 3 (PI)) 4)]\n  [acos-sqrt3/2 (acos (/ (sqrt 3) 2)) (/ (PI) 6)]\n  [acos--sqrt3/2 (acos (/ (neg (sqrt 3)) 2)) (/ (* 5 (PI)) 6)]\n  [atan-0 (atan 0) 0]\n  [atan-1 (atan 1) (/ (PI) 4)]\n  [atan--1 (atan -1) (neg (/ (PI) 4))])\n\n(define-rules hyperbolic\n  [asinh-0 (asinh 0) 0]\n  [acosh-1 (acosh 1) 0]\n  [atanh-0 (atanh 0) 0])\n\n; Sound-X removal rules: run these before lowering\n(define (*sound-removal-rules*)\n  (list (rule 'remove-sound-/ '(sound-/ a b fallback) '(/ a b) '(sound-removal))\n        (rule 'remove-sound-pow '(sound-pow a b fallback) '(pow a b) '(sound-removal))\n        (rule 'remove-sound-log '(sound-log a fallback) '(log a) '(sound-removal))))\n"
  },
  {
    "path": "src/core/sampling.rkt",
    "content": "#lang racket\n(require math/bigfloat\n         math/base\n         (only-in fpbench interval range-table-ref condition->range-table [expr? fpcore-expr?]))\n(require \"../utils/common.rkt\"\n         \"../utils/errors.rkt\"\n         \"../syntax/float.rkt\"\n         \"../utils/timeline.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/batch.rkt\"\n         \"searchreals.rkt\"\n         \"../syntax/rival.rkt\")\n\n(provide batch-prepare-points\n         sample-points)\n\n;; Part 1: use FPBench's condition->range-table to create initial hyperrects\n\n(define (precondition->hyperrects pre vars var-reprs)\n  (define range-table (condition->range-table pre))\n  (apply cartesian-product\n         (for/list ([var-name (in-vector vars)]\n                    [var-repr (in-vector var-reprs)])\n           (map (lambda (interval) (fpbench-ival->ival var-repr interval))\n                (range-table-ref range-table var-name)))))\n\n(define (fpbench-ival->ival repr fpbench-interval)\n  (match-define (interval lo hi lo? hi?) fpbench-interval)\n  (match (representation-type repr)\n    ['real (ival (bfstep (bf lo) (if lo? 0 1)) (bfstep (bf hi) (if hi? 0 -1)))]\n    ['bool (ival #f #t)]))\n\n(module+ test\n  (require rackunit)\n  (require \"../syntax/platform.rkt\"\n           \"../syntax/load-platform.rkt\")\n  (activate-platform! (*platform-name*))\n  (define binary64 (get-representation 'binary64))\n  (define pre '(and (and (<= 0 a) (<= a 1)) (and (<= 0 b) (<= b 1))))\n\n  (check-equal? (precondition->hyperrects pre '#(a b) (vector binary64 binary64))\n                (list (list (ival 0.bf 1.bf) (ival 0.bf 1.bf)))))\n\n;; Part 2: using subdivision search to find valid intervals\n\n;; we want a index i such that vector[i] > num and vector[i-1] <= num\n;; assumes vector strictly increasing\n(define (binary-search vector num)\n  (let loop ([left 0]\n             [right (- (vector-length vector) 1)])\n    (cond\n      [(>= left right) (min left (- (vector-length vector) 1))]\n      [else\n       (define mid (arithmetic-shift (+ left right) -1))\n       (define pivot (vector-ref vector mid))\n       (if (<= pivot num)\n           (loop (+ 1 mid) right)\n           (loop left mid))])))\n\n(module+ test\n  (define arr (partial-sums (build-vector 50 (lambda (_) (random-integer 1 100)))))\n  (define max-num (vector-ref arr (- (vector-length arr) 1)))\n  (for ([search-for (in-range max-num)])\n    (define search-result (binary-search arr search-for))\n    (check-true (> (vector-ref arr search-result) search-for))\n    (check-true (or (zero? search-result) (<= (vector-ref arr (- search-result 1)) search-for)))))\n\n(define (make-hyperrect-sampler hyperrects* hints* reprs)\n  (when (null? hyperrects*)\n    (raise-herbie-sampling-error \"No valid values.\" #:url \"faq.html#no-valid-values\"))\n  (define hints (list->vector hints*))\n  (define hyperrects (list->vector hyperrects*))\n  (define lo-ends\n    (for/vector #:length (vector-length hyperrects)\n                ([hyperrect (in-vector hyperrects)])\n      (for/list ([interval (in-list hyperrect)]\n                 [repr (in-vector reprs)])\n        ((representation-repr->ordinal repr) ((representation-bf->repr repr) (ival-lo interval))))))\n  (define hi-ends\n    (for/vector #:length (vector-length hyperrects)\n                ([hyperrect (in-vector hyperrects)])\n      (for/list ([interval (in-list hyperrect)]\n                 [repr (in-vector reprs)])\n        (+ 1\n           ((representation-repr->ordinal repr)\n            ((representation-bf->repr repr) (ival-hi interval)))))))\n  (define weights (partial-sums (vector-map (curryr hyperrect-weight reprs) hyperrects)))\n  (define weight-max (vector-ref weights (- (vector-length weights) 1)))\n\n  ;; returns pt and hint\n  (define num-vars (vector-length reprs))\n  (define (hyperrect-sampler)\n    (define idx (binary-search weights (random-natural weight-max)))\n    (values (for/vector #:length num-vars\n                        ([lo (in-list (vector-ref lo-ends idx))]\n                         [hi (in-list (vector-ref hi-ends idx))]\n                         [repr (in-vector reprs)])\n              ((representation-ordinal->repr repr) (random-integer lo hi)))\n            (vector-ref hints idx)))\n  hyperrect-sampler)\n\n(define (make-sampler compiler)\n  (match-define (real-compiler pre vars var-reprs _ reprs _ _ _ _) compiler)\n  (cond\n    [(and (flag-set? 'setup 'search)\n          (not (vector-empty? var-reprs))\n          (for/and ([repr (in-vector (vector-append var-reprs reprs))])\n            (equal? (representation-type repr) 'real)))\n     (timeline-push! 'method \"search\")\n     (define hyperrects-analysis (precondition->hyperrects pre vars var-reprs))\n     ; hints-hyperrects is a (listof '(hint hyperrect))\n     (match-define (list hyperrects hints sampling-table)\n       (find-intervals compiler hyperrects-analysis #:fuel (*max-find-range-depth*)))\n     (values (make-hyperrect-sampler hyperrects hints var-reprs) sampling-table)]\n    [else\n     (timeline-push! 'method \"random\")\n     ; sampler return false hint since rival-analyze has not been called in random method\n     (values (λ () (values (vector-map random-generate var-reprs) #f)) (hash 'unknown 1.0))]))\n\n;; Returns an evaluator for a list of expressions.\n;; Part 3: compute exact values using Rival's algorithm\n\n(define (batch-prepare-points compiler sampler)\n  ;; If we're using the bf fallback, start at the max precision\n  (define outcomes (make-hash))\n  (define vars (real-compiler-vars compiler))\n  (define var-reprs (real-compiler-var-reprs compiler))\n  (define reprs (real-compiler-reprs compiler))\n  (define assemble-point (real-compiler-assemble-point compiler))\n  (define assemble-output (real-compiler-assemble-output compiler))\n  (define exact-count (length (assemble-output (make-list (vector-length reprs) #f))))\n\n  (real-compiler-clear! compiler) ; Clear profiling vector\n  (define-values (points exactss)\n    (let loop ([sampled 0]\n               [skipped 0]\n               [points '()]\n               [exactss (make-list exact-count '())])\n      (define-values (pt hint) (sampler))\n      (define-values (status exs) (real-apply compiler pt hint))\n      (case status\n        [(exit)\n         (warn 'ground-truth\n               \"could not determine a ground truth\"\n               #:url \"faq.html#ground-truth\"\n               #:extra (vector->list (vector-map (curry format \"~a = ~a\") vars pt)))]\n        [(valid)\n         (for ([ex (in-list exs)]\n               [repr (in-vector reprs)])\n           ; The `bool` representation does not produce bigfloats\n           (define maybe-bf ((representation-repr->bf repr) ex))\n           (when (and (bigfloat? maybe-bf) (bfinfinite? maybe-bf))\n             (set! status 'infinite)))])\n\n      (hash-update! outcomes status add1 0)\n\n      (define is-bad?\n        (for/or ([input (in-vector pt)]\n                 [repr (in-vector var-reprs)])\n          ((representation-special-value? repr) input)))\n\n      (cond\n        [(and (list? exs) (not is-bad?))\n         (define assembled-exs (assemble-output exs))\n         (define assembled-pt (assemble-point pt))\n         (define next-exactss (map cons assembled-exs exactss))\n         (if (>= (+ 1 sampled) (*num-points*))\n             (values (cons assembled-pt points) next-exactss)\n             (loop (+ 1 sampled) 0 (cons assembled-pt points) next-exactss))]\n        [else\n         (when (>= skipped (*max-skipped-points*))\n           (raise-herbie-sampling-error \"Cannot sample enough valid points.\"\n                                        #:url \"faq.html#sample-valid-points\"))\n         (loop sampled (+ 1 skipped) points exactss)])))\n  (values (cons points exactss) outcomes))\n\n(define (combine-tables t1 t2)\n  (define t2-total (apply + (hash-values t2)))\n  (define t1-base (+ (hash-ref t1 'unknown 0) (hash-ref t1 'valid 0)))\n  (for/fold ([t1 (hash-remove (hash-remove t1 'unknown) 'valid)]) ([(k v) (in-hash t2)])\n    (hash-set t1 k (+ (hash-ref t1 k 0) (* (/ v t2-total) t1-base)))))\n\n(define (sample-points pre batch brfs ctxs)\n  (timeline-event! 'analyze)\n  (define compiler (make-real-compiler batch brfs ctxs #:pre pre))\n  (define-values (sampler table) (make-sampler compiler))\n  (timeline-event! 'sample)\n  (define-values (results table2) (batch-prepare-points compiler sampler))\n  (define total (apply + (hash-values table2)))\n  (when (> (hash-ref table2 'infinite 0.0) (* 0.2 total))\n    (warn 'inf-points\n          #:url \"faq.html#inf-points\"\n          \"~a% of points produce a very large (infinite) output. You may want to add a precondition.\"\n          (~r (/ (- total (hash-ref table2 'infinite)) total 0.01) #:precision '(= 1))))\n  (timeline-push! 'bogosity (combine-tables table table2))\n  results)\n"
  },
  {
    "path": "src/core/searchreals.rkt",
    "content": "#lang racket\n\n(require math/bigfloat)\n\n(require \"../utils/errors.rkt\"\n         \"../syntax/float.rkt\"\n         \"../utils/pretty-print.rkt\"\n         \"../utils/timeline.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/rival.rkt\")\n\n(provide find-intervals\n         hyperrect-weight)\n\n(struct search-space (true false other true-hints other-hints))\n\n(define (make-search-space . ranges)\n  (search-space '() '() ranges '() (make-list (length ranges) #f)))\n\n(define (total-weight reprs)\n  (expt 2 (apply + (vector->list (vector-map representation-total-bits reprs)))))\n\n(define (hyperrect-weight hyperrect reprs)\n  (apply *\n         (for/list ([interval (in-list hyperrect)]\n                    [repr (in-vector reprs)])\n           (define ->ordinal\n             (compose (representation-repr->ordinal repr) (representation-bf->repr repr)))\n           (+ 1 (- (->ordinal (ival-hi interval)) (->ordinal (ival-lo interval)))))))\n\n(define (search-step compiler space split-var)\n  (define vars (real-compiler-vars compiler))\n  (define reprs (real-compiler-var-reprs compiler))\n  (match-define (search-space true false other true-hints other-hints) space)\n  (define-values (true* false* other* true-hints* other-hints*)\n    (for/fold ([true* true]\n               [false* false]\n               [other* '()]\n               [true-hints* true-hints]\n               [other-hints* '()])\n              ([rect (in-list other)]\n               [hint (in-list other-hints)])\n      (match-define (list err-ival hint* converged?)\n        (real-compiler-analyze compiler (list->vector rect) hint))\n      (define err (ival-lo err-ival))\n      (define err? (ival-hi err-ival))\n      (when (eq? err 'unsamplable)\n        (warn 'ground-truth\n              #:url \"faq.html#ground-truth\"\n              \"could not determine a ground truth\"\n              #:extra (for/list ([var (in-vector vars)]\n                                 [repr (in-vector reprs)]\n                                 [iv rect])\n                        (define val\n                          (value->string ((representation-bf->repr repr)\n                                          (bigfloat-pick-point (ival-lo iv) (ival-hi iv)))\n                                         repr))\n                        (format \"~a = ~a\" var val))))\n      (cond\n        [err (values true* (cons rect false*) other* true-hints* other-hints*)]\n        [(and (not err?) converged?)\n         (values (cons rect true*) false* other* (cons hint* true-hints*) other-hints*)]\n        [else\n         (define range (list-ref rect split-var))\n         (define repr (vector-ref reprs split-var))\n         (match (two-midpoints repr (ival-lo range) (ival-hi range))\n           [(cons midleft midright)\n            (define rect-lo (list-set rect split-var (ival (ival-lo range) midleft)))\n            (define rect-hi (list-set rect split-var (ival midright (ival-hi range))))\n            (values true*\n                    false*\n                    (list* rect-lo rect-hi other*)\n                    true-hints*\n                    (list* hint* hint* other-hints*))]\n           [#f (values true* false* (cons rect other*) true-hints* (cons hint* other-hints*))])])))\n  (search-space true* false* other* true-hints* other-hints*))\n\n(define (make-sampling-table reprs true false other)\n  (define denom (total-weight reprs))\n  (define true-weight (apply + (map (curryr hyperrect-weight reprs) true)))\n  (define false-weight (apply + (map (curryr hyperrect-weight reprs) false)))\n  (define other-weight (apply + (map (curryr hyperrect-weight reprs) other)))\n  (define out (make-hash))\n  (hash-set! out 'valid (exact->inexact (/ true-weight denom)))\n  (hash-set! out 'unknown (exact->inexact (/ other-weight denom)))\n  (hash-set! out 'invalid (exact->inexact (/ false-weight denom)))\n  (define total (apply + (hash-values out)))\n  (hash-update! out 'precondition (curry + (- 1 total)) 0)\n  (make-immutable-hash (hash->list out)))\n\n(define (find-intervals compiler rects #:fuel [depth 128])\n  (define var-reprs (real-compiler-var-reprs compiler))\n  (let loop ([space (apply make-search-space rects)]\n             [n 0])\n    (match-define (search-space true false other true-hints other-hints) space)\n    (timeline-push! 'sampling n (make-sampling-table var-reprs true false other))\n\n    (define n* (remainder n (vector-length var-reprs)))\n    (if (or (>= n depth) (empty? (search-space-other space)) (>= (length other) (expt 2 depth)))\n        (list (append (search-space-true space) (search-space-other space))\n              (append (search-space-true-hints space) (search-space-other-hints space))\n              (make-sampling-table var-reprs true false other))\n        (loop (search-step compiler space n*) (+ n 1)))))\n"
  },
  {
    "path": "src/core/taylor.rkt",
    "content": "#lang racket\n\n(require math/number-theory)\n(require \"../utils/common.rkt\"\n         \"../utils/dvector.rkt\"\n         \"../syntax/syntax.rkt\"\n         \"../syntax/batch.rkt\"\n         \"programs.rkt\")\n\n(provide approximate\n         taylor-coefficients\n         reduce\n         add)\n\n(define reduce (make-parameter #f))\n(define add (make-parameter #f))\n\n(define (reducer x)\n  ((reduce) x))\n\n(define (adder x)\n  ((add) x))\n\n(define (taylor-coefficients batch brfs vars transforms-to-try)\n  (define expander (expand-taylor! batch))\n  (for*/list ([var (in-list vars)]\n              #:do [(define taylorer (taylor var batch))]\n              [transform-type transforms-to-try])\n    (match-define (list name f finv) transform-type)\n    (define replacer (batch-replace-expression! batch var (f var)))\n    (for/list ([brf (in-list brfs)])\n      (taylorer (expander (reducer (replacer brf)))))))\n\n(define (approximate taylor-approxs\n                     batch\n                     var\n                     #:transform [tform (cons identity identity)]\n                     #:iters [iters 5])\n  (define replacer (batch-replace-expression! batch var ((cdr tform) var)))\n  (for/list ([ta taylor-approxs])\n    (define offset (series-offset ta))\n    (define i 0)\n    (define terms '())\n\n    (define (next [iter 0])\n      (define coeff (reducer (replacer (series-ref ta i))))\n      (set! i (+ i 1))\n      (match (deref coeff)\n        [0\n         (if (< iter iters)\n             (next (+ iter 1))\n             (reducer (make-horner ((cdr tform) var) (reverse terms))))]\n        [_\n         (set! terms (cons (cons coeff (- i offset 1)) terms))\n         (reducer (make-horner ((cdr tform) var) (reverse terms)))]))\n    next))\n\n;; Our Taylor expander prefers sin, cos, exp, log, neg over trig, htrig, pow, and subtraction\n(define (expand-taylor! input-batch)\n  (define (f node)\n    (match node\n      [(list '- ref1 ref2) `(+ ,ref1 (neg ,ref2))]\n      [(list 'pow base (app deref 1/2)) `(sqrt ,base)]\n      [(list 'pow base (app deref 1/3)) `(cbrt ,base)]\n      [(list 'pow base (app deref 2/3)) `(cbrt (* ,base ,base))]\n      [(list 'pow base power)\n       #:when (exact-integer? (deref power))\n       `(pow ,base ,power)]\n      [(list 'pow base power) `(exp (* ,power (log ,base)))]\n      [(list 'tan arg) `(/ (sin ,arg) (cos ,arg))]\n      [(list 'cosh arg) `(* 1/2 (+ (exp ,arg) (/ 1 (exp ,arg))))]\n      [(list 'sinh arg) `(* 1/2 (+ (exp ,arg) (/ -1 (exp ,arg))))]\n      [(list 'tanh arg) `(/ (+ (exp ,arg) (neg (/ 1 (exp ,arg)))) (+ (exp ,arg) (/ 1 (exp ,arg))))]\n      [(list 'asinh arg) `(log (+ ,arg (sqrt (+ (* ,arg ,arg) 1))))]\n      [(list 'acosh arg) `(log (+ ,arg (sqrt (+ (* ,arg ,arg) -1))))]\n      [(list 'atanh arg) `(* 1/2 (log (/ (+ 1 ,arg) (+ 1 (neg ,arg)))))]\n      [_ node]))\n  (batch-recurse\n   input-batch\n   (λ (brf recurse)\n     (define node (deref brf))\n     (define node* (f node))\n     (let loop ([node* node*])\n       (match node*\n         [(? batchref? brf) (recurse brf)]\n         [_ (batch-push! input-batch (expr-recurse node* (compose batchref-idx loop)))])))))\n\n; Tests for expand-taylor\n(module+ test\n  (require rackunit)\n\n  (define (test-expand-taylor expr)\n    (define-values (batch brfs) (progs->batch (list expr)))\n    (define brf* ((expand-taylor! batch) (car brfs)))\n    ((batch-exprs batch) brf*))\n\n  (check-equal? '(* 1/2 (log (/ (+ 1 x) (+ 1 (neg x))))) (test-expand-taylor '(atanh x)))\n  (check-equal? '(log (+ x (sqrt (+ (* x x) -1)))) (test-expand-taylor '(acosh x)))\n  (check-equal? '(log (+ x (sqrt (+ (* x x) 1)))) (test-expand-taylor '(asinh x)))\n  (check-equal? '(/ (+ (exp x) (neg (/ 1 (exp x)))) (+ (exp x) (/ 1 (exp x))))\n                (test-expand-taylor '(tanh x)))\n  (check-equal? '(* 1/2 (+ (exp x) (/ -1 (exp x)))) (test-expand-taylor '(sinh x)))\n  (check-equal? '(+ 1 (neg (+ 2 (neg 3)))) (test-expand-taylor '(- 1 (- 2 3))))\n  (check-equal? '(* 1/2 (+ (exp x) (/ 1 (exp x)))) (test-expand-taylor '(cosh x)))\n  (check-equal? '(/ (sin x) (cos x)) (test-expand-taylor '(tan x)))\n  (check-equal? '(+ 1 (neg (* 1/2 (+ (exp (/ (sin 3) (cos 3))) (/ 1 (exp (/ (sin 3) (cos 3))))))))\n                (test-expand-taylor '(- 1 (cosh (tan 3)))))\n  (check-equal? '(exp (* a (log x))) (test-expand-taylor '(pow x a)))\n  (check-equal? '(+ x (sin a)) (test-expand-taylor '(+ x (sin a))))\n  (check-equal? '(cbrt x) (test-expand-taylor '(pow x 1/3)))\n  (check-equal? '(cbrt (* x x)) (test-expand-taylor '(pow x 2/3)))\n  (check-equal? '(+ 100 (cbrt x)) (test-expand-taylor '(+ 100 (pow x 1/3))))\n  (check-equal? `(+ 100 (cbrt (* x y))) (test-expand-taylor `(+ 100 (pow (* x y) 1/3))))\n  (check-equal? `(+ y (cbrt x)) (test-expand-taylor `(+ y (pow x 1/3))))\n  (check-equal? `(+ (cbrt x) y) (test-expand-taylor `(+ (pow x 1/3) y))))\n\n(define (make-horner var terms [start 0])\n  (match terms\n    ['() (adder 0)]\n    [(list (cons c n)) (adder `(* ,c ,(make-monomial var (- n start))))]\n    [(list (cons c n) rest ...)\n     (adder `(* ,(make-monomial var (- n start)) (+ ,c ,(make-horner var rest n))))]))\n\n(define (make-sum terms)\n  (match terms\n    ['() 0]\n    [`(,x) x]\n    [`(,x ,xs ...) `(+ ,x ,(make-sum xs))]))\n\n(define (make-monomial var power)\n  (cond\n    [(equal? power 0) 1]\n    [(equal? power 1) var]\n    [(equal? power -1) `(/ 1 ,var)]\n    [(positive? power) `(pow ,var ,power)]\n    [(negative? power) `(pow ,var ,power)]))\n\n(define/reset n-sum-to-cache (make-hash))\n\n(define/reset log-cache (make-hash '((1 . ((1 -1 1))))))\n\n(define (n-sum-to n k)\n  (hash-ref! (n-sum-to-cache)\n             (cons n k)\n             (λ ()\n               (cond\n                 [(= k 0) (list (make-list n 0))]\n                 [(= n 1) (list (list k))]\n                 [(= n 0) '()]\n                 [else\n                  (for*/list ([i (in-range 0 (+ k 1))]\n                              [v (in-list (map (curry cons i) (n-sum-to (- n 1) (- k i))))])\n                    v)]))))\n\n(define (taylor var expr-batch)\n  \"Return a pair (e, n), such that expr ~= e var^n\"\n  (batch-recurse\n   expr-batch\n   (lambda (brf recurse)\n     (define node (deref brf))\n     (match node\n       [(? (curry equal? var)) (taylor-exact (adder 0) (adder 1))]\n       [(? number?) (taylor-exact brf)]\n       [(? symbol?) (taylor-exact brf)]\n       [`(,const) (taylor-exact brf)]\n       [`(+ ,arg1 ,arg2) (taylor-add (recurse arg1) (recurse arg2))]\n       [`(neg ,arg) (taylor-negate (recurse arg))]\n       [`(* ,left ,right) (taylor-mult (recurse left) (recurse right))]\n       [`(/ ,num ,den)\n        #:when (equal? (deref num) 1)\n        (taylor-invert (recurse den))]\n       [`(/ ,num ,den) (taylor-quotient (recurse num) (recurse den))]\n       [`(sqrt ,arg) (taylor-sqrt var (recurse arg))]\n       [`(cbrt ,arg) (taylor-cbrt var (recurse arg))]\n       [`(fabs ,arg) (or (taylor-fabs var (recurse arg)) (taylor-exact brf))]\n       [`(exp ,arg)\n        (define arg* (normalize-series (recurse arg)))\n        (if (positive? (series-offset arg*))\n            (taylor-exact brf)\n            (taylor-exp (zero-series arg*)))]\n       [`(sin ,arg)\n        (define arg* (normalize-series (recurse arg)))\n        (cond\n          [(positive? (series-offset arg*)) (taylor-exact brf)]\n          [(= (series-offset arg*) 0)\n           ; Our taylor-sin function assumes that a0 is 0,\n           ; because that way it is especially simple. We correct for this here\n           ; We use the identity sin (x + y) = sin x cos y + cos x sin y\n           (taylor-add (taylor-mult (taylor-exact (adder `(sin ,(series-ref arg* 0))))\n                                    (taylor-cos (zero-series arg*)))\n                       (taylor-mult (taylor-exact (adder `(cos ,(series-ref arg* 0))))\n                                    (taylor-sin (zero-series arg*))))]\n          [else (taylor-sin (zero-series arg*))])]\n       [`(cos ,arg)\n        (define arg* (normalize-series (recurse arg)))\n        (cond\n          [(positive? (series-offset arg*)) (taylor-exact brf)]\n          [(= (series-offset arg*) 0)\n           ; Our taylor-cos function assumes that a0 is 0,\n           ; because that way it is especially simple. We correct for this here\n           ; We use the identity cos (x + y) = cos x cos y - sin x sin y\n           (taylor-add (taylor-mult (taylor-exact (adder `(cos ,(series-ref arg* 0))))\n                                    (taylor-cos (zero-series arg*)))\n                       (taylor-negate (taylor-mult (taylor-exact (adder `(sin ,(series-ref arg* 0))))\n                                                   (taylor-sin (zero-series arg*)))))]\n          [else (taylor-cos (zero-series arg*))])]\n       [`(log ,arg) (taylor-log var (recurse arg))]\n       [`(pow ,base ,power)\n        #:when (exact-integer? (deref power))\n        (taylor-pow (normalize-series (recurse base)) (deref power))]\n       [_ (taylor-exact brf)]))))\n\n; A taylor series is represented by a struct containing a coefficient builder,\n; a cache of computed coefficients, and an integer offset to the exponent\n\n; (define term? series?)\n\n(struct series (offset f cache) #:transparent)\n\n(define (taylor-exact . terms)\n  ;(->* () #:rest (listof batchref?) term?)\n  (define items (list->vector (map reducer terms)))\n  (define len (vector-length items))\n  (make-series 0\n               (λ (f n)\n                 (if (< n len)\n                     (deref (vector-ref items n))\n                     0))))\n\n(define (first-nonzero-exp f)\n  ;(-> (-> number? batchref?) number?)\n  \"Returns n, where (series n) != 0, but (series n) = 0 for all smaller n\"\n  (let loop ([n 0])\n    (if (and (equal? (deref (f n)) 0) (< n 20))\n        (loop (+ n 1))\n        n)))\n\n(define (make-series offset builder)\n  (series offset builder (make-dvector 10)))\n\n(define (series-ref s n)\n  (define cache (series-cache s))\n  (define builder (series-f s))\n  (define (fetch i)\n    (dvector-ref cache i))\n  (when (>= n (dvector-length cache))\n    (for ([i (in-range (dvector-length cache) (add1 n))])\n      (define value (reducer (adder (builder fetch i))))\n      (dvector-set! cache i value)))\n  (dvector-ref cache n))\n\n(define ((series-function s) n)\n  (series-ref s n))\n\n(define (taylor-add left right)\n  ;(-> term? term? term?)\n  (define left-offset (series-offset left))\n  (define right-offset (series-offset right))\n  (define target-offset (max left-offset right-offset))\n  (define (align offset series)\n    (define shift (- offset target-offset))\n    (cond\n      [(zero? shift) (series-function series)]\n      [else\n       (λ (n)\n         (if (negative? (+ n shift))\n             (adder 0)\n             (series-ref series (+ n shift))))]))\n  (define left* (align left-offset left))\n  (define right* (align right-offset right))\n  (make-series target-offset (λ (f n) (make-sum (list (left* n) (right* n))))))\n\n(define (taylor-negate term)\n  ;(-> term? term?)\n  (make-series (series-offset term) (λ (f n) (list 'neg (series-ref term n)))))\n\n(define (taylor-mult left right)\n  ;(-> term? term? term?)\n  (make-series (+ (series-offset left) (series-offset right))\n               (λ (f n)\n                 (make-sum (for/list ([i (in-range (+ n 1))]\n                                      #:unless (or (equal? (deref (series-ref left i)) 0)\n                                                   (equal? (deref (series-ref right (- n i))) 0)))\n                             (list '* (series-ref left i) (series-ref right (- n i))))))))\n\n(define (normalize-series s)\n  ;(-> term? term?)\n  \"Fixes up the series to have a non-zero zeroth term,\n   allowing a possibly negative offset\"\n  (define offset (series-offset s))\n  (define coeffs (series-function s))\n  (define slack (first-nonzero-exp coeffs))\n  (if (zero? slack)\n      s\n      (make-series (- offset slack) (λ (f n) (deref (series-ref s (+ n slack)))))))\n\n(define ((zero-series s) n)\n  ;(-> series? (-> number? batchref?))\n  (if (< n (- (series-offset s)))\n      (adder 0)\n      (series-ref s (+ n (series-offset s)))))\n\n(define (taylor-invert term)\n  ;(-> term? term?)\n  \"This gets tricky, because the function might have a pole at 0.\n   This happens if the inverted series doesn't have a constant term,\n   so we extract that case out.\"\n  (define normalized (normalize-series term))\n  (define offset (series-offset normalized))\n  (define b (series-function normalized))\n  (make-series (- offset)\n               (λ (f n)\n                 (if (zero? n)\n                     `(/ 1 ,(b 0))\n                     `(neg (+ ,@(for/list ([i (in-range n)])\n                                  `(* ,(f i) (/ ,(b (- n i)) ,(b 0))))))))))\n\n(define (taylor-quotient num denom)\n  ;(-> term? term? term?)\n  \"This gets tricky, because the function might have a pole at 0.\n   This happens if the inverted series doesn't have a constant term,\n   so we extract that case out.\"\n  (define normalized-num (normalize-series num))\n  (define normalized-denom (normalize-series denom))\n  (define noff (series-offset normalized-num))\n  (define doff (series-offset normalized-denom))\n  (define a (series-function normalized-num))\n  (define b (series-function normalized-denom))\n  (make-series (- noff doff)\n               (λ (f n)\n                 (if (zero? n)\n                     `(/ ,(a 0) ,(b 0))\n                     `(- (/ ,(a n) ,(b 0))\n                         (+ ,@(for/list ([i (in-range n)])\n                                `(* ,(f i) (/ ,(b (- n i)) ,(b 0))))))))))\n\n(define (modulo-series var n series)\n  ;(-> symbol? number? term? term?)\n  (define normalized (normalize-series series))\n  (define offset (series-offset normalized))\n  (define coeffs (series-function normalized))\n  (define offset* (+ offset (modulo (- offset) n)))\n  (cond\n    [(= offset offset*) normalized]\n    [else\n     (define cache (make-dvector 2)) ;; never called more than twice\n     (define (coeffs* i)\n       (unless (and (> (dvector-capacity cache) i) (dvector-ref cache i))\n         (define res\n           (match i\n             [0\n              (adder (make-sum (for/list ([j (in-range (modulo offset n))])\n                                 `(* ,(coeffs j) (pow ,var ,(+ j (modulo (- offset) n)))))))]\n             [_\n              #:when (< i n)\n              (adder 0)]\n             [_ (coeffs (+ (- i n) (modulo offset n)))]))\n         (dvector-set! cache i res))\n       (dvector-ref cache i))\n     (make-series offset* (λ (f i) (deref (coeffs* i))))]))\n\n(define (taylor-sqrt var num)\n  ;(-> symbol? term? term?)\n  (define normalized (modulo-series var 2 num))\n  (define offset* (series-offset normalized))\n  (define coeffs* (series-function normalized))\n  (make-series (/ offset* 2)\n               (λ (f n)\n                 (cond\n                   [(zero? n) `(sqrt ,(coeffs* 0))]\n                   [(= n 1) `(/ ,(coeffs* 1) (* 2 (sqrt ,(coeffs* 0))))]\n                   [(even? n)\n                    `(/ (- ,(coeffs* n)\n                           (pow ,(f (/ n 2)) 2)\n                           (+ ,@(for/list ([k (in-naturals 1)]\n                                           #:break (>= k (- n k)))\n                                  `(* 2 (* ,(f k) ,(f (- n k)))))))\n                        (* 2 ,(f 0)))]\n                   [(odd? n)\n                    `(/ (- ,(coeffs* n)\n                           (+ ,@(for/list ([k (in-naturals 1)]\n                                           #:break (>= k (- n k)))\n                                  `(* 2 (* ,(f k) ,(f (- n k)))))))\n                        (* 2 ,(f 0)))]))))\n\n(define (taylor-cbrt var num)\n  ;(-> symbol? term? term?)\n  (define normalized (modulo-series var 3 num))\n  (define offset* (series-offset normalized))\n  (define coeffs* (series-function normalized))\n  (make-series (/ offset* 3)\n               (λ (f n)\n                 (cond\n                   [(zero? n) `(cbrt ,(coeffs* 0))]\n                   [(= n 1) `(/ ,(coeffs* 1) (* 3 (cbrt (* ,(f 0) ,(f 0)))))]\n                   [else\n                    `(/ (- ,(coeffs* n)\n                           ,@(for*/list ([terms (in-list (n-sum-to 3 n))]\n                                         #:unless (set-member? terms n))\n                               (match-define (list a b c) terms)\n                               `(* ,(f a) ,(f b) ,(f c))))\n                        (* 3 ,(f 0) ,(f 0)))]))))\n\n(define (taylor-fabs var term)\n  (define normalized (normalize-series term))\n  (define offset (series-offset normalized))\n  (define a0 (deref (series-ref normalized 0)))\n  (cond\n    [(or (not (number? a0)) (zero? a0)) #f]\n    [(and (even? offset) (negative? a0)) (taylor-negate normalized)]\n    [(and (even? offset) (positive? a0)) normalized]\n    [(odd? offset)\n     (define scale-factor (adder `(* (fabs ,var) ,(if (negative? a0) -1 1))))\n     (define new-offset (add1 offset))\n     (make-series new-offset\n                  (λ (f n)\n                    (if (zero? n)\n                        scale-factor\n                        (series-ref normalized (+ n (- new-offset offset))))))]\n    [else #f]))\n\n(define (taylor-pow coeffs n)\n  ;(-> term? number? term?)\n  (match n ;; Russian peasant multiplication\n    [(? negative?) (taylor-pow (taylor-invert coeffs) (- n))]\n    [0 (taylor-exact (adder 1))]\n    [1 coeffs]\n    [(? even?)\n     (define half (taylor-pow coeffs (/ n 2)))\n     (taylor-mult half half)]\n    [(? odd?)\n     (define half (taylor-pow coeffs (/ (- n 1) 2)))\n     (taylor-mult coeffs (taylor-mult half half))]))\n\n(define (all-partitions n options)\n  (match options\n    ['()\n     (if (= n 0)\n         '(())\n         '())]\n    [(cons k options*)\n     (reap [sow]\n           (for* ([i (in-range (/ (+ n 1) k))])\n             (define head (cons i k))\n             (if (= i 0)\n                 (map sow (all-partitions n options*))\n                 (for ([pt (all-partitions (- n (* k i)) options*)])\n                   (sow (cons head pt))))))]))\n\n(define (taylor-exp coeffs)\n  ;(-> (-> number? batchref?) term?)\n  (make-series 0\n               (λ (f n)\n                 (cond\n                   [(zero? n) `(exp ,(coeffs 0))]\n                   [else\n                    (define coeffs* (list->vector (map coeffs (range 1 (+ n 1)))))\n                    (define nums\n                      (for/list ([i (in-range 1 (+ n 1))]\n                                 [coeff (in-vector coeffs*)]\n                                 #:unless (equal? (deref coeff) 0))\n                        i))\n                    `(* (exp ,(coeffs 0))\n                        (+ ,@(for/list ([p (in-list (all-partitions n (sort nums >)))])\n                               `(* ,@(for/list ([(count num) (in-dict p)])\n                                       `(/ (pow ,(vector-ref coeffs* (- num 1)) ,count)\n                                           ,(factorial count)))))))]))))\n\n(define (taylor-sin coeffs)\n  ;(-> (-> number? batchref?) term?)\n  (make-series 0\n               (λ (f n)\n                 (cond\n                   [(zero? n) 0]\n                   [else\n                    (define coeffs* (list->vector (map coeffs (range 1 (+ n 1)))))\n                    (define nums\n                      (for/list ([i (in-range 1 (+ n 1))]\n                                 [coeff (in-vector coeffs*)]\n                                 #:unless (equal? (deref coeff) 0))\n                        i))\n                    `(+ ,@(for/list ([p (in-list (all-partitions n (sort nums >)))])\n                            (if (= (modulo (apply + (map car p)) 2) 1)\n                                `(* ,(if (= (modulo (apply + (map car p)) 4) 1) 1 -1)\n                                    ,@(for/list ([(count num) (in-dict p)])\n                                        `(/ (pow ,(vector-ref coeffs* (- num 1)) ,count)\n                                            ,(factorial count))))\n                                0)))]))))\n\n(define (taylor-cos coeffs)\n  ;(-> (-> number? batchref?) term?)\n  (make-series 0\n               (λ (f n)\n                 (cond\n                   [(zero? n) 1]\n                   [else\n                    (define coeffs* (list->vector (map coeffs (range 1 (+ n 1)))))\n                    (define nums\n                      (for/list ([i (in-range 1 (+ n 1))]\n                                 [coeff (in-vector coeffs*)]\n                                 #:unless (equal? (deref coeff) 0))\n                        i))\n                    `(+ ,@(for/list ([p (in-list (all-partitions n (sort nums >)))])\n                            (if (= (modulo (apply + (map car p)) 2) 0)\n                                `(* ,(if (= (modulo (apply + (map car p)) 4) 0) 1 -1)\n                                    ,@(for/list ([(count num) (in-dict p)])\n                                        `(/ (pow ,(vector-ref coeffs* (- num 1)) ,count)\n                                            ,(factorial count))))\n                                0)))]))))\n\n;; This is a hyper-specialized symbolic differentiator for log(f(x))\n\n(define (list-setinc l i)\n  (let loop ([i i]\n             [l l]\n             [rest '()])\n    (if (= i 0)\n        (if (null? (cdr l))\n            (append (reverse rest) (list (- (car l) 1) 1))\n            (append (reverse rest) (list* (- (car l) 1) (+ (cadr l) 1) (cddr l))))\n        (loop (- i 1) (cdr l) (cons (car l) rest)))))\n\n(define (loggenerate table)\n  (apply append\n         (for/list ([term table])\n           (match-define `(,coeff ,ps ...) term)\n           (filter identity\n                   (for/list ([i (in-naturals)]\n                              [p ps])\n                     (if (zero? p)\n                         #f\n                         `(,(* coeff p) ,@(list-setinc ps i))))))))\n\n(define (lognormalize table)\n  (filter (λ (entry) (not (= (car entry) 0)))\n          (for/list ([entry (group-by cdr table)])\n            (cons (apply + (map car entry)) (cdar entry)))))\n\n(define (logstep table)\n  (lognormalize (loggenerate table)))\n\n(define (logcompute i)\n  (hash-ref! (log-cache) i (λ () (logstep (logcompute (- i 1))))))\n\n(define (taylor-log var arg)\n  ;(-> symbol? term? term?)\n  (define normalized (normalize-series arg))\n  (define shift (series-offset normalized))\n  (define coeffs (series-function normalized))\n  (define negate? (and (number? (deref (coeffs 0))) (not (positive? (deref (coeffs 0))))))\n  (define (maybe-negate x)\n    (if negate?\n        `(neg ,x)\n        x))\n\n  (define base\n    (make-series 0\n                 (λ (f n)\n                   (cond\n                     [(zero? n) `(log ,(maybe-negate (coeffs 0)))]\n                     [else\n                      (define tmpl (logcompute n))\n                      (define coeffs* (list->vector (map coeffs (range 1 (add1 n)))))\n                      (define relevant-terms\n                        (for/list ([term (in-list tmpl)]\n                                   #:do [(match-define `(,coeff ,k ,ps ...) term)]\n                                   #:unless (for/or ([i (in-naturals 1)]\n                                                     [p (in-list ps)]\n                                                     #:when (not (= p 0)))\n                                              (equal? (deref (vector-ref coeffs* (sub1 i))) 0)))\n                          `(* ,coeff\n                              (/ (* ,@(for/list ([i (in-naturals 1)]\n                                                 [p (in-list ps)])\n                                        (if (= p 0)\n                                            1\n                                            `(pow (* ,(factorial i) ,(vector-ref coeffs* (sub1 i)))\n                                                  ,p))))\n                                 (exp (* ,(- k) ,(f 0)))))))\n                      `(/ ,(make-sum relevant-terms) ,(factorial n))]))))\n\n  (if (zero? shift)\n      base\n      (taylor-add base\n                  (make-series 0\n                               (λ (f n)\n                                 (if (zero? n)\n                                     `(* (neg ,shift) (log ,(maybe-negate var)))\n                                     0))))))\n\n(module+ test\n  (require rackunit)\n  (define-values (batch brfs) (progs->batch (list '(pow x 1.0))))\n  (parameterize ([reduce (batch-reduce batch)]\n                 [add (λ (x) (batch-add! batch x))])\n    (define brfs* (map (expand-taylor! batch) brfs))\n    (define brf (car brfs*))\n    (check-pred exact-integer? (series-offset ((taylor 'x batch) brf)))))\n\n(module+ test\n  (require \"batch-reduce.rkt\")\n  (define (coeffs expr #:n [n 7])\n    (define-values (batch brfs) (progs->batch (list expr)))\n    (parameterize ([reduce (batch-reduce batch)]\n                   [add (λ (x) (batch-add! batch x))])\n      (define brfs* (map (expand-taylor! batch) brfs))\n      (define brf (car brfs*))\n      (define fn (zero-series ((taylor 'x batch) brf)))\n      (map (batch-exprs batch) (build-list n fn))))\n  (check-equal? (coeffs '(sin x)) '(0 1 0 -1/6 0 1/120 0))\n  (check-equal? (coeffs '(sqrt (+ 1 x))) '(1 1/2 -1/8 1/16 -5/128 7/256 -21/1024))\n  (check-equal? (coeffs '(cbrt (+ 1 x))) '(1 1/3 -1/9 5/81 -10/243 22/729 -154/6561))\n  (check-equal? (coeffs '(sqrt x)) '((sqrt x) 0 0 0 0 0 0))\n  (check-equal? (coeffs '(cbrt x)) '((cbrt x) 0 0 0 0 0 0))\n  (check-equal? (coeffs '(cbrt (* x x))) '((pow x 2/3) 0 0 0 0 0 0))\n  (check-equal? (coeffs '(fabs (+ 2 x))) '(2 1 0 0 0 0 0))\n  (check-equal? (coeffs '(fabs (+ -2 x))) '(2 -1 0 0 0 0 0)))\n"
  },
  {
    "path": "src/core/test-rules.rkt",
    "content": "#lang racket\n\n(require rackunit)\n(require \"../utils/common.rkt\"\n         \"../syntax/float.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/batch.rkt\"\n         \"../syntax/rival.rkt\"\n         \"rules.rkt\"\n         \"programs.rkt\"\n         \"../syntax/platform.rkt\"\n         \"../syntax/load-platform.rkt\"\n         \"sampling.rkt\")\n\n(activate-platform! (*platform-name*))\n\n(define skip-rules '(log-pow))\n\n(define num-test-points (make-parameter 100))\n(define double-repr (get-representation 'binary64))\n\n(define (env->ctx p1 p2)\n  (define vars (set-union (free-variables p1) (free-variables p2)))\n  (context vars double-repr (map (const double-repr) vars)))\n\n(define (drop-sound expr)\n  (match expr\n    [(list op args ... extra)\n     #:when (string-contains? (~a op) \"sound\")\n     (define op* (string->symbol (substring (symbol->string (car expr)) (string-length \"sound-\"))))\n     (cons op* (map drop-sound args))]\n    [(list op args ...) (cons op (map drop-sound args))]\n    [_ expr]))\n\n(define (check-rule test-rule)\n  (match-define (rule name p1 p2 _) test-rule)\n  (define ctx (env->ctx p1 p2))\n  (define ulps (repr-ulps (context-repr ctx)))\n\n  (define-values (batch brfs) (progs->batch (list p1 (drop-sound p2))))\n  (match-define (list pts exs1 exs2)\n    (parameterize ([*num-points* (num-test-points)]\n                   [*max-find-range-depth* 0])\n      (sample-points '(TRUE) batch brfs (list ctx ctx))))\n\n  (for ([pt (in-list pts)]\n        [v1 (in-list exs1)]\n        [v2 (in-list exs2)])\n    (with-check-info* (map make-check-info (context-vars ctx) (vector->list pt))\n                      (λ () (with-check-info (['lhs v1] ['rhs v2]) (check-eq? (ulps v1 v2) 1))))))\n\n(module+ main\n  (num-test-points (* 100 (num-test-points)))\n  (command-line #:args names\n                (for* ([name (in-list names)]\n                       [rule (in-list (*rules*))]\n                       #:when (equal? (~a (rule-name rule)) name))\n                  (eprintf \"Checking ~a...\\n\" name)\n                  (check-rule rule))))\n\n(module+ test\n  (for* ([rule (in-list (*rules*))]\n         #:unless (set-member? skip-rules (rule-name rule)))\n    (test-case (~a (rule-name rule))\n      (check-rule rule))))\n"
  },
  {
    "path": "src/info.rkt",
    "content": "#lang info\n\n(define collection \"herbie\")\n(define version \"2.3\")\n(define license 'MIT)\n\n;; Packaging information\n\n(define pkg-desc \"A tool for automatically improving the accuracy of floating point expressions\")\n\n;; The `herbie` command-line tool\n\n(define racket-launcher-names '(\"herbie\"))\n(define racket-launcher-libraries '(\"main.rkt\"))\n\n;; Dependencies\n\n(define deps\n  '((\"base\" #:version \"8.0\") \"math-lib\"\n                             \"typed-racket-lib\"\n                             \"profile-lib\"\n                             \"cover\"\n                             \"rackunit-lib\"\n                             \"web-server-lib\"\n                             (\"rival3\" #:version \"1.0\")\n                             (\"egg-herbie\" #:version \"2.2\")\n                             (\"rival\" #:version \"2.3\")\n                             (\"fpbench\" #:version \"2.0.3\")\n                             \"fmt\"))\n\n(define build-deps '(\"rackunit-lib\"))\n\n(define test-omit-paths\n  (if (getenv \"PLT_PKG_BUILD_SERVICE\")\n      '(\"syntax/test-rules.rkt\" ; These take too long, package server gives us 60s\n        \"sampling.rkt\") ; These require the benchmarks\n      '()))\n"
  },
  {
    "path": "src/main.rkt",
    "content": "#lang racket\n\n(require racket/lazy-require\n         racket/runtime-path)\n(require \"config.rkt\"\n         \"utils/multi-command-line.rkt\"\n         \"utils/errors.rkt\"\n         \"syntax/load-platform.rkt\")\n\n;; Define the built-in platforms to force bundling them\n(lazy-require [\"api/demo.rkt\" (run-demo)]\n              [\"api/run.rkt\" (make-report rerun-report)]\n              [\"api/shell.rkt\" (run-shell run-improve)])\n\n(define (string->thread-count th)\n  (match th\n    [\"no\" #f]\n    [\"yes\" (max (- (processor-count) 1) 1)]\n    [(app string->number (? positive-integer? x)) x]\n    [_ (raise-herbie-error \"Invalid thread count `~a`\" th #:url \"options.html\")]))\n\n(define (string->flag s)\n  (match (string-split s \":\")\n    [(list (app string->symbol category) (app string->symbol flag))\n     #:when (set-member? (dict-ref all-flags category '()) flag)\n     (list category flag)]\n    [_ (raise-herbie-error \"Invalid flag `~a`\" s #:url \"options.html\")]))\n\n(define (default-flags->table)\n  (list* (format \"~a | ~a | ~a\"\n                 (~a \"category\" #:min-width 10)\n                 (~a \"flag\" #:min-width 20)\n                 (~a \"default?\" #:min-width 10))\n         (~a \"\" #:min-width 44 #:pad-string \"=\")\n         (for*/list ([(category flags) (in-hash all-flags)]\n                     [flag (in-list flags)]\n                     #:unless (flag-deprecated? category flag))\n           (format \"~a | ~a | ~a\"\n                   (~a category #:min-width 10)\n                   (~a flag #:min-width 20)\n                   (if (flag-set? category flag) \"\\u2714\" \"\")))))\n\n(module+ main\n  (define quiet? #f)\n  (define browser? #t)\n  (define demo-output #f)\n  (define demo-log #f)\n  (define demo-prefix \"/\")\n  (define demo? #f)\n  (define demo-port 8000)\n  (define demo-public #f)\n\n  (define threads #f)\n  (set-seed! (random 1 (expt 2 31)))\n\n  (multi-command-line\n   #:program \"herbie\"\n   #:version (format \"Herbie ~a\" *herbie-version*)\n   #:once-each\n   [(\"--timeout\")\n    s\n    (\"Timeout for each test (in seconds).\" (format \"[Default: ~a seconds]\" (/ (*timeout*) 1000)))\n    (*timeout* (* 1000 (string->number s)))]\n   [(\"--seed\")\n    int\n    (\"The random seed to use in point generation.\" \"[Default: random]\")\n    (define given-seed (read (open-input-string int)))\n    (when given-seed\n      (set-seed! given-seed))]\n   [(\"--threads\")\n    num\n    \"How many jobs to run in parallel: Processor count is the default.\"\n    (set! threads (string->thread-count num))]\n   [(\"--platform\")\n    platform\n    (\"The platform to use during improvement\" \"[Default: default]\")\n    (*platform-name* platform)]\n   [(\"--num-iters\")\n    num\n    (\"The number of iterations to use for the main loop. Herbie may find additional improvements\n     with more iterations. Herbie slows down with more iterations.\"\n     (format \"[Default: ~a iterations]\" (*num-iterations*)))\n    (*num-iterations* (string->number num))]\n   [(\"--num-points\")\n    num\n    (\"The number of points to use during sampling. Increasing the number of points may make results\n     more consistent, but may slow down Herbie.\"\n     (format \"[Default: ~a points]\" (*num-points*)))\n    (*num-points* (string->number num))]\n   [(\"--num-enodes\")\n    num\n    (\"The maximum number of enodes to use during egraph-based rewriting. Herbie may find additional\n     improvements with a higher limit, but run time increases exponentially.\"\n     (format \"[Default: ~a enodes]\" (*node-limit*)))\n    (*node-limit* (string->number num))]\n   [(\"--num-analysis\")\n    num\n    (\"The number of input analysis iterations used when searching for valid input points\n     during sampling. May fix \\\"Cannot sample enough valid points\\\" but will slow.\"\n     (format \"[Default: ~a iterations]\" (*max-find-range-depth*)))\n    (*max-find-range-depth* (string->number num))]\n   [(\"--profile\") \"Whether to profile each run (no-op, always on)\" (void)]\n   #:multi [(\"-o\" \"--disable\")\n            flag\n            (\"Disable a search flag (formatted category:name).\"\n             \"See `+o/--enable` for the full list of search flags.\")\n            (apply disable-flag! (string->flag flag))]\n   [(\"+o\" \"--enable\")\n    flag\n    (\"Enable a search flag (formatted category:name).\"\n     (format \"Description of each search flag: https://herbie.uwplse.org/doc/~a/options.html.\"\n             *herbie-version*)\n     (apply string-append\n            \"\\n\" ;; 5 spaces is the padding inserted by `command-line`\n            (map (curry format \"     ~a\\n\") (default-flags->table))))\n    (apply enable-flag! (string->flag flag))]\n   #:subcommands [shell \"Interact with Herbie from the shell\" #:args () (run-shell)]\n   [web\n    \"Interact with Herbie from your browser\"\n    #:once-each\n    [(\"--port\") port \"Port to run the web shell on\" (set! demo-port (string->number port))]\n    [(\"--public\") \"Whether to listen on a public port (instead of localhost)\" (set! demo-public #t)]\n    [(\"--save-session\")\n     dir\n     \"The dir to place a report from submitted expressions\"\n     (set! demo-output dir)]\n    [(\"--log\") file \"The file to write web access log to\" (set! demo-log file)]\n    [(\"--prefix\") prefix \"Prefix for proxying demo\" (set! demo-prefix prefix)]\n    [(\"--demo\") \"Run in Herbie web demo mode. Changes some text\" (set! demo? true)]\n    [(\"--quiet\") \"Print a smaller banner and don't start a browser.\" (set! quiet? true)]\n    [(\"--no-browser\") \"Run the web demo but don't start a browser.\" (set! browser? #f)]\n    #:args ()\n    (run-demo #:quiet quiet?\n              #:threads threads\n              #:browser browser?\n              #:output demo-output\n              #:log demo-log\n              #:prefix demo-prefix\n              #:demo? demo?\n              #:port demo-port\n              #:public? demo-public)]\n   [improve\n    \"Run Herbie on an FPCore file, producing an FPCore file\"\n    #:args (input output)\n    (run-improve input output #:threads threads)]\n   [report\n    \"Run Herbie on an FPCore file, producing an HTML report\"\n    #:args (input output)\n    (make-report (list input) #:dir output #:threads threads)]\n   [reproduce\n    \"Rerun an HTML report\"\n    #:args (input output)\n    (rerun-report input #:dir output #:threads threads)]\n   #:args files\n   (match files\n     ['()\n      (raise-herbie-error \"Please specify a Herbie tool like `racket -l herbie web`\"\n                          #:url \"options.html\")]\n     [(cons tool _)\n      (raise-herbie-error \"Unknown tool `~a`. List available tools with `racket -l herbie -- --help`\"\n                          tool\n                          #:url \"options.html\")])))\n"
  },
  {
    "path": "src/platform.rkt",
    "content": "#lang racket\n\n(require \"syntax/platform-language.rkt\")\n(provide (all-from-out \"syntax/platform-language.rkt\"))\n(module reader syntax/module-reader\n  herbie/syntax/platform-language)\n"
  },
  {
    "path": "src/platforms/c-windows.rkt",
    "content": "#lang s-exp \"../syntax/platform-language.rkt\"\n\n;; C/C++ on Windows platform with a full libm\n\n(require math/flonum)\n\n(define 64bit-move-cost   0.125)\n(define 32bit-move-cost   0.125)\n(define boolean-move-cost 0.100)\n\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BOOLEAN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <bool> #:cost boolean-move-cost)\n\n(define-operations () <bool>\n  [TRUE  #:spec (TRUE)  #:impl (const true)  #:fpcore TRUE  #:cost boolean-move-cost]\n  [FALSE #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost boolean-move-cost])\n\n(define-operations ([x <bool>] [y <bool>]) <bool>\n  [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost boolean-move-cost]\n  [or  #:spec (or x y)  #:impl (lambda v (ormap values v))  #:cost boolean-move-cost])\n\n(define-operation (not [x <bool>]) <bool>\n  #:spec (not x) #:impl not #:cost boolean-move-cost)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <binary32> #:cost 32bit-move-cost)\n\n(define-operation (if.f32 [c <bool>] [t <binary32>] [f <binary32>]) <binary32>\n  #:spec (if c t f) #:impl if-impl\n  #:cost (if-cost boolean-move-cost))\n\n(define-operations ([x <binary32>] [y <binary32>]) <bool>\n  [==.f32 #:spec (== x y) #:impl =          #:cost 32bit-move-cost]\n  [!=.f32 #:spec (!= x y) #:impl (negate =) #:cost 32bit-move-cost]\n  [<.f32  #:spec (< x y)  #:impl <          #:cost 32bit-move-cost]\n  [>.f32  #:spec (> x y)  #:impl >          #:cost 32bit-move-cost]\n  [<=.f32 #:spec (<= x y) #:impl <=         #:cost 32bit-move-cost]\n  [>=.f32 #:spec (>= x y) #:impl >=         #:cost 32bit-move-cost])\n\n(define-operations () <binary32> #:fpcore (! :precision binary32 _)\n  [PI.f32       #:spec (PI)       #:impl (const (flsingle pi))       #:fpcore PI       #:cost 32bit-move-cost]\n  [E.f32        #:spec (E)        #:impl (const (flsingle (exp 1)))  #:fpcore E        #:cost 32bit-move-cost]\n  [INFINITY.f32 #:spec (INFINITY) #:impl (const +inf.0)              #:fpcore INFINITY #:cost 32bit-move-cost]\n  [NAN.f32      #:spec (NAN)      #:impl (const +nan.0)              #:fpcore NAN      #:cost 32bit-move-cost])\n\n(define-operation (neg.f32 [x <binary32>]) <binary32>\n  #:spec (neg x) #:impl (compose flsingle -)\n  #:fpcore (! :precision binary32 (- x)) #:cost 0.125)\n\n(define-operations ([x <binary32>] [y <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [+.f32 #:spec (+ x y) #:impl (compose flsingle +) #:cost 0.200]\n  [-.f32 #:spec (- x y) #:impl (compose flsingle -) #:cost 0.200]\n  [*.f32 #:spec (* x y) #:impl (compose flsingle *) #:cost 0.250]\n  [/.f32 #:spec (/ x y) #:impl (compose flsingle /) #:cost 0.350])\n\n(define-operations ([x <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [sin.f32    #:spec (sin x)    #:impl (from-libm 'sinf)    #:cost 4.250]\n  [cos.f32    #:spec (cos x)    #:impl (from-libm 'cosf)    #:cost 4.250]\n  [tan.f32    #:spec (tan x)    #:impl (from-libm 'tanf)    #:cost 4.750]\n  [sinh.f32   #:spec (sinh x)   #:impl (from-libm 'sinhf)   #:cost 1.750]\n  [cosh.f32   #:spec (cosh x)   #:impl (from-libm 'coshf)   #:cost 1.250]\n  [acos.f32   #:spec (acos x)   #:impl (from-libm 'acosf)   #:cost 0.500]\n  [acosh.f32  #:spec (acosh x)  #:impl (from-libm 'acoshf)  #:cost 0.850]\n  [asin.f32   #:spec (asin x)   #:impl (from-libm 'asinf)   #:cost 0.500]\n  [asinh.f32  #:spec (asinh x)  #:impl (from-libm 'asinhf)  #:cost 1.125]\n  [atan.f32   #:spec (atan x)   #:impl (from-libm 'atanf)   #:cost 1.100]\n  [atanh.f32  #:spec (atanh x)  #:impl (from-libm 'atanhf)  #:cost 0.500]\n  [cbrt.f32   #:spec (cbrt x)   #:impl (from-libm 'cbrtf)   #:cost 2.000]\n  [ceil.f32   #:spec (ceil x)   #:impl (from-libm 'ceilf)   #:cost 0.250]\n  [erf.f32    #:spec (erf x)    #:impl (from-libm 'erff)    #:cost 1.125]\n  [exp.f32    #:spec (exp x)    #:impl (from-libm 'expf)    #:cost 1.375]\n  [exp2.f32   #:spec (exp2 x)   #:impl (from-libm 'exp2f)   #:cost 1.175]\n  [floor.f32  #:spec (floor x)  #:impl (from-libm 'floorf)  #:cost 0.250]\n  [lgamma.f32 #:spec (lgamma x) #:impl (from-libm 'lgammaf) #:cost 2.250]\n  [log.f32    #:spec (log x)    #:impl (from-libm 'logf)    #:cost 0.750]\n  [log10.f32  #:spec (log10 x)  #:impl (from-libm 'log10f)  #:cost 1.175]\n  [log2.f32   #:spec (log2 x)   #:impl (from-libm 'log2f)   #:cost 0.875]\n  [logb.f32   #:spec (logb x)   #:impl (from-libm 'logbf)   #:cost 0.375]\n  [rint.f32   #:spec (rint x)   #:impl (from-libm 'rintf)   #:cost 0.300]\n  [round.f32  #:spec (round x)  #:impl (from-libm 'roundf)  #:cost 0.875]\n  [sqrt.f32   #:spec (sqrt x)   #:impl (from-libm 'sqrtf)   #:cost 0.250]\n  [tanh.f32   #:spec (tanh x)   #:impl (from-libm 'tanhf)   #:cost 1.000]\n  [tgamma.f32 #:spec (tgamma x) #:impl (from-libm 'tgammaf) #:cost 2.625]\n  [trunc.f32  #:spec (trunc x)  #:impl (from-libm 'truncf)  #:cost 0.275])\n\n(define-operations ([x <binary32>] [y <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [pow.f32       #:spec (pow x y)       #:impl (from-libm 'powf)       #:cost 2.000]\n  [atan2.f32     #:spec (atan2 x y)     #:impl (from-libm 'atan2f)     #:cost 2.000]\n  [copysign.f32  #:spec (copysign x y)  #:impl (from-libm 'copysignf)  #:cost 0.200]\n  [fdim.f32      #:spec (fdim x y)      #:impl (from-libm 'fdimf)      #:cost 0.750]\n  [fmax.f32      #:spec (fmax x y)      #:impl (from-libm 'fmaxf)      #:cost 0.250]\n  [fmin.f32      #:spec (fmin x y)      #:impl (from-libm 'fminf)      #:cost 0.250]\n  [fmod.f32      #:spec (fmod x y)      #:impl (from-libm 'fmodf)      #:cost 1.750]\n  [remainder.f32 #:spec (remainder x y) #:impl (from-libm 'remainderf) #:cost 1.000])\n\n(define-operations ([x <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [erfc.f32  #:spec (- 1 (erf x)) #:impl (from-libm 'erfcf)  #:fpcore (erfc x)  #:cost 0.900]\n  [expm1.f32 #:spec (- (exp x) 1) #:impl (from-libm 'expm1f) #:fpcore (expm1 x) #:cost 0.900]\n  [log1p.f32 #:spec (log (+ 1 x)) #:impl (from-libm 'log1pf) #:fpcore (log1p x) #:cost 1.300])\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <binary64> #:cost 64bit-move-cost)\n\n(define-operation (if.f64 [c <bool>] [t <binary64>] [f <binary64>]) <binary64>\n  #:spec (if c t f) #:impl if-impl\n  #:cost (if-cost boolean-move-cost))\n\n(define-operations ([x <binary64>] [y <binary64>]) <binary64>\n  [+.f64 #:spec (+ x y) #:impl + #:cost 0.200]\n  [-.f64 #:spec (- x y) #:impl - #:cost 0.200]\n  [*.f64 #:spec (* x y) #:impl * #:cost 0.250]\n  [/.f64 #:spec (/ x y) #:impl / #:cost 0.350])\n\n(define-operations () <binary64> #:fpcore (! :precision binary64 _)\n  [PI.f64   #:spec (PI)       #:impl (const pi)      #:fpcore PI       #:cost 64bit-move-cost]\n  [E.f64    #:spec (E)        #:impl (const (exp 1)) #:fpcore E        #:cost 64bit-move-cost]\n  [INFINITY #:spec (INFINITY) #:impl (const +inf.0)  #:fpcore INFINITY #:cost 64bit-move-cost]\n  [NAN.f64  #:spec (NAN)      #:impl (const +nan.0)  #:fpcore NAN      #:cost 64bit-move-cost])\n\n(define-operation (neg.f64 [x <binary64>]) <binary64>\n  #:spec (neg x) #:impl -\n  #:fpcore (! :precision binary64 (- x)) #:cost 0.125)\n\n(define-operations ([x <binary64>] [y <binary64>]) <bool>\n  [==.f64 #:spec (== x y) #:impl =          #:cost 64bit-move-cost]\n  [!=.f64 #:spec (!= x y) #:impl (negate =) #:cost 64bit-move-cost]\n  [<.f64  #:spec (< x y)  #:impl <          #:cost 64bit-move-cost]\n  [>.f64  #:spec (> x y)  #:impl >          #:cost 64bit-move-cost]\n  [<=.f64 #:spec (<= x y) #:impl <=         #:cost 64bit-move-cost]\n  [>=.f64 #:spec (>= x y) #:impl >=         #:cost 64bit-move-cost])\n\n(define-operations ([x <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [fabs.f64   #:spec (fabs x)   #:impl (from-libm 'fabs)      #:cost 0.125]\n  [sin.f64    #:spec (sin x)    #:impl (from-libm 'sin)       #:cost 4.200]\n  [cos.f64    #:spec (cos x)    #:impl (from-libm 'cos)       #:cost 4.200]\n  [tan.f64    #:spec (tan x)    #:impl (from-libm 'tan)       #:cost 4.650]\n  [sinh.f64   #:spec (sinh x)   #:impl (from-libm 'sinh)      #:cost 1.750]\n  [cosh.f64   #:spec (cosh x)   #:impl (from-libm 'cosh)      #:cost 1.650]\n  [acos.f64   #:spec (acos x)   #:impl (from-libm 'acos)      #:cost 0.500]\n  [acosh.f64  #:spec (acosh x)  #:impl (from-libm 'acosh)     #:cost 0.850]\n  [asin.f64   #:spec (asin x)   #:impl (from-libm 'asin)      #:cost 0.500]\n  [asinh.f64  #:spec (asinh x)  #:impl (from-libm 'asinh)     #:cost 1.125]\n  [atan.f64   #:spec (atan x)   #:impl (from-libm 'atan)      #:cost 1.100]\n  [atanh.f64  #:spec (atanh x)  #:impl (from-libm 'atanh)     #:cost 0.450]\n  [cbrt.f64   #:spec (cbrt x)   #:impl (from-libm 'cbrt)      #:cost 2.000]\n  [ceil.f64   #:spec (ceil x)   #:impl (from-libm 'ceil)      #:cost 0.250]\n  [erf.f64    #:spec (erf x)    #:impl (from-libm 'erf)       #:cost 1.125]\n  [exp.f64    #:spec (exp x)    #:impl (from-libm 'exp)       #:cost 1.375]\n  [exp2.f64   #:spec (exp2 x)   #:impl (from-libm 'exp2)      #:cost 1.175]\n  [floor.f64  #:spec (floor x)  #:impl (from-libm 'floor)     #:cost 0.300]\n  [lgamma.f64 #:spec (lgamma x) #:impl (from-libm 'lgamma)    #:cost 2.250]\n  [log.f64    #:spec (log x)    #:impl (from-libm 'log)       #:cost 0.750]\n  [log10.f64  #:spec (log10 x)  #:impl (from-libm 'log10)     #:cost 1.175]\n  [log2.f64   #:spec (log2 x)   #:impl (from-libm 'log2)      #:cost 0.850]\n  [logb.f64   #:spec (logb x)   #:impl (from-libm 'logb)      #:cost 0.350]\n  [rint.f64   #:spec (rint x)   #:impl (from-libm 'rint)      #:cost 0.300]\n  [round.f64  #:spec (round x)  #:impl (from-libm 'round)     #:cost 0.850]\n  [sqrt.f64   #:spec (sqrt x)   #:impl (from-libm 'sqrt)      #:cost 0.250]\n  [tanh.f64   #:spec (tanh x)   #:impl (from-libm 'tanh)      #:cost 1.000]\n  [tgamma.f64 #:spec (tgamma x) #:impl (from-libm 'tgamma)    #:cost 2.625]\n  [trunc.f64  #:spec (trunc x)  #:impl (from-libm 'trunc)     #:cost 0.250])\n\n(define-operations ([x <binary64>] [y <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [pow.f64       #:spec (pow x y)       #:impl (from-libm 'pow)       #:cost 2.000]\n  [atan2.f64     #:spec (atan2 x y)     #:impl (from-libm 'atan2)     #:cost 2.000]\n  [copysign.f64  #:spec (copysign x y)  #:impl (from-libm 'copysign)  #:cost 0.200]\n  [fdim.f64      #:spec (fdim x y)      #:impl (from-libm 'fdim)      #:cost 0.750]\n  [fmax.f64      #:spec (fmax x y)      #:impl (from-libm 'fmax)      #:cost 0.250]\n  [fmin.f64      #:spec (fmin x y)      #:impl (from-libm 'fmin)      #:cost 0.250]\n  [fmod.f64      #:spec (fmod x y)      #:impl (from-libm 'fmod)      #:cost 1.750]\n  [remainder.f64 #:spec (remainder x y) #:impl (from-libm 'remainder) #:cost 1.000])\n\n(define-operations ([x <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [erfc.f64  #:spec (- 1 (erf x)) #:impl (from-libm 'erfc)  #:fpcore (erfc x)  #:cost 0.900]\n  [expm1.f64 #:spec (- (exp x) 1) #:impl (from-libm 'expm1) #:fpcore (expm1 x) #:cost 0.900]\n  [log1p.f64 #:spec (log (+ 1 x)) #:impl (from-libm 'log1p) #:fpcore (log1p x) #:cost 1.300])\n\n(define-operation (hypot.f64 [x <binary64>] [y <binary64>]) <binary64>\n  #:spec (sqrt (+ (* x x) (* y y))) #:impl (from-libm 'hypot)\n  #:fpcore (! :precision binary64 (hypot x y)) #:cost 1.700)\n\n(define-operation (fma.f64 [x <binary64>] [y <binary64>] [z <binary64>]) <binary64>\n  #:spec (+ (* x y) z) #:impl (from-libm 'fma)\n  #:fpcore (! :precision binary64 (fma x y z)) #:cost 0.375)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CASTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-operation (binary64->binary32 [x <binary64>]) <binary32>\n  #:spec x #:fpcore (! :precision binary32 (cast x)) #:impl flsingle #:cost 32bit-move-cost)\n\n(define-operation (binary32->binary64 [x <binary32>]) <binary64>\n  #:spec x #:fpcore (! :precision binary64 (cast x)) #:impl identity #:cost 64bit-move-cost)\n"
  },
  {
    "path": "src/platforms/c.rkt",
    "content": "#lang s-exp \"../syntax/platform-language.rkt\"\n\n;; C/C++ platform with a full libm\n\n(require math/flonum)\n\n(define 64bit-move-cost   0.125)\n(define 32bit-move-cost   0.125)\n(define boolean-move-cost 0.100)\n\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BOOLEAN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <bool> #:cost boolean-move-cost)\n\n(define-operations () <bool>\n  [TRUE  #:spec (TRUE)  #:impl (const true)  #:fpcore TRUE  #:cost boolean-move-cost]\n  [FALSE #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost boolean-move-cost])\n\n(define-operations ([x <bool>] [y <bool>]) <bool>\n  [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost boolean-move-cost]\n  [or  #:spec (or x y)  #:impl (lambda v (ormap values v))  #:cost boolean-move-cost])\n\n(define-operation (not [x <bool>]) <bool>\n  #:spec (not x) #:impl not #:cost boolean-move-cost)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <binary32> #:cost 32bit-move-cost)\n(define <array32> (make-array-representation #:elem <binary32> #:len 2))\n(define <array32r3> (make-array-representation #:elem <binary32> #:len 3))\n\n(define-operation (if.f32 [c <bool>] [t <binary32>] [f <binary32>]) <binary32>\n  #:spec (if c t f) #:impl if-impl\n  #:cost (if-cost boolean-move-cost))\n\n(define-operations ([x <binary32>] [y <binary32>]) <bool>\n  [==.f32 #:spec (== x y) #:impl =          #:cost 32bit-move-cost]\n  [!=.f32 #:spec (!= x y) #:impl (negate =) #:cost 32bit-move-cost]\n  [<.f32  #:spec (< x y)  #:impl <          #:cost 32bit-move-cost]\n  [>.f32  #:spec (> x y)  #:impl >          #:cost 32bit-move-cost]\n  [<=.f32 #:spec (<= x y) #:impl <=         #:cost 32bit-move-cost]\n  [>=.f32 #:spec (>= x y) #:impl >=         #:cost 32bit-move-cost])\n\n(define-operations () <binary32> #:fpcore (! :precision binary32 _)\n  [PI.f32       #:spec (PI)       #:impl (const (flsingle pi))       #:fpcore PI       #:cost 32bit-move-cost]\n  [E.f32        #:spec (E)        #:impl (const (flsingle (exp 1)))  #:fpcore E        #:cost 32bit-move-cost]\n  [INFINITY.f32 #:spec (INFINITY) #:impl (const +inf.0)              #:fpcore INFINITY #:cost 32bit-move-cost]\n  [NAN.f32      #:spec (NAN)      #:impl (const +nan.0)              #:fpcore NAN      #:cost 32bit-move-cost])\n\n(define-operation (neg.f32 [x <binary32>]) <binary32>\n  #:spec (neg x) #:impl (compose flsingle -)\n  #:fpcore (! :precision binary32 (- x)) #:cost 0.125)\n\n(define-operations ([x <binary32>] [y <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [+.f32 #:spec (+ x y) #:impl (compose flsingle +) #:cost 0.200]\n  [-.f32 #:spec (- x y) #:impl (compose flsingle -) #:cost 0.200]\n  [*.f32 #:spec (* x y) #:impl (compose flsingle *) #:cost 0.250]\n  [/.f32 #:spec (/ x y) #:impl (compose flsingle /) #:cost 0.350])\n\n(define-operations ([x <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [fabs.f32   #:spec (fabs x)   #:impl (from-libm 'fabsf)   #:cost 0.125]\n  [sin.f32    #:spec (sin x)    #:impl (from-libm 'sinf)    #:cost 4.250]\n  [cos.f32    #:spec (cos x)    #:impl (from-libm 'cosf)    #:cost 4.250]\n  [tan.f32    #:spec (tan x)    #:impl (from-libm 'tanf)    #:cost 4.750]\n  [sinh.f32   #:spec (sinh x)   #:impl (from-libm 'sinhf)   #:cost 1.750]\n  [cosh.f32   #:spec (cosh x)   #:impl (from-libm 'coshf)   #:cost 1.250]\n  [acos.f32   #:spec (acos x)   #:impl (from-libm 'acosf)   #:cost 0.500]\n  [acosh.f32  #:spec (acosh x)  #:impl (from-libm 'acoshf)  #:cost 0.850]\n  [asin.f32   #:spec (asin x)   #:impl (from-libm 'asinf)   #:cost 0.500]\n  [asinh.f32  #:spec (asinh x)  #:impl (from-libm 'asinhf)  #:cost 1.125]\n  [atan.f32   #:spec (atan x)   #:impl (from-libm 'atanf)   #:cost 1.100]\n  [atanh.f32  #:spec (atanh x)  #:impl (from-libm 'atanhf)  #:cost 0.500]\n  [cbrt.f32   #:spec (cbrt x)   #:impl (from-libm 'cbrtf)   #:cost 2.000]\n  [ceil.f32   #:spec (ceil x)   #:impl (from-libm 'ceilf)   #:cost 0.250]\n  [erf.f32    #:spec (erf x)    #:impl (from-libm 'erff)    #:cost 1.125]\n  [exp.f32    #:spec (exp x)    #:impl (from-libm 'expf)    #:cost 1.375]\n  [exp2.f32   #:spec (exp2 x)   #:impl (from-libm 'exp2f)   #:cost 1.175]\n  [floor.f32  #:spec (floor x)  #:impl (from-libm 'floorf)  #:cost 0.250]\n  [lgamma.f32 #:spec (lgamma x) #:impl (from-libm 'lgammaf) #:cost 2.250]\n  [log.f32    #:spec (log x)    #:impl (from-libm 'logf)    #:cost 0.750]\n  [log10.f32  #:spec (log10 x)  #:impl (from-libm 'log10f)  #:cost 1.175]\n  [log2.f32   #:spec (log2 x)   #:impl (from-libm 'log2f)   #:cost 0.875]\n  [logb.f32   #:spec (logb x)   #:impl (from-libm 'logbf)   #:cost 0.375]\n  [rint.f32   #:spec (rint x)   #:impl (from-libm 'rintf)   #:cost 0.300]\n  [round.f32  #:spec (round x)  #:impl (from-libm 'roundf)  #:cost 0.875]\n  [sqrt.f32   #:spec (sqrt x)   #:impl (from-libm 'sqrtf)   #:cost 0.250]\n  [tanh.f32   #:spec (tanh x)   #:impl (from-libm 'tanhf)   #:cost 1.000]\n  [tgamma.f32 #:spec (tgamma x) #:impl (from-libm 'tgammaf) #:cost 2.625]\n  [trunc.f32  #:spec (trunc x)  #:impl (from-libm 'truncf)  #:cost 0.275])\n\n(define-representation <array32> #:cost (* 2 32bit-move-cost))\n(define-representation <array32r3> #:cost (* 3 32bit-move-cost))\n\n(define-operation (array.f32 [x <binary32>] [y <binary32>]) <array32>\n  #:spec (array x y)\n  #:impl (lambda (a b) (vector a b))\n  #:fpcore (! :precision binary32 (array x y))\n  #:cost 0.25)\n\n(define-operation (array3.f32 [x <binary32>] [y <binary32>] [z <binary32>]) <array32r3>\n  #:spec (array x y z)\n  #:impl (lambda (a b c) (vector a b c))\n  #:fpcore (! :precision binary32 (array x y z))\n  #:cost 0.375)\n\n(define-operation (ref.f32 [arr <array32>] [idx <binary32>]) <binary32>\n  #:spec (ref arr idx)\n  #:impl (lambda (arr idx)\n           (vector-ref arr (inexact->exact (round idx))))\n  #:fpcore (! :precision binary32 (ref arr idx))\n  #:cost 0.2)\n\n(define-operation (ref.r3.f32 [arr <array32r3>] [idx <binary32>]) <binary32>\n  #:spec (ref arr idx)\n  #:impl (lambda (arr idx)\n           (vector-ref arr (inexact->exact (round idx))))\n  #:fpcore (! :precision binary32 (ref arr idx))\n  #:cost 0.2)\n\n(define-operations ([x <binary32>] [y <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [pow.f32       #:spec (pow x y)       #:impl (from-libm 'powf)       #:cost 2.000]\n  [atan2.f32     #:spec (atan2 x y)     #:impl (from-libm 'atan2f)     #:cost 2.000]\n  [copysign.f32  #:spec (copysign x y)  #:impl (from-libm 'copysignf)  #:cost 0.200]\n  [fdim.f32      #:spec (fdim x y)      #:impl (from-libm 'fdimf)      #:cost 0.750]\n  [fmax.f32      #:spec (fmax x y)      #:impl (from-libm 'fmaxf)      #:cost 0.250]\n  [fmin.f32      #:spec (fmin x y)      #:impl (from-libm 'fminf)      #:cost 0.250]\n  [fmod.f32      #:spec (fmod x y)      #:impl (from-libm 'fmodf)      #:cost 1.750]\n  [remainder.f32 #:spec (remainder x y) #:impl (from-libm 'remainderf) #:cost 1.000])\n\n(define-operations ([x <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [erfc.f32  #:spec (- 1 (erf x)) #:impl (from-libm 'erfcf)  #:fpcore (erfc x)  #:cost 0.900]\n  [expm1.f32 #:spec (- (exp x) 1) #:impl (from-libm 'expm1f) #:fpcore (expm1 x) #:cost 0.900]\n  [log1p.f32 #:spec (log (+ 1 x)) #:impl (from-libm 'log1pf) #:fpcore (log1p x) #:cost 1.300])\n\n(define-operation (hypot.f32 [x <binary32>] [y <binary32>]) <binary32>\n  #:spec (sqrt (+ (* x x) (* y y))) #:impl (from-libm 'hypotf)\n  #:fpcore (! :precision binary32 (hypot x y)) #:cost 1.700)\n\n(define-operation (fma.f32 [x <binary32>] [y <binary32>] [z <binary32>]) <binary32>\n  #:spec (+ (* x y) z) #:impl (from-libm 'fmaf)\n  #:fpcore (! :precision binary32 (fma x y z)) #:cost 0.375)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <binary64> #:cost 64bit-move-cost)\n(define <array64> (make-array-representation #:elem <binary64> #:len 2))\n(define <array64r3> (make-array-representation #:elem <binary64> #:len 3))\n(define <array64r2> (make-array-representation #:elem <array64> #:len 2))\n\n(define-operation (if.f64 [c <bool>] [t <binary64>] [f <binary64>]) <binary64>\n  #:spec (if c t f) #:impl if-impl\n  #:cost (if-cost boolean-move-cost))\n\n(define-operations ([x <binary64>] [y <binary64>]) <bool>\n  [==.f64 #:spec (== x y) #:impl =          #:cost 64bit-move-cost]\n  [!=.f64 #:spec (!= x y) #:impl (negate =) #:cost 64bit-move-cost]\n  [<.f64  #:spec (< x y)  #:impl <          #:cost 64bit-move-cost]\n  [>.f64  #:spec (> x y)  #:impl >          #:cost 64bit-move-cost]\n  [<=.f64 #:spec (<= x y) #:impl <=         #:cost 64bit-move-cost]\n  [>=.f64 #:spec (>= x y) #:impl >=         #:cost 64bit-move-cost])\n\n(define-operations () <binary64> #:fpcore (! :precision binary64 _)\n  [PI.f64   #:spec (PI)       #:impl (const pi)      #:fpcore PI       #:cost 64bit-move-cost]\n  [E.f64    #:spec (E)        #:impl (const (exp 1)) #:fpcore E        #:cost 64bit-move-cost]\n  [INFINITY #:spec (INFINITY) #:impl (const +inf.0)  #:fpcore INFINITY #:cost 64bit-move-cost]\n  [NAN.f64  #:spec (NAN)      #:impl (const +nan.0)  #:fpcore NAN      #:cost 64bit-move-cost])\n\n(define-operation (neg.f64 [x <binary64>]) <binary64>\n  #:spec (neg x) #:impl - #:fpcore (! :precision binary64 (- x)) #:cost 0.125)\n\n(define-operations ([x <binary64>] [y <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [+.f64 #:spec (+ x y) #:impl + #:cost 0.200]\n  [-.f64 #:spec (- x y) #:impl - #:cost 0.200]\n  [*.f64 #:spec (* x y) #:impl * #:cost 0.250]\n  [/.f64 #:spec (/ x y) #:impl / #:cost 0.350])\n\n(define-operations ([x <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [fabs.f64   #:spec (fabs x)   #:impl (from-libm 'fabs)      #:cost 0.125]\n  [sin.f64    #:spec (sin x)    #:impl (from-libm 'sin)       #:cost 4.200]\n  [cos.f64    #:spec (cos x)    #:impl (from-libm 'cos)       #:cost 4.200]\n  [tan.f64    #:spec (tan x)    #:impl (from-libm 'tan)       #:cost 4.650]\n  [sinh.f64   #:spec (sinh x)   #:impl (from-libm 'sinh)      #:cost 1.750]\n  [cosh.f64   #:spec (cosh x)   #:impl (from-libm 'cosh)      #:cost 1.650]\n  [acos.f64   #:spec (acos x)   #:impl (from-libm 'acos)      #:cost 0.500]\n  [acosh.f64  #:spec (acosh x)  #:impl (from-libm 'acosh)     #:cost 0.850]\n  [asin.f64   #:spec (asin x)   #:impl (from-libm 'asin)      #:cost 0.500]\n  [asinh.f64  #:spec (asinh x)  #:impl (from-libm 'asinh)     #:cost 1.125]\n  [atan.f64   #:spec (atan x)   #:impl (from-libm 'atan)      #:cost 1.100]\n  [atanh.f64  #:spec (atanh x)  #:impl (from-libm 'atanh)     #:cost 0.450]\n  [cbrt.f64   #:spec (cbrt x)   #:impl (from-libm 'cbrt)      #:cost 2.000]\n  [ceil.f64   #:spec (ceil x)   #:impl (from-libm 'ceil)      #:cost 0.250]\n  [erf.f64    #:spec (erf x)    #:impl (from-libm 'erf)       #:cost 1.125]\n  [exp.f64    #:spec (exp x)    #:impl (from-libm 'exp)       #:cost 1.375]\n  [exp2.f64   #:spec (exp2 x)   #:impl (from-libm 'exp2)      #:cost 1.175]\n  [floor.f64  #:spec (floor x)  #:impl (from-libm 'floor)     #:cost 0.300]\n  [lgamma.f64 #:spec (lgamma x) #:impl (from-libm 'lgamma)    #:cost 2.250]\n  [log.f64    #:spec (log x)    #:impl (from-libm 'log)       #:cost 0.750]\n  [log10.f64  #:spec (log10 x)  #:impl (from-libm 'log10)     #:cost 1.175]\n  [log2.f64   #:spec (log2 x)   #:impl (from-libm 'log2)      #:cost 0.850]\n  [logb.f64   #:spec (logb x)   #:impl (from-libm 'logb)      #:cost 0.350]\n  [rint.f64   #:spec (rint x)   #:impl (from-libm 'rint)      #:cost 0.300]\n  [round.f64  #:spec (round x)  #:impl (from-libm 'round)     #:cost 0.850]\n  [sqrt.f64   #:spec (sqrt x)   #:impl (from-libm 'sqrt)      #:cost 0.250]\n  [tanh.f64   #:spec (tanh x)   #:impl (from-libm 'tanh)      #:cost 1.000]\n  [tgamma.f64 #:spec (tgamma x) #:impl (from-libm 'tgamma)    #:cost 2.625]\n  [trunc.f64  #:spec (trunc x)  #:impl (from-libm 'trunc)     #:cost 0.250])\n\n(define-representation <array64> #:cost (* 2 64bit-move-cost))\n(define-representation <array64r3> #:cost (* 3 64bit-move-cost))\n(define-representation <array64r2> #:cost (* 2 64bit-move-cost))\n\n(define-operation (array.f64 [x <binary64>] [y <binary64>]) <array64>\n  #:spec (array x y)\n  #:impl (lambda (a b) (vector a b))\n  #:fpcore (! :precision binary64 (array x y))\n  #:cost 0.25)\n\n(define-operation (array3.f64 [x <binary64>] [y <binary64>] [z <binary64>]) <array64r3>\n  #:spec (array x y z)\n  #:impl (lambda (a b c) (vector a b c))\n  #:fpcore (! :precision binary64 (array x y z))\n  #:cost 0.375)\n\n(define-operation (array2.f64 [x <array64>] [y <array64>]) <array64r2>\n  #:spec (array x y)\n  #:impl (lambda (a b) (vector a b))\n  #:fpcore (array x y)\n  #:cost 0.25)\n\n(define-operation (ref.f64 [arr <array64>] [idx <binary64>]) <binary64>\n  #:spec (ref arr idx)\n  #:impl (lambda (arr idx)\n           (vector-ref arr (inexact->exact (round idx))))\n  #:fpcore (! :precision binary64 (ref arr idx))\n  #:cost 0.2)\n\n(define-operation (ref.r3.f64 [arr <array64r3>] [idx <binary64>]) <binary64>\n  #:spec (ref arr idx)\n  #:impl (lambda (arr idx)\n           (vector-ref arr (inexact->exact (round idx))))\n  #:fpcore (! :precision binary64 (ref arr idx))\n  #:cost 0.2)\n\n(define-operation (ref.r2.f64 [arr <array64r2>] [idx <binary64>]) <array64>\n  #:spec (ref arr idx)\n  #:impl (lambda (arr idx)\n           (vector-ref arr (inexact->exact (round idx))))\n  #:fpcore (! :precision binary64 (ref arr idx))\n  #:cost 0.2)\n\n\n(define-operations ([x <binary64>] [y <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [pow.f64       #:spec (pow x y)       #:impl (from-libm 'pow)       #:cost 2.000]\n  [atan2.f64     #:spec (atan2 x y)     #:impl (from-libm 'atan2)     #:cost 2.000]\n  [copysign.f64  #:spec (copysign x y)  #:impl (from-libm 'copysign)  #:cost 0.200]\n  [fdim.f64      #:spec (fdim x y)      #:impl (from-libm 'fdim)      #:cost 0.750]\n  [fmax.f64      #:spec (fmax x y)      #:impl (from-libm 'fmax)      #:cost 0.250]\n  [fmin.f64      #:spec (fmin x y)      #:impl (from-libm 'fmin)      #:cost 0.250]\n  [fmod.f64      #:spec (fmod x y)      #:impl (from-libm 'fmod)      #:cost 1.750]\n  [remainder.f64 #:spec (remainder x y) #:impl (from-libm 'remainder) #:cost 1.000])\n\n(define-operations ([x <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [erfc.f64  #:spec (- 1 (erf x)) #:impl (from-libm 'erfc)  #:fpcore (erfc x) #:cost 0.900]\n  [expm1.f64 #:spec (- (exp x) 1) #:impl (from-libm 'expm1) #:fpcore (expm1 x) #:cost 0.900]\n  [log1p.f64 #:spec (log (+ 1 x)) #:impl (from-libm 'log1p) #:fpcore (log1p x) #:cost 1.300])\n\n(define-operation (hypot.f64 [x <binary64>] [y <binary64>]) <binary64>\n  #:spec (sqrt (+ (* x x) (* y y))) #:impl (from-libm 'hypot)\n  #:fpcore (! :precision binary64 (hypot x y)) #:cost 1.700)\n\n(define-operation (fma.f64 [x <binary64>] [y <binary64>] [z <binary64>]) <binary64>\n  #:spec (+ (* x y) z) #:impl (from-libm 'fma)\n  #:fpcore (! :precision binary64 (fma x y z)) #:cost 0.375)\n"
  },
  {
    "path": "src/platforms/herbie10.rkt",
    "content": "#lang s-exp \"../syntax/platform-language.rkt\"\n\n;; Herbie 1.0 platform. Based on the C Windows platform, but with\n;; every operation having cost 0, so as to emulate no-pareto mode.\n\n(require math/flonum)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BOOLEAN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <bool> #:cost 0)\n\n(define-operations () <bool>\n  [TRUE  #:spec (TRUE)  #:impl (const true)  #:fpcore TRUE  #:cost 0]\n  [FALSE #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost 0])\n\n(define-operations ([x <bool>] [y <bool>]) <bool>\n  [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost 0]\n  [or  #:spec (or x y)  #:impl (lambda v (ormap values v))  #:cost 0])\n\n(define-operation (not [x <bool>]) <bool>\n  #:spec (not x) #:impl not #:cost 0)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <binary32> #:cost 0)\n\n(define-operation (if.f32 [c <bool>] [t <binary32>] [f <binary32>]) <binary32>\n  #:spec (if c t f) #:impl if-impl\n  #:cost (if-cost 0))\n\n(define-operations ([x <binary32>] [y <binary32>]) <bool>\n  [==.f32 #:spec (== x y) #:impl =          #:cost 0]\n  [!=.f32 #:spec (!= x y) #:impl (negate =) #:cost 0]\n  [<.f32  #:spec (< x y)  #:impl <          #:cost 0]\n  [>.f32  #:spec (> x y)  #:impl >          #:cost 0]\n  [<=.f32 #:spec (<= x y) #:impl <=         #:cost 0]\n  [>=.f32 #:spec (>= x y) #:impl >=         #:cost 0])\n\n(define-operations () <binary32> #:fpcore (! :precision binary32 _)\n  [PI.f32       #:spec (PI)       #:impl (const (flsingle pi))       #:fpcore PI       #:cost 0]\n  [E.f32        #:spec (E)        #:impl (const (flsingle (exp 1)))  #:fpcore E        #:cost 0]\n  [INFINITY.f32 #:spec (INFINITY) #:impl (const +inf.0)              #:fpcore INFINITY #:cost 0]\n  [NAN.f32      #:spec (NAN)      #:impl (const +nan.0)              #:fpcore NAN      #:cost 0])\n\n(define-operation (neg.f32 [x <binary32>]) <binary32>\n  #:spec (neg x) #:impl (compose flsingle -)\n  #:fpcore (! :precision binary32 (- x)) #:cost 0)\n  \n(define-operations ([x <binary32>] [y <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [+.f32 #:spec (+ x y) #:impl (compose flsingle +) #:cost 0]\n  [-.f32 #:spec (- x y) #:impl (compose flsingle -) #:cost 0]\n  [*.f32 #:spec (* x y) #:impl (compose flsingle *) #:cost 0]\n  [/.f32 #:spec (/ x y) #:impl (compose flsingle /) #:cost 0])\n\n(define-operations ([x <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [fabs.f32   #:spec (fabs x)   #:impl (from-libm 'fabsf)   #:cost 0]\n  [sin.f32    #:spec (sin x)    #:impl (from-libm 'sinf)    #:cost 0]\n  [cos.f32    #:spec (cos x)    #:impl (from-libm 'cosf)    #:cost 0]\n  [tan.f32    #:spec (tan x)    #:impl (from-libm 'tanf)    #:cost 0]\n  [sinh.f32   #:spec (sinh x)   #:impl (from-libm 'sinhf)   #:cost 0]\n  [cosh.f32   #:spec (cosh x)   #:impl (from-libm 'coshf)   #:cost 0]\n  [acos.f32   #:spec (acos x)   #:impl (from-libm 'acosf)   #:cost 0]\n  [acosh.f32  #:spec (acosh x)  #:impl (from-libm 'acoshf)  #:cost 0]\n  [asin.f32   #:spec (asin x)   #:impl (from-libm 'asinf)   #:cost 0]\n  [asinh.f32  #:spec (asinh x)  #:impl (from-libm 'asinhf)  #:cost 0]\n  [atan.f32   #:spec (atan x)   #:impl (from-libm 'atanf)   #:cost 0]\n  [atanh.f32  #:spec (atanh x)  #:impl (from-libm 'atanhf)  #:cost 0]\n  [cbrt.f32   #:spec (cbrt x)   #:impl (from-libm 'cbrtf)   #:cost 0]\n  [ceil.f32   #:spec (ceil x)   #:impl (from-libm 'ceilf)   #:cost 0]\n  [erf.f32    #:spec (erf x)    #:impl (from-libm 'erff)    #:cost 0]\n  [exp.f32    #:spec (exp x)    #:impl (from-libm 'expf)    #:cost 0]\n  [exp2.f32   #:spec (exp2 x)   #:impl (from-libm 'exp2f)   #:cost 0]\n  [floor.f32  #:spec (floor x)  #:impl (from-libm 'floorf)  #:cost 0]\n  [lgamma.f32 #:spec (lgamma x) #:impl (from-libm 'lgammaf) #:cost 0]\n  [log.f32    #:spec (log x)    #:impl (from-libm 'logf)    #:cost 0]\n  [log10.f32  #:spec (log10 x)  #:impl (from-libm 'log10f)  #:cost 0]\n  [log2.f32   #:spec (log2 x)   #:impl (from-libm 'log2f)   #:cost 0]\n  [logb.f32   #:spec (logb x)   #:impl (from-libm 'logbf)   #:cost 0]\n  [rint.f32   #:spec (rint x)   #:impl (from-libm 'rintf)   #:cost 0]\n  [round.f32  #:spec (round x)  #:impl (from-libm 'roundf)  #:cost 0]\n  [sqrt.f32   #:spec (sqrt x)   #:impl (from-libm 'sqrtf)   #:cost 0]\n  [tanh.f32   #:spec (tanh x)   #:impl (from-libm 'tanhf)   #:cost 0]\n  [tgamma.f32 #:spec (tgamma x) #:impl (from-libm 'tgammaf) #:cost 0]\n  [trunc.f32  #:spec (trunc x)  #:impl (from-libm 'truncf)  #:cost 0])\n  \n(define-operations ([x <binary32>] [y <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [pow.f32       #:spec (pow x y)       #:impl (from-libm 'powf)       #:cost 0]\n  [atan2.f32     #:spec (atan2 x y)     #:impl (from-libm 'atan2f)     #:cost 0]\n  [copysign.f32  #:spec (copysign x y)  #:impl (from-libm 'copysignf)  #:cost 0]\n  [fdim.f32      #:spec (fdim x y)      #:impl (from-libm 'fdimf)      #:cost 0]\n  [fmax.f32      #:spec (fmax x y)      #:impl (from-libm 'fmaxf)      #:cost 0]\n  [fmin.f32      #:spec (fmin x y)      #:impl (from-libm 'fminf)      #:cost 0]\n  [fmod.f32      #:spec (fmod x y)      #:impl (from-libm 'fmodf)      #:cost 0]\n  [remainder.f32 #:spec (remainder x y) #:impl (from-libm 'remainderf) #:cost 0])\n  \n(define-operations ([x <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [erfc.f32  #:spec (- 1 (erf x)) #:impl (from-libm 'erfcf)  #:fpcore (erfc x)  #:cost 0]\n  [expm1.f32 #:spec (- (exp x) 1) #:impl (from-libm 'expm1f) #:fpcore (expm1 x) #:cost 0]\n  [log1p.f32 #:spec (log (+ 1 x)) #:impl (from-libm 'log1pf) #:fpcore (log1p x) #:cost 0])\n  \n(define-operation (hypot.f32 [x <binary32>] [y <binary32>]) <binary32>\n  #:spec (sqrt (+ (* x x) (* y y))) #:impl (from-libm 'hypotf)\n  #:fpcore (! :precision binary32 (hypot x y)) #:cost 0)\n\n(define-operation (fma.f32 [x <binary32>] [y <binary32>] [z <binary32>]) <binary32>\n  #:spec (+ (* x y) z) #:impl (from-libm 'fmaf)\n  #:fpcore (! :precision binary32 (fma x y z)) #:cost 0)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <binary64> #:cost 0)\n\n(define-operation (if.f64 [c <bool>] [t <binary64>] [f <binary64>]) <binary64>\n  #:spec (if c t f) #:impl if-impl\n  #:cost (if-cost 0))\n\n(define-operations ([x <binary64>] [y <binary64>]) <bool>\n  [==.f64 #:spec (== x y) #:impl =          #:cost 0]\n  [!=.f64 #:spec (!= x y) #:impl (negate =) #:cost 0]\n  [<.f64  #:spec (< x y)  #:impl <          #:cost 0]\n  [>.f64  #:spec (> x y)  #:impl >          #:cost 0]\n  [<=.f64 #:spec (<= x y) #:impl <=         #:cost 0]\n  [>=.f64 #:spec (>= x y) #:impl >=         #:cost 0])\n\n(define-operations () <binary64> #:fpcore (! :precision binary64 _)\n  [PI.f64   #:spec (PI)       #:impl (const pi)      #:fpcore PI       #:cost 0]\n  [E.f64    #:spec (E)        #:impl (const (exp 1)) #:fpcore E        #:cost 0]\n  [INFINITY #:spec (INFINITY) #:impl (const +inf.0)  #:fpcore INFINITY #:cost 0]\n  [NAN.f64  #:spec (NAN)      #:impl (const +nan.0)  #:fpcore NAN      #:cost 0])\n\n (define-operations ([x <binary64>] [y <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n   [+.f64 #:spec (+ x y) #:impl + #:cost 0]\n   [-.f64 #:spec (- x y) #:impl - #:cost 0]\n   [*.f64 #:spec (* x y) #:impl * #:cost 0]\n   [/.f64 #:spec (/ x y) #:impl / #:cost 0])\n\n (define-operation (neg.f64 [x <binary64>]) <binary64>\n   #:spec (neg x) #:impl -\n   #:fpcore (! :precision binary64 (- x)) #:cost 0)\n  \n (define-operations ([x <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n   [fabs.f64   #:spec (fabs x)   #:impl (from-libm 'fabs)      #:cost 0]\n   [sin.f64    #:spec (sin x)    #:impl (from-libm 'sin)       #:cost 0]\n   [cos.f64    #:spec (cos x)    #:impl (from-libm 'cos)       #:cost 0]\n   [tan.f64    #:spec (tan x)    #:impl (from-libm 'tan)       #:cost 0]\n   [sinh.f64   #:spec (sinh x)   #:impl (from-libm 'sinh)      #:cost 0]\n   [cosh.f64   #:spec (cosh x)   #:impl (from-libm 'cosh)      #:cost 0]\n   [acos.f64   #:spec (acos x)   #:impl (from-libm 'acos)      #:cost 0]\n   [acosh.f64  #:spec (acosh x)  #:impl (from-libm 'acosh)     #:cost 0]\n   [asin.f64   #:spec (asin x)   #:impl (from-libm 'asin)      #:cost 0]\n   [asinh.f64  #:spec (asinh x)  #:impl (from-libm 'asinh)     #:cost 0]\n   [atan.f64   #:spec (atan x)   #:impl (from-libm 'atan)      #:cost 0]\n   [atanh.f64  #:spec (atanh x)  #:impl (from-libm 'atanh)     #:cost 0]\n   [cbrt.f64   #:spec (cbrt x)   #:impl (from-libm 'cbrt)      #:cost 0]\n   [ceil.f64   #:spec (ceil x)   #:impl (from-libm 'ceil)      #:cost 0]\n   [erf.f64    #:spec (erf x)    #:impl (from-libm 'erf)       #:cost 0]\n   [exp.f64    #:spec (exp x)    #:impl (from-libm 'exp)       #:cost 0]\n   [exp2.f64   #:spec (exp2 x)   #:impl (from-libm 'exp2)      #:cost 0]\n   [floor.f64  #:spec (floor x)  #:impl (from-libm 'floor)     #:cost 0]\n   [lgamma.f64 #:spec (lgamma x) #:impl (from-libm 'lgamma)    #:cost 0]\n   [log.f64    #:spec (log x)    #:impl (from-libm 'log)       #:cost 0]\n   [log10.f64  #:spec (log10 x)  #:impl (from-libm 'log10)     #:cost 0]\n   [log2.f64   #:spec (log2 x)   #:impl (from-libm 'log2)      #:cost 0]\n   [logb.f64   #:spec (logb x)   #:impl (from-libm 'logb)      #:cost 0]\n   [rint.f64   #:spec (rint x)   #:impl (from-libm 'rint)      #:cost 0]\n   [round.f64  #:spec (round x)  #:impl (from-libm 'round)     #:cost 0]\n   [sqrt.f64   #:spec (sqrt x)   #:impl (from-libm 'sqrt)      #:cost 0]\n   [tanh.f64   #:spec (tanh x)   #:impl (from-libm 'tanh)      #:cost 0]\n   [tgamma.f64 #:spec (tgamma x) #:impl (from-libm 'tgamma)    #:cost 0]\n   [trunc.f64  #:spec (trunc x)  #:impl (from-libm 'trunc)     #:cost 0])\n  \n (define-operations ([x <binary64>] [y <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n   [pow.f64       #:spec (pow x y)       #:impl (from-libm 'pow)       #:cost 0]\n   [atan2.f64     #:spec (atan2 x y)     #:impl (from-libm 'atan2)     #:cost 0]\n   [copysign.f64  #:spec (copysign x y)  #:impl (from-libm 'copysign)  #:cost 0]\n   [fdim.f64      #:spec (fdim x y)      #:impl (from-libm 'fdim)      #:cost 0]\n   [fmax.f64      #:spec (fmax x y)      #:impl (from-libm 'fmax)      #:cost 0]\n   [fmin.f64      #:spec (fmin x y)      #:impl (from-libm 'fmin)      #:cost 0]\n   [fmod.f64      #:spec (fmod x y)      #:impl (from-libm 'fmod)      #:cost 0]\n   [remainder.f64 #:spec (remainder x y) #:impl (from-libm 'remainder) #:cost 0])\n  \n (define-operations ([x <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n   [erfc.f64  #:spec (- 1 (erf x)) #:impl (from-libm 'erfc)  #:fpcore (erfc x)  #:cost 0]\n   [expm1.f64 #:spec (- (exp x) 1) #:impl (from-libm 'expm1) #:fpcore (expm1 x) #:cost 0]\n   [log1p.f64 #:spec (log (+ 1 x)) #:impl (from-libm 'log1p) #:fpcore (log1p x) #:cost 0])\n\n (define-operation (hypot.f64 [x <binary64>] [y <binary64>]) <binary64>\n   #:spec (sqrt (+ (* x x) (* y y))) #:impl (from-libm 'hypot)\n   #:fpcore (! :precision binary64 (hypot x y)) #:cost 0)\n\n (define-operation (fma.f64 [x <binary64>] [y <binary64>] [z <binary64>]) <binary64>\n   #:spec (+ (* x y) z) #:impl (from-libm 'fma)\n   #:fpcore (! :precision binary64 (fma x y z)) #:cost 0)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CASTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-operation (binary64->binary32 [x <binary64>]) <binary32>\n  #:spec x #:fpcore (! :precision binary32 (cast x)) #:impl flsingle #:cost 0)\n\n(define-operation (binary32->binary64 [x <binary32>]) <binary64>\n  #:spec x #:fpcore (! :precision binary64 (cast x)) #:impl identity #:cost 0)\n"
  },
  {
    "path": "src/platforms/herbie20.rkt",
    "content": "#lang s-exp \"../syntax/platform-language.rkt\"\n\n;; Herbie 2.0 platform. Based on the C Windows platform, but with\n;; every operation having heuristic costs from Herbie 2.0.\n\n(require math/flonum)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BOOLEAN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <bool> #:cost 1)\n\n(define-operations () <bool>\n  [TRUE  #:spec (TRUE)  #:impl (const true)  #:fpcore TRUE  #:cost 1]\n  [FALSE #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost 1])\n\n(define-operations ([x <bool>] [y <bool>]) <bool>\n  [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost 1]\n  [or  #:spec (or x y)  #:impl (lambda v (ormap values v))  #:cost 1])\n\n(define-operation (not [x <bool>]) <bool>\n  #:spec (not x) #:impl not #:cost 1)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <binary32> #:cost 32)\n\n(define-operation (if.f32 [c <bool>] [t <binary32>] [f <binary32>]) <binary32>\n  #:spec (if c t f) #:impl if-impl\n  #:cost (if-cost 1))\n\n(define-operations ([x <binary32>] [y <binary32>]) <bool>\n  [==.f32 #:spec (== x y) #:impl =          #:cost 128]\n  [!=.f32 #:spec (!= x y) #:impl (negate =) #:cost 128]\n  [<.f32  #:spec (< x y)  #:impl <          #:cost 128]\n  [>.f32  #:spec (> x y)  #:impl >          #:cost 128]\n  [<=.f32 #:spec (<= x y) #:impl <=         #:cost 128]\n  [>=.f32 #:spec (>= x y) #:impl >=         #:cost 128])\n\n(define-operations () <binary32> #:fpcore (! :precision binary32 _)\n  [PI.f32       #:spec (PI)       #:impl (const (flsingle pi))       #:fpcore PI       #:cost 32]\n  [E.f32        #:spec (E)        #:impl (const (flsingle (exp 1)))  #:fpcore E        #:cost 32]\n  [INFINITY.f32 #:spec (INFINITY) #:impl (const +inf.0)              #:fpcore INFINITY #:cost 32]\n  [NAN.f32      #:spec (NAN)      #:impl (const +nan.0)              #:fpcore NAN      #:cost 32])\n\n(define-operation (neg.f32 [x <binary32>]) <binary32>\n  #:spec (neg x) #:impl (compose flsingle -)\n  #:fpcore (! :precision binary32 (- x)) #:cost 64)\n\n(define-operations ([x <binary32>] [y <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [+.f32 #:spec (+ x y) #:impl (compose flsingle +) #:cost 64]\n  [-.f32 #:spec (- x y) #:impl (compose flsingle -) #:cost 64]\n  [*.f32 #:spec (* x y) #:impl (compose flsingle *) #:cost 128]\n  [/.f32 #:spec (/ x y) #:impl (compose flsingle /) #:cost 320])\n\n(define-operations ([x <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [fabs.f32   #:spec (fabs x)   #:impl (from-libm 'fabsf)   #:cost 64]\n  [sin.f32    #:spec (sin x)    #:impl (from-libm 'sinf)    #:cost 3200]\n  [cos.f32    #:spec (cos x)    #:impl (from-libm 'cosf)    #:cost 3200]\n  [tan.f32    #:spec (tan x)    #:impl (from-libm 'tanf)    #:cost 3200]\n  [sinh.f32   #:spec (sinh x)   #:impl (from-libm 'sinhf)   #:cost 3200]\n  [cosh.f32   #:spec (cosh x)   #:impl (from-libm 'coshf)   #:cost 3200]\n  [acos.f32   #:spec (acos x)   #:impl (from-libm 'acosf)   #:cost 3200]\n  [acosh.f32  #:spec (acosh x)  #:impl (from-libm 'acoshf)  #:cost 3200]\n  [asin.f32   #:spec (asin x)   #:impl (from-libm 'asinf)   #:cost 3200]\n  [asinh.f32  #:spec (asinh x)  #:impl (from-libm 'asinhf)  #:cost 3200]\n  [atan.f32   #:spec (atan x)   #:impl (from-libm 'atanf)   #:cost 3200]\n  [atanh.f32  #:spec (atanh x)  #:impl (from-libm 'atanhf)  #:cost 3200]\n  [cbrt.f32   #:spec (cbrt x)   #:impl (from-libm 'cbrtf)   #:cost 3200]\n  [ceil.f32   #:spec (ceil x)   #:impl (from-libm 'ceilf)   #:cost 3200]\n  [erf.f32    #:spec (erf x)    #:impl (from-libm 'erff)    #:cost 3200]\n  [exp.f32    #:spec (exp x)    #:impl (from-libm 'expf)    #:cost 3200]\n  [exp2.f32   #:spec (exp2 x)   #:impl (from-libm 'exp2f)   #:cost 3200]\n  [floor.f32  #:spec (floor x)  #:impl (from-libm 'floorf)  #:cost 3200]\n  [lgamma.f32 #:spec (lgamma x) #:impl (from-libm 'lgammaf) #:cost 3200]\n  [log.f32    #:spec (log x)    #:impl (from-libm 'logf)    #:cost 3200]\n  [log10.f32  #:spec (log10 x)  #:impl (from-libm 'log10f)  #:cost 3200]\n  [log2.f32   #:spec (log2 x)   #:impl (from-libm 'log2f)   #:cost 3200]\n  [logb.f32   #:spec (logb x)   #:impl (from-libm 'logbf)   #:cost 3200]\n  [rint.f32   #:spec (rint x)   #:impl (from-libm 'rintf)   #:cost 3200]\n  [round.f32  #:spec (round x)  #:impl (from-libm 'roundf)  #:cost 3200]\n  [sqrt.f32   #:spec (sqrt x)   #:impl (from-libm 'sqrtf)   #:cost 320]\n  [tanh.f32   #:spec (tanh x)   #:impl (from-libm 'tanhf)   #:cost 3200]\n  [tgamma.f32 #:spec (tgamma x) #:impl (from-libm 'tgammaf) #:cost 3200]\n  [trunc.f32  #:spec (trunc x)  #:impl (from-libm 'truncf)  #:cost 3200])\n\n(define-operations ([x <binary32>] [y <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [pow.f32       #:spec (pow x y)       #:impl (from-libm 'powf)       #:cost 3200]\n  [atan2.f32     #:spec (atan2 x y)     #:impl (from-libm 'atan2f)     #:cost 3200]\n  [copysign.f32  #:spec (copysign x y)  #:impl (from-libm 'copysignf)  #:cost 3200]\n  [fdim.f32      #:spec (fdim x y)      #:impl (from-libm 'fdimf)      #:cost 3200]\n  [fmax.f32      #:spec (fmax x y)      #:impl (from-libm 'fmaxf)      #:cost 3200]\n  [fmin.f32      #:spec (fmin x y)      #:impl (from-libm 'fminf)      #:cost 3200]\n  [fmod.f32      #:spec (fmod x y)      #:impl (from-libm 'fmodf)      #:cost 3200]\n  [remainder.f32 #:spec (remainder x y) #:impl (from-libm 'remainderf) #:cost 3200])\n\n(define-operations ([x <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [erfc.f32  #:spec (- 1 (erf x)) #:impl (from-libm 'erfcf)  #:fpcore (erfc x)  #:cost 3200]\n  [expm1.f32 #:spec (- (exp x) 1) #:impl (from-libm 'expm1f) #:fpcore (expm1 x) #:cost 3200]\n  [log1p.f32 #:spec (log (+ 1 x)) #:impl (from-libm 'log1pf) #:fpcore (log1p x) #:cost 3200])\n\n(define-operation (hypot.f32 [x <binary32>] [y <binary32>]) <binary32>\n  #:spec (sqrt (+ (* x x) (* y y))) #:impl (from-libm 'hypotf)\n  #:fpcore (! :precision binary32 (hypot x y)) #:cost 3200)\n\n(define-operation (fma.f32 [x <binary32>] [y <binary32>] [z <binary32>]) <binary32>\n  #:spec (+ (* x y) z) #:impl (from-libm 'fmaf)\n  #:fpcore (! :precision binary32 (fma x y z)) #:cost 128)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <binary64> #:cost 64)\n\n(define-operation (if.f64 [c <bool>] [t <binary64>] [f <binary64>]) <binary64>\n  #:spec (if c t f) #:impl if-impl\n  #:cost (if-cost 1))\n\n(define-operations ([x <binary64>] [y <binary64>]) <bool>\n  [==.f64 #:spec (== x y) #:impl =          #:cost 256]\n  [!=.f64 #:spec (!= x y) #:impl (negate =) #:cost 256]\n  [<.f64  #:spec (< x y)  #:impl <          #:cost 256]\n  [>.f64  #:spec (> x y)  #:impl >          #:cost 256]\n  [<=.f64 #:spec (<= x y) #:impl <=         #:cost 256]\n  [>=.f64 #:spec (>= x y) #:impl >=         #:cost 256])\n\n(define-operations () <binary64> #:fpcore (! :precision binary64 _)\n  [PI.f64   #:spec (PI)       #:impl (const pi)      #:fpcore PI       #:cost 64]\n  [E.f64    #:spec (E)        #:impl (const (exp 1)) #:fpcore E        #:cost 64]\n  [INFINITY #:spec (INFINITY) #:impl (const +inf.0)  #:fpcore INFINITY #:cost 64]\n  [NAN.f64  #:spec (NAN)      #:impl (const +nan.0)  #:fpcore NAN      #:cost 64])\n\n(define-operation (neg.f64 [x <binary64>]) <binary64>\n  #:spec (neg x) #:impl -\n  #:fpcore (! :precision binary64 (- x)) #:cost 128)\n\n(define-operations ([x <binary64>] [y <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [+.f64 #:spec (+ x y) #:impl + #:cost 128]\n  [-.f64 #:spec (- x y) #:impl - #:cost 128]\n  [*.f64 #:spec (* x y) #:impl * #:cost 256]\n  [/.f64 #:spec (/ x y) #:impl / #:cost 640])\n\n(define-operations ([x <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [fabs.f64   #:spec (fabs x)   #:impl (from-libm 'fabs)      #:cost 128]\n  [sin.f64    #:spec (sin x)    #:impl (from-libm 'sin)       #:cost 6400]\n  [cos.f64    #:spec (cos x)    #:impl (from-libm 'cos)       #:cost 6400]\n  [tan.f64    #:spec (tan x)    #:impl (from-libm 'tan)       #:cost 6400]\n  [sinh.f64   #:spec (sinh x)   #:impl (from-libm 'sinh)      #:cost 6400]\n  [cosh.f64   #:spec (cosh x)   #:impl (from-libm 'cosh)      #:cost 6400]\n  [acos.f64   #:spec (acos x)   #:impl (from-libm 'acos)      #:cost 6400]\n  [acosh.f64  #:spec (acosh x)  #:impl (from-libm 'acosh)     #:cost 6400]\n  [asin.f64   #:spec (asin x)   #:impl (from-libm 'asin)      #:cost 6400]\n  [asinh.f64  #:spec (asinh x)  #:impl (from-libm 'asinh)     #:cost 6400]\n  [atan.f64   #:spec (atan x)   #:impl (from-libm 'atan)      #:cost 6400]\n  [atanh.f64  #:spec (atanh x)  #:impl (from-libm 'atanh)     #:cost 6400]\n  [cbrt.f64   #:spec (cbrt x)   #:impl (from-libm 'cbrt)      #:cost 6400]\n  [ceil.f64   #:spec (ceil x)   #:impl (from-libm 'ceil)      #:cost 6400]\n  [erf.f64    #:spec (erf x)    #:impl (from-libm 'erf)       #:cost 6400]\n  [exp.f64    #:spec (exp x)    #:impl (from-libm 'exp)       #:cost 6400]\n  [exp2.f64   #:spec (exp2 x)   #:impl (from-libm 'exp2)      #:cost 6400]\n  [floor.f64  #:spec (floor x)  #:impl (from-libm 'floor)     #:cost 6400]\n  [lgamma.f64 #:spec (lgamma x) #:impl (from-libm 'lgamma)    #:cost 6400]\n  [log.f64    #:spec (log x)    #:impl (from-libm 'log)       #:cost 6400]\n  [log10.f64  #:spec (log10 x)  #:impl (from-libm 'log10)     #:cost 6400]\n  [log2.f64   #:spec (log2 x)   #:impl (from-libm 'log2)      #:cost 6400]\n  [logb.f64   #:spec (logb x)   #:impl (from-libm 'logb)      #:cost 6400]\n  [rint.f64   #:spec (rint x)   #:impl (from-libm 'rint)      #:cost 6400]\n  [round.f64  #:spec (round x)  #:impl (from-libm 'round)     #:cost 6400]\n  [sqrt.f64   #:spec (sqrt x)   #:impl (from-libm 'sqrt)      #:cost 640]\n  [tanh.f64   #:spec (tanh x)   #:impl (from-libm 'tanh)      #:cost 6400]\n  [tgamma.f64 #:spec (tgamma x) #:impl (from-libm 'tgamma)    #:cost 6400]\n  [trunc.f64  #:spec (trunc x)  #:impl (from-libm 'trunc)     #:cost 6400])\n\n(define-operations ([x <binary64>] [y <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [pow.f64       #:spec (pow x y)       #:impl (from-libm 'pow)       #:cost 6400]\n  [atan2.f64     #:spec (atan2 x y)     #:impl (from-libm 'atan2)     #:cost 6400]\n  [copysign.f64  #:spec (copysign x y)  #:impl (from-libm 'copysign)  #:cost 6400]\n  [fdim.f64      #:spec (fdim x y)      #:impl (from-libm 'fdim)      #:cost 6400]\n  [fmax.f64      #:spec (fmax x y)      #:impl (from-libm 'fmax)      #:cost 6400]\n  [fmin.f64      #:spec (fmin x y)      #:impl (from-libm 'fmin)      #:cost 6400]\n  [fmod.f64      #:spec (fmod x y)      #:impl (from-libm 'fmod)      #:cost 6400]\n  [remainder.f64 #:spec (remainder x y) #:impl (from-libm 'remainder) #:cost 6400])\n\n(define-operations ([x <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [erfc.f64  #:spec (- 1 (erf x)) #:impl (from-libm 'erfc)  #:fpcore (erfc x)  #:cost 6400]\n  [expm1.f64 #:spec (- (exp x) 1) #:impl (from-libm 'expm1) #:fpcore (expm1 x) #:cost 6400]\n  [log1p.f64 #:spec (log (+ 1 x)) #:impl (from-libm 'log1p) #:fpcore (log1p x) #:cost 6400])\n\n(define-operation (hypot.f64 [x <binary64>] [y <binary64>]) <binary64>\n  #:spec (sqrt (+ (* x x) (* y y))) #:impl (from-libm 'hypot)\n  #:fpcore (! :precision binary64 (hypot x y)) #:cost 6400)\n\n(define-operation (fma.f64 [x <binary64>] [y <binary64>] [z <binary64>]) <binary64>\n  #:spec (+ (* x y) z) #:impl (from-libm 'fma)\n  #:fpcore (! :precision binary64 (fma x y z)) #:cost 256)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CASTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-operation (binary64->binary32 [x <binary64>]) <binary32>\n  #:spec x #:fpcore (! :precision binary32 (cast x)) #:impl flsingle #:cost 64)\n\n(define-operation (binary32->binary64 [x <binary32>]) <binary64>\n  #:spec x #:fpcore (! :precision binary64 (cast x)) #:impl identity #:cost 64)\n"
  },
  {
    "path": "src/platforms/julia.rkt",
    "content": "#lang s-exp \"../syntax/platform-language.rkt\"\n\n;; Julia platform\n\n(require math/flonum)\n\n(define 64bit-move-cost   1.000)\n(define 32bit-move-cost   1.000)\n(define boolean-move-cost 0.100)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BOOLEAN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <bool> #:cost boolean-move-cost)\n\n(define-operations () <bool>\n    [TRUE   #:spec (TRUE)   #:impl (const true)   #:fpcore TRUE   #:cost boolean-move-cost]\n    [FALSE  #:spec (FALSE)  #:impl (const false)  #:fpcore FALSE  #:cost boolean-move-cost])\n\n(define-operations ([x <bool>] [y <bool>]) <bool>\n    [and    #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost boolean-move-cost]\n    [or     #:spec (or x y)  #:impl (lambda v (ormap values v))  #:cost boolean-move-cost])\n\n(define-operation (not [x <bool>]) <bool>\n    #:spec (not x) #:impl not #:cost boolean-move-cost)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <binary32> #:cost 32bit-move-cost)\n\n(define-operation (if.f32 [c <bool>] [t <binary32>] [f <binary32>]) <binary32>\n    #:spec (if c t f) #:impl if-impl\n    #:cost (if-cost boolean-move-cost))\n\n(define-operation (neg.f32 [x <binary32>]) <binary32>\n    #:spec (neg x) #:impl (compose flsingle -) #:fpcore (! :precision binary32 (- x)) #:cost 1.0)\n\n;; Comparison operations\n(define-operations ([x <binary32>] [y <binary32>]) <bool>\n    [==.f32  #:spec (== x y)  #:impl =          #:cost boolean-move-cost]\n    [!=.f32  #:spec (!= x y)  #:impl (negate =) #:cost boolean-move-cost]\n    [<.f32   #:spec (< x y)   #:impl <          #:cost boolean-move-cost]\n    [>.f32   #:spec (> x y)   #:impl >          #:cost boolean-move-cost]\n    [<=.f32  #:spec (<= x y)  #:impl <=         #:cost boolean-move-cost]\n    [>=.f32  #:spec (>= x y)  #:impl >=         #:cost boolean-move-cost])\n\n;; Constants\n(define-operations () <binary32> #:fpcore (! :precision binary32 _)\n    [PI.f32       #:spec (PI)        #:impl (const (flsingle pi))       #:fpcore PI        #:cost 32bit-move-cost]\n    [E.f32        #:spec (E)         #:impl (const (flsingle (exp 1)))  #:fpcore E         #:cost 32bit-move-cost]\n    [INFINITY.f32 #:spec (INFINITY)  #:impl (const +inf.0)              #:fpcore INFINITY  #:cost 32bit-move-cost]\n    [NAN.f32      #:spec (NAN)       #:impl (const +nan.0)              #:fpcore NAN       #:cost 32bit-move-cost])\n\n;; Binary operations\n(define-operations ([x <binary32>] [y <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n    [+.f32         #:spec (+ x y)                    #:impl (compose flsingle +)       #:cost 1.0]\n    [-.f32         #:spec (- x y)                    #:impl (compose flsingle -)       #:cost 1.0]\n    [*.f32         #:spec (* x y)                    #:impl (compose flsingle *)       #:cost 1.0]\n    [/.f32         #:spec (/ x y)                    #:impl (compose flsingle /)       #:cost 1.0]\n    [fmax.f32      #:spec (fmax x y)                 #:impl (from-libm 'fmaxf)         #:cost 1.0]\n    [fmin.f32      #:spec (fmin x y)                 #:impl (from-libm 'fminf)         #:cost 1.0]\n    [hypot.f32     #:spec (sqrt (+ (* x x) (* y y))) #:impl (from-libm 'hypotf)        #:cost 4.0  #:fpcore (hypot x y)]\n    [pow.f32       #:spec (pow x y)                  #:impl (from-libm 'powf)          #:cost 15.5]\n    [copysign.f32  #:spec (copysign x y)             #:impl (from-libm 'copysignf)     #:cost 1.0])\n\n;; Unary operations\n(define-operations ([x <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n    [fabs.f32    #:spec (fabs x)                           #:impl (from-libm 'fabsf)  #:cost 1.0]\n    [sqrt.f32    #:spec (sqrt x)                           #:impl (from-libm 'sqrtf)  #:cost 1.0]\n    [exp.f32     #:spec (exp x)                            #:impl (from-libm 'expf)   #:cost 3.5]\n    [exp2.f32    #:spec (exp2 x)                           #:impl (from-libm 'exp2f)  #:cost 3.5]\n    [exp10.f32   #:spec (pow 10 x)                         #:impl (from-rival)        #:cost 3.5]\n    [log.f32     #:spec (log x)                            #:impl (from-libm 'logf)   #:cost 4.5]\n    [log10.f32   #:spec (log10 x)                          #:impl (from-libm 'log10f) #:cost 5.0]\n    [log2.f32    #:spec (log2 x)                           #:impl (from-libm 'log2f)  #:cost 5.5]\n    [sin.f32     #:spec (sin x)                            #:impl (from-libm 'sinf)   #:cost 3.5]\n    [cos.f32     #:spec (cos x)                            #:impl (from-libm 'cosf)   #:cost 4.0]\n    [tan.f32     #:spec (tan x)                            #:impl (from-libm 'tanf)   #:cost 6.0]\n    [sinh.f32    #:spec (sinh x)                           #:impl (from-libm 'sinhf)  #:cost 4.5]\n    [cosh.f32    #:spec (cosh x)                           #:impl (from-libm 'coshf)  #:cost 4.5]\n    [tanh.f32    #:spec (tanh x)                           #:impl (from-libm 'tanhf)  #:cost 5.0]\n    [asin.f32    #:spec (asin x)                           #:impl (from-libm 'asinf)  #:cost 4.0]\n    [acos.f32    #:spec (acos x)                           #:impl (from-libm 'acosf)  #:cost 4.0]\n    [atan.f32    #:spec (atan x)                           #:impl (from-libm 'atanf)  #:cost 6.0]\n    [atanh.f32   #:spec (atanh x)                          #:impl (from-libm 'atanhf) #:cost 6.5]\n    [asinh.f32   #:spec (asinh x)                          #:impl (from-libm 'asinhf) #:cost 9.5]\n    [acosh.f32   #:spec (acosh x)                          #:impl (from-libm 'acoshf) #:cost 7.5]\n    [cbrt.f32    #:spec (cbrt x)                           #:impl (from-libm 'cbrtf)  #:cost 4.5]\n    [log1p.f32   #:spec (log (+ 1 x))                      #:impl (from-libm 'log1pf) #:cost 5.5    #:fpcore (log1p x)]\n    [expm1.f32   #:spec (- (exp x) 1)                      #:impl (from-libm 'expm1f) #:cost 5.5    #:fpcore (expm1 x)]\n    [deg2rad.f32 #:spec (* x (/ (PI) 180))                 #:impl (from-rival)        #:cost 1.0    #:fpcore (deg2rad x)]\n    [rad2deg.f32 #:spec (* x (/ 180 (PI)))                 #:impl (from-rival)        #:cost 1.0    #:fpcore (rad2deg x)]\n    [abs2.f32    #:spec (* (fabs x) (fabs x))              #:impl (from-rival)        #:cost 1.0    #:fpcore (abs2 x)]\n    [sec.f32     #:spec (/ 1 (cos x))                      #:impl (from-rival)        #:cost 4.0    #:fpcore (sec x)]\n    [csc.f32     #:spec (/ 1 (sin x))                      #:impl (from-rival)        #:cost 3.5    #:fpcore (csc x)]\n    [cot.f32     #:spec (/ 1 (tan x))                      #:impl (from-rival)        #:cost 7.5    #:fpcore (cot x)]\n    [sech.f32    #:spec (/ 1 (cosh x))                     #:impl (from-rival)        #:cost 8.0    #:fpcore (sech x)]\n    [csch.f32    #:spec (/ 1 (sinh x))                     #:impl (from-rival)        #:cost 5.0    #:fpcore (csch x)]\n    [coth.f32    #:spec (/ (cosh x) (sinh x))              #:impl (from-rival)        #:cost 8.0    #:fpcore (coth x)]\n    [asec.f32    #:spec (acos (/ 1 x))                     #:impl (from-rival)        #:cost 4.5    #:fpcore (asec x)]\n    [acsc.f32    #:spec (asin (/ 1 x))                     #:impl (from-rival)        #:cost 6.5    #:fpcore (acsc x)]\n    [acot.f32    #:spec (atan (/ 1 x))                     #:impl (from-rival)        #:cost 7.5    #:fpcore (acot x)]\n    [asech.f32   #:spec (acosh (/ 1 x))                    #:impl (from-rival)        #:cost 8.5    #:fpcore (asech x)]\n    [acsch.f32   #:spec (asinh (/ 1 x))                    #:impl (from-rival)        #:cost 10.0   #:fpcore (acsch x)]\n    [acoth.f32   #:spec (atanh (/ 1 x))                    #:impl (from-rival)        #:cost 7.0    #:fpcore (acoth x)]\n    [sind.f32    #:spec (sin (* x (/ (PI) 180)))           #:impl (from-rival)        #:cost 6.0    #:fpcore (sind x)]\n    [cosd.f32    #:spec (cos (* x (/ (PI) 180)))           #:impl (from-rival)        #:cost 6.5    #:fpcore (cosd x)]\n    [tand.f32    #:spec (tan (* x (/ (PI) 180)))           #:impl (from-rival)        #:cost 13.0   #:fpcore (tand x)]\n    [cotd.f32    #:spec (/ 1 (tan (* x (/ (PI) 180))))     #:impl (from-rival)        #:cost 14.0   #:fpcore (cotd x)]\n    [asind.f32   #:spec (* (asin x) (/ 180 (PI)))          #:impl (from-rival)        #:cost 4.5    #:fpcore (asind x)]\n    [acosd.f32   #:spec (* (acos x) (/ 180 (PI)))          #:impl (from-rival)        #:cost 4.0    #:fpcore (acosd x)]\n    [atand.f32   #:spec (* (atan x) (/ 180 (PI)))          #:impl (from-rival)        #:cost 6.0    #:fpcore (atand x)]\n    [acotd.f32   #:spec (* (atan (/ 1 x)) (/ 180 (PI)))    #:impl (from-rival)        #:cost 8.0    #:fpcore (acotd x)]\n    [asecd.f32   #:spec (* (acos (/ 1 x)) (/ 180 (PI)))    #:impl (from-rival)        #:cost 5.0    #:fpcore (asecd x)]\n    [acscd.f32   #:spec (* (asin (/ 1 x)) (/ 180 (PI)))    #:impl (from-rival)        #:cost 6.5    #:fpcore (acscd x)]\n    [secd.f32    #:spec (/ 1 (cos (* x (/ (PI) 180))))     #:impl (from-rival)        #:cost 8.0    #:fpcore (secd x)]\n    [cscd.f32    #:spec (/ 1 (sin (* x (/ (PI) 180))))     #:impl (from-rival)        #:cost 6.5    #:fpcore (cscd x)]\n    [sinpi.f32   #:spec (sin (* (* x (PI)) (/ (PI) 180)))  #:impl (from-rival)        #:cost 5.0    #:fpcore (sinpi x)]\n    [cospi.f32   #:spec (cos (* (* x (PI)) (/ (PI) 180)))  #:impl (from-rival)        #:cost 5.0    #:fpcore (cospi x)])\n\n;; Ternary fused multiply-add operation\n(define-operation (fma.f32 [x <binary32>] [y <binary32>] [z <binary32>]) <binary32>\n    #:spec (+ (* x y) z) #:impl (from-libm 'fmaf)\n    #:fpcore (! :precision binary32 (fma x y z)) #:cost 1.0)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <binary64> #:cost 64bit-move-cost)\n\n(define-operation (if.f64 [c <bool>] [t <binary64>] [f <binary64>]) <binary64>\n    #:spec (if c t f) #:impl if-impl\n    #:cost (if-cost boolean-move-cost))\n\n(define-operation (neg.f64 [x <binary64>]) <binary64>\n    #:spec (neg x) #:impl - #:fpcore (! :precision binary64 (- x)) #:cost 1.0)\n\n;; Comparison operations\n(define-operations ([x <binary64>] [y <binary64>]) <bool>\n    [==.f64  #:spec (== x y)  #:impl =          #:cost boolean-move-cost]\n    [!=.f64  #:spec (!= x y)  #:impl (negate =) #:cost boolean-move-cost]\n    [<.f64   #:spec (< x y)   #:impl <          #:cost boolean-move-cost]\n    [>.f64   #:spec (> x y)   #:impl >          #:cost boolean-move-cost]\n    [<=.f64  #:spec (<= x y)  #:impl <=         #:cost boolean-move-cost]\n    [>=.f64  #:spec (>= x y)  #:impl >=         #:cost boolean-move-cost])\n\n;; Constants\n(define-operations () <binary64> #:fpcore (! :precision binary64 _)\n    [PI.f64    #:spec (PI)        #:impl (const pi)        #:fpcore PI        #:cost 64bit-move-cost]\n    [E.f64     #:spec (E)         #:impl (const (exp 1))   #:fpcore E         #:cost 64bit-move-cost]\n    [INFINITY  #:spec (INFINITY)  #:impl (const +inf.0)    #:fpcore INFINITY  #:cost 64bit-move-cost]\n    [NAN.f64   #:spec (NAN)       #:impl (const +nan.0)    #:fpcore NAN       #:cost 64bit-move-cost])\n\n;; Binary operations\n(define-operations ([x <binary64>] [y <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n    [+.f64         #:spec (+ x y)                    #:impl +                      #:cost 1.0]\n    [-.f64         #:spec (- x y)                    #:impl -                      #:cost 1.0]\n    [*.f64         #:spec (* x y)                    #:impl *                      #:cost 1.0]\n    [/.f64         #:spec (/ x y)                    #:impl /                      #:cost 1.0]\n    [fmax.f64      #:spec (fmax x y)                 #:impl (from-libm 'fmax)      #:cost 1.0]\n    [fmin.f64      #:spec (fmin x y)                 #:impl (from-libm 'fmin)      #:cost 1.0]\n    [hypot.f64     #:spec (sqrt (+ (* x x) (* y y))) #:impl (from-libm 'hypot)     #:cost 4.0  #:fpcore (hypot x y)]\n    [pow.f64       #:spec (pow x y)                  #:impl (from-libm 'pow)       #:cost 15.5]\n    [copysign.f64  #:spec (copysign x y)             #:impl (from-libm 'copysign)  #:cost 1.0])\n\n;; Unary operations\n(define-operations ([x <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n    [fabs.f64    #:spec (fabs x)                           #:impl (from-libm 'fabs)   #:cost 1.0]\n    [sqrt.f64    #:spec (sqrt x)                           #:impl (from-libm 'sqrt)   #:cost 1.0]\n    [exp.f64     #:spec (exp x)                            #:impl (from-libm 'exp)    #:cost 3.5]\n    [exp2.f64    #:spec (exp2 x)                           #:impl (from-libm 'exp2)   #:cost 3.5]\n    [exp10.f64   #:spec (pow 10 x)                         #:impl (from-rival)        #:cost 3.5]\n    [log.f64     #:spec (log x)                            #:impl (from-libm 'log)    #:cost 4.5]\n    [log10.f64   #:spec (log10 x)                          #:impl (from-libm 'log10)  #:cost 5.0]\n    [log2.f64    #:spec (log2 x)                           #:impl (from-libm 'log2)   #:cost 5.5]\n    [sin.f64     #:spec (sin x)                            #:impl (from-libm 'sin)    #:cost 3.5]\n    [cos.f64     #:spec (cos x)                            #:impl (from-libm 'cos)    #:cost 4.0]\n    [tan.f64     #:spec (tan x)                            #:impl (from-libm 'tan)    #:cost 6.0]\n    [sinh.f64    #:spec (sinh x)                           #:impl (from-libm 'sinh)   #:cost 4.5]\n    [cosh.f64    #:spec (cosh x)                           #:impl (from-libm 'cosh)   #:cost 4.5]\n    [tanh.f64    #:spec (tanh x)                           #:impl (from-libm 'tanh)   #:cost 5.0]\n    [asin.f64    #:spec (asin x)                           #:impl (from-libm 'asin)   #:cost 4.0]\n    [acos.f64    #:spec (acos x)                           #:impl (from-libm 'acos)   #:cost 4.0]\n    [atan.f64    #:spec (atan x)                           #:impl (from-libm 'atan)   #:cost 6.0]\n    [atanh.f64   #:spec (atanh x)                          #:impl (from-libm 'atanh)  #:cost 6.5]\n    [asinh.f64   #:spec (asinh x)                          #:impl (from-libm 'asinh)  #:cost 9.5]\n    [acosh.f64   #:spec (acosh x)                          #:impl (from-libm 'acosh)  #:cost 7.5]\n    [cbrt.f64    #:spec (cbrt x)                           #:impl (from-libm 'cbrt)   #:cost 4.5]\n    [log1p.f64   #:spec (log (+ 1 x))                      #:impl (from-libm 'log1p)  #:cost 5.5    #:fpcore (log1p x)]\n    [expm1.f64   #:spec (- (exp x) 1)                      #:impl (from-libm 'expm1)  #:cost 5.5    #:fpcore (expm1 x)]\n    [deg2rad.f64 #:spec (* x (/ (PI) 180))                 #:impl (from-rival)        #:cost 1.0    #:fpcore (deg2rad x)]\n    [rad2deg.f64 #:spec (* x (/ 180 (PI)))                 #:impl (from-rival)        #:cost 1.0    #:fpcore (rad2deg x)]\n    [abs2.f64    #:spec (* (fabs x) (fabs x))              #:impl (from-rival)        #:cost 1.0    #:fpcore (abs2 x)]\n    [sec.f64     #:spec (/ 1 (cos x))                      #:impl (from-rival)        #:cost 4.0    #:fpcore (sec x)]\n    [csc.f64     #:spec (/ 1 (sin x))                      #:impl (from-rival)        #:cost 3.5    #:fpcore (csc x)]\n    [cot.f64     #:spec (/ 1 (tan x))                      #:impl (from-rival)        #:cost 7.5    #:fpcore (cot x)]\n    [sech.f64    #:spec (/ 1 (cosh x))                     #:impl (from-rival)        #:cost 8.0    #:fpcore (sech x)]\n    [csch.f64    #:spec (/ 1 (sinh x))                     #:impl (from-rival)        #:cost 5.0    #:fpcore (csch x)]\n    [coth.f64    #:spec (/ (cosh x) (sinh x))              #:impl (from-rival)        #:cost 8.0    #:fpcore (coth x)]\n    [asec.f64    #:spec (acos (/ 1 x))                     #:impl (from-rival)        #:cost 4.5    #:fpcore (asec x)]\n    [acsc.f64    #:spec (asin (/ 1 x))                     #:impl (from-rival)        #:cost 6.5    #:fpcore (acsc x)]\n    [acot.f64    #:spec (atan (/ 1 x))                     #:impl (from-rival)        #:cost 7.5    #:fpcore (acot x)]\n    [asech.f64   #:spec (acosh (/ 1 x))                    #:impl (from-rival)        #:cost 8.5    #:fpcore (asech x)]\n    [acsch.f64   #:spec (asinh (/ 1 x))                    #:impl (from-rival)        #:cost 10.0   #:fpcore (acsch x)]\n    [acoth.f64   #:spec (atanh (/ 1 x))                    #:impl (from-rival)        #:cost 7.0    #:fpcore (acoth x)]\n    [sind.f64    #:spec (sin (* x (/ (PI) 180)))           #:impl (from-rival)        #:cost 6.0    #:fpcore (sind x)]\n    [cosd.f64    #:spec (cos (* x (/ (PI) 180)))           #:impl (from-rival)        #:cost 6.5    #:fpcore (cosd x)]\n    [tand.f64    #:spec (tan (* x (/ (PI) 180)))           #:impl (from-rival)        #:cost 13.0   #:fpcore (tand x)]\n    [cotd.f64    #:spec (/ 1 (tan (* x (/ (PI) 180))))     #:impl (from-rival)        #:cost 14.0   #:fpcore (cotd x)]\n    [asind.f64   #:spec (* (asin x) (/ 180 (PI)))          #:impl (from-rival)        #:cost 4.5    #:fpcore (asind x)]\n    [acosd.f64   #:spec (* (acos x) (/ 180 (PI)))          #:impl (from-rival)        #:cost 4.0    #:fpcore (acosd x)]\n    [atand.f64   #:spec (* (atan x) (/ 180 (PI)))          #:impl (from-rival)        #:cost 6.0    #:fpcore (atand x)]\n    [acotd.f64   #:spec (* (atan (/ 1 x)) (/ 180 (PI)))    #:impl (from-rival)        #:cost 8.0    #:fpcore (acotd x)]\n    [asecd.f64   #:spec (* (acos (/ 1 x)) (/ 180 (PI)))    #:impl (from-rival)        #:cost 5.0    #:fpcore (asecd x)]\n    [acscd.f64   #:spec (* (asin (/ 1 x)) (/ 180 (PI)))    #:impl (from-rival)        #:cost 6.5    #:fpcore (acscd x)]\n    [secd.f64    #:spec (/ 1 (cos (* x (/ (PI) 180))))     #:impl (from-rival)        #:cost 8.0    #:fpcore (secd x)]\n    [cscd.f64    #:spec (/ 1 (sin (* x (/ (PI) 180))))     #:impl (from-rival)        #:cost 6.5    #:fpcore (cscd x)]\n    [sinpi.f64   #:spec (sin (* (* x (PI)) (/ (PI) 180)))  #:impl (from-rival)        #:cost 5.0    #:fpcore (sinpi x)]\n    [cospi.f64   #:spec (cos (* (* x (PI)) (/ (PI) 180)))  #:impl (from-rival)        #:cost 5.0    #:fpcore (cospi x)])\n\n;; Ternary fused multiply-add operation\n(define-operation (fma.f64 [x <binary64>] [y <binary64>] [z <binary64>]) <binary64>\n    #:spec (+ (* x y) z) #:impl (from-libm 'fma)\n    #:fpcore (! :precision binary64 (fma x y z)) #:cost 1.0)\n"
  },
  {
    "path": "src/platforms/math.rkt",
    "content": "#lang s-exp \"../syntax/platform-language.rkt\"\n\n;;; C/C++ on Linux with reduced libm, meaning no special numeric\n;;; functions. It is also 64-bit only.\n\n(define move-cost    0.02333600000000001)\n(define fl-move-cost (* move-cost 4))\n\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BOOLEAN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <bool> #:cost move-cost)\n\n(define-operations () <bool>\n  [TRUE  #:spec (TRUE)  #:impl (const true)  #:fpcore TRUE  #:cost move-cost]\n  [FALSE #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost move-cost])\n\n(define-operations ([x <bool>] [y <bool>]) <bool>\n  [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost move-cost]\n  [or  #:spec (or x y)  #:impl (lambda v (ormap values v))  #:cost move-cost])\n\n(define-operation (not [x <bool>]) <bool>\n  #:spec (not x) #:impl not #:cost move-cost)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <binary64> #:cost fl-move-cost)\n\n(define-operation (if.f64 [c <bool>] [t <binary64>] [f <binary64>]) <binary64>\n  #:spec (if c t f) #:impl if-impl\n  #:cost (if-cost move-cost))\n\n(define-operations ([x <binary64>] [y <binary64>]) <bool>\n  [==.f64 #:spec (== x y) #:impl =          #:cost fl-move-cost]\n  [!=.f64 #:spec (!= x y) #:impl (negate =) #:cost fl-move-cost]\n  [<.f64  #:spec (< x y)  #:impl <          #:cost fl-move-cost]\n  [>.f64  #:spec (> x y)  #:impl >          #:cost fl-move-cost]\n  [<=.f64 #:spec (<= x y) #:impl <=         #:cost fl-move-cost]\n  [>=.f64 #:spec (>= x y) #:impl >=         #:cost fl-move-cost])\n\n(define-operations () <binary64> #:fpcore (! :precision binary64 _)\n  [PI.f64   #:spec (PI)       #:impl (const pi)      #:fpcore PI       #:cost fl-move-cost]\n  [E.f64    #:spec (E)        #:impl (const (exp 1)) #:fpcore E        #:cost fl-move-cost]\n  [INFINITY #:spec (INFINITY) #:impl (const +inf.0)  #:fpcore INFINITY #:cost fl-move-cost]\n  [NAN.f64  #:spec (NAN)      #:impl (const +nan.0)  #:fpcore NAN      #:cost fl-move-cost])\n\n(define-operation (neg.f64 [x <binary64>]) <binary64>\n  #:spec (neg x) #:impl -\n  #:fpcore (! :precision binary64 (- x)) #:cost 0.096592)\n\n(define-operations ([x <binary64>] [y <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [+.f64 #:spec (+ x y) #:impl + #:cost 0.164604]\n  [-.f64 #:spec (- x y) #:impl - #:cost 0.15163999999999997]\n  [*.f64 #:spec (* x y) #:impl * #:cost 0.20874800000000002]\n  [/.f64 #:spec (/ x y) #:impl / #:cost 0.26615199999999994])\n\n(define-operations ([x <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [fabs.f64   #:spec (fabs x)   #:impl (from-libm 'fabs)      #:cost 0.10162]\n  [sin.f64    #:spec (sin x)    #:impl (from-libm 'sin)       #:cost 3.318128]\n  [cos.f64    #:spec (cos x)    #:impl (from-libm 'cos)       #:cost 3.32288]\n  [tan.f64    #:spec (tan x)    #:impl (from-libm 'tan)       #:cost 3.710904]\n  [sinh.f64   #:spec (sinh x)   #:impl (from-libm 'sinh)      #:cost 1.20954]\n  [cosh.f64   #:spec (cosh x)   #:impl (from-libm 'cosh)      #:cost 0.953896]\n  [acos.f64   #:spec (acos x)   #:impl (from-libm 'acos)      #:cost 0.357748]\n  [acosh.f64  #:spec (acosh x)  #:impl (from-libm 'acosh)     #:cost 0.659472]\n  [asin.f64   #:spec (asin x)   #:impl (from-libm 'asin)      #:cost 0.389788]\n  [asinh.f64  #:spec (asinh x)  #:impl (from-libm 'asinh)     #:cost 0.835028]\n  [atan.f64   #:spec (atan x)   #:impl (from-libm 'atan)      #:cost 0.83752]\n  [atanh.f64  #:spec (atanh x)  #:impl (from-libm 'atanh)     #:cost 0.36238]\n  [cbrt.f64   #:spec (cbrt x)   #:impl (from-libm 'cbrt)      #:cost 1.565176]\n  [ceil.f64   #:spec (ceil x)   #:impl (from-libm 'ceil)      #:cost 0.47299]\n  [erf.f64    #:spec (erf x)    #:impl (from-libm 'erf)       #:cost 0.806436]\n  [exp.f64    #:spec (exp x)    #:impl (from-libm 'exp)       #:cost 1.0806]\n  [exp2.f64   #:spec (exp2 x)   #:impl (from-libm 'exp2)      #:cost 0.825484]\n  [floor.f64  #:spec (floor x)  #:impl (from-libm 'floor)     #:cost 0.468568]\n  [lgamma.f64 #:spec (lgamma x) #:impl (from-libm 'lgamma)    #:cost 1.568012]\n  [log.f64    #:spec (log x)    #:impl (from-libm 'log)       #:cost 0.505724]\n  [log10.f64  #:spec (log10 x)  #:impl (from-libm 'log10)     #:cost 0.868856]\n  [log2.f64   #:spec (log2 x)   #:impl (from-libm 'log2)      #:cost 0.681276]\n  [logb.f64   #:spec (logb x)   #:impl (from-libm 'logb)      #:cost 0.220656]\n  [rint.f64   #:spec (rint x)   #:impl (from-libm 'rint)      #:cost 0.121864]\n  [round.f64  #:spec (round x)  #:impl (from-libm 'round)     #:cost 0.658564]\n  [sqrt.f64   #:spec (sqrt x)   #:impl (from-libm 'sqrt)      #:cost 0.191872]\n  [tanh.f64   #:spec (tanh x)   #:impl (from-libm 'tanh)      #:cost 0.824016]\n  [tgamma.f64 #:spec (tgamma x) #:impl (from-libm 'tgamma)    #:cost 1.882576]\n  [trunc.f64  #:spec (trunc x)  #:impl (from-libm 'trunc)     #:cost 0.463644])\n\n(define-operations ([x <binary64>] [y <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [pow.f64       #:spec (pow x y)       #:impl (from-libm 'pow)       #:cost 1.52482]\n  [atan2.f64     #:spec (atan2 x y)     #:impl (from-libm 'atan2)     #:cost 1.492804]\n  [copysign.f64  #:spec (copysign x y)  #:impl (from-libm 'copysign)  #:cost 0.200452]\n  [fdim.f64      #:spec (fdim x y)      #:impl (from-libm 'fdim)      #:cost 0.592576]\n  [fmax.f64      #:spec (fmax x y)      #:impl (from-libm 'fmax)      #:cost 0.3106]\n  [fmin.f64      #:spec (fmin x y)      #:impl (from-libm 'fmin)      #:cost 0.289256]\n  [fmod.f64      #:spec (fmod x y)      #:impl (from-libm 'fmod)      #:cost 94.277144]\n  [remainder.f64 #:spec (remainder x y) #:impl (from-libm 'remainder) #:cost 16.165012])\n\n(define-operation (erfc.f64 [x <binary64>]) <binary64>\n  #:spec (- 1 (erf x)) #:impl (from-libm 'erfc)\n  #:fpcore (! :precision binary64 (erfc x)) #:cost 0.816512)\n"
  },
  {
    "path": "src/platforms/python.rkt",
    "content": "#lang s-exp \"../syntax/platform-language.rkt\"\n\n(require math/flonum)\n\n(define 64bit-move-cost   0.125)\n(define boolean-move-cost 0.100)\n\n(define-representation <bool> #:cost boolean-move-cost)\n(define-representation <binary64> #:cost 64bit-move-cost)\n\n(define-operations () <bool>\n  [true  #:spec (TRUE)  #:impl (const true)  #:fpcore TRUE  #:cost boolean-move-cost]\n  [false #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost boolean-move-cost])\n\n(define-operations ([x <bool>] [y <bool>]) <bool>\n  [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost boolean-move-cost]\n  [or  #:spec (or x y)  #:impl (lambda v (ormap values v))  #:cost boolean-move-cost])\n\n(define-operation (not [x <bool>]) <bool>\n  #:spec (not x) #:impl not #:cost boolean-move-cost)\n\n(define-operation (if.py [c <bool>] [t <binary64>] [f <binary64>]) <binary64>\n  #:spec (if c t f) #:impl if-impl\n  #:cost (if-cost boolean-move-cost))\n\n\n\n(define-operations ([x <binary64>] [y <binary64>]) <bool>\n  [== #:spec (== x y) #:impl =          #:cost 64bit-move-cost]\n  [!= #:spec (!= x y) #:impl (negate =) #:cost 64bit-move-cost]\n  [<  #:spec (< x y)  #:impl <          #:cost 64bit-move-cost]\n  [>  #:spec (> x y)  #:impl >          #:cost 64bit-move-cost]\n  [<= #:spec (<= x y) #:impl <=         #:cost 64bit-move-cost]\n  [>= #:spec (>= x y) #:impl >=         #:cost 64bit-move-cost])\n\n(define-operations () <binary64>\n  [pi    #:spec (PI)   #:impl (const (flsingle pi))       #:fpcore PI       #:cost 64bit-move-cost]\n  [e     #:spec (E)    #:impl (const (flsingle (exp 1)))  #:fpcore E        #:cost 64bit-move-cost]\n  [inf   #:spec (INFINITY)  #:impl (const +inf.0)         #:fpcore INFINITY #:cost 64bit-move-cost]\n  [nan   #:spec (NAN)  #:impl (const +nan.0)              #:fpcore NAN      #:cost 64bit-move-cost]\n  [tau   #:spec (* 2 (PI))  #:impl (const(* 2 pi))        #:fpcore (* 2 PI) #:cost 64bit-move-cost])\n\n(define-operations ([x <binary64>] [y <binary64>]) <binary64>\n  [+.py #:spec (+ x y) #:impl (compose flsingle +) #:cost 0.200]\n  [-.py #:spec (- x y) #:impl (compose flsingle -) #:cost 0.200]\n  [*.py #:spec (* x y) #:impl (compose flsingle *) #:cost 0.250]\n  [/.py #:spec (/ x y) #:impl (compose flsingle /) #:cost 0.350])\n\n(define-operations ([x <binary64>]) <binary64>\n  [degrees.py  #:spec (* x (/ (PI) 180.0)) #:impl radians->degrees #:fpcore (degrees x) #:cost 1]\n  [radians.py  #:spec (* x (/ 180.0 (PI))) #:impl degrees->radians #:fpcore (radians x) #:cost 1]\n  [neg.py      #:spec (neg x)    #:impl -                   #:cost 0.125]\n  [fabs.py     #:spec (fabs x)   #:impl (from-libm 'fabs)   #:cost 1]\n  [sin.py      #:spec (sin x)    #:impl (from-libm 'sin)    #:cost 1]\n  [sinh.py     #:spec (sinh x)   #:impl (from-libm 'sinh)   #:cost 1]\n  [asin.py     #:spec (asin x)   #:impl (from-libm 'asin)   #:cost 1]\n  [asinh.py    #:spec (asinh x)  #:impl (from-libm 'asinh)  #:cost 1]\n  [cos.py      #:spec (cos x)    #:impl (from-libm 'cos)    #:cost 1]\n  [cosh.py     #:spec (cosh x)   #:impl (from-libm 'cosh)   #:cost 1]\n  [acos.py     #:spec (acos x)   #:impl (from-libm 'acos)   #:cost 1]\n  [acosh.py    #:spec (acosh x)  #:impl (from-libm 'acosh)  #:cost 1]\n  [tan.py      #:spec (tan x)    #:impl (from-libm 'tan)    #:cost 1]\n  [atan.py     #:spec (atan x)   #:impl (from-libm 'atan)   #:cost 1]\n  [atanh.py    #:spec (atanh x)  #:impl (from-libm 'atanh)  #:cost 1]\n  [tanh.py     #:spec (tanh x)   #:impl (from-libm 'tanh)   #:cost 1]\n  [sqrt.py     #:spec (sqrt x)   #:impl (from-libm 'sqrt)   #:cost 1]\n  [cbrt.py     #:spec (cbrt x)   #:impl (from-libm 'cbrt)   #:cost 1]\n  [ceil.py     #:spec (ceil x)   #:impl (from-libm 'ceil)   #:cost 1]\n  [floor.py    #:spec (floor x)  #:impl (from-libm 'floor)  #:cost 1]\n  [erf.py      #:spec (erf x)    #:impl (from-libm 'erf)    #:cost 1]\n  [exp.py      #:spec (exp x)    #:impl (from-libm 'exp)    #:cost 1]\n  [exp2.py     #:spec (exp2 x)   #:impl (from-libm 'exp2)   #:cost 1]\n  [gamma.py    #:spec (tgamma x) #:impl (from-libm 'tgamma) #:cost 1]\n  [lgamma.py   #:spec (lgamma x) #:impl (from-libm 'lgamma) #:cost 1]\n  [log.1var    #:spec (log x)    #:impl (from-libm 'log)    #:cost 1]\n  [log10.py    #:spec (log10 x)  #:impl (from-libm 'log10)  #:cost 1]\n  [log2.py     #:spec (log2 x)   #:impl (from-libm 'log2)   #:cost 1]\n  [rint.py     #:spec (rint x)   #:impl (from-libm 'rint)   #:cost 1]\n  [round.py    #:spec (round x)  #:impl (from-libm 'round)  #:cost 1]\n  [trunc.py    #:spec (trunc x)  #:impl (from-libm 'trunc)  #:cost 1])\n\n(define-operations ([x <binary64>]) <binary64>\n  [erfc.py  #:spec (- 1 (erf x)) #:impl (from-libm 'erfc)  #:fpcore (erfc x) #:cost 1]\n  [expm1.py #:spec (- (exp x) 1) #:impl (from-libm 'expm1) #:fpcore (expm1 x) #:cost 1]\n  [log1p.py #:spec (log (+ 1 x)) #:impl (from-libm 'log1p) #:fpcore (log1p x) #:cost 1])\n\n(define-operations ([x <binary64>] [y <binary64>]) <binary64>\n  [pow.py       #:spec (pow x y)       #:impl (from-libm 'pow)       #:cost 1]\n  [atan2.py     #:spec (atan2 x y)     #:impl (from-libm 'atan2)     #:cost 1]\n  [copysign.py  #:spec (copysign x y)  #:impl (from-libm 'copysign)  #:cost 1]\n  [fdim.py      #:spec (fdim x y)      #:impl (from-libm 'fdim)      #:cost 1]\n  [fmax.py      #:spec (fmax x y)      #:impl (from-libm 'fmax)      #:cost 1]\n  [fmin.py      #:spec (fmin x y)      #:impl (from-libm 'fmin)      #:cost 1]\n  [fmod.py      #:spec (fmod x y)      #:impl (from-libm 'fmod)      #:cost 1]\n  [remainder.py #:spec (remainder x y) #:impl (from-libm 'remainder) #:cost 1])\n\n(define-operations ([x <binary64>] [y <binary64>] [w <binary64>]) <binary64>\n  [fsum.3var #:spec (+ (+ x y) w) #:impl (curry apply flsum) #:fpcore (fsum x y w) #:cost 1]\n  [prod.3var #:spec (* (* x y) w) #:impl (from-rival)        #:fpcore (prod x y w) #:cost 1])\n\n(define-operations ([x <binary64>] [y <binary64>] [w <binary64>] [z <binary64>]) <binary64>\n  [fsum.4var #:spec (+ (+ (+ x y) z) w) #:impl (curry apply flsum) #:fpcore (fsum x y w z) #:cost 1]\n  [prod.4var #:spec (* (* (* x y) w) z) #:impl (from-rival)        #:fpcore (prod x y w z) #:cost 1])\n\n(define-operation (dist.2D [x <binary64>] [y <binary64>] [z <binary64>] [w <binary64>]) <binary64>\n  #:spec (sqrt (+ (pow (- y x) 2) (pow (- w z) 2))) #:impl (from-rival)\n  #:fpcore (dist x y z w) #:cost 1)\n\n(define-operation (dist.3D [x <binary64>] [y <binary64>] [z <binary64>] [w <binary64>] [u <binary64>] [v <binary64>]) <binary64>\n  #:spec (sqrt (+ (+ (pow (- y x) 2) (pow (- w z) 2)) (pow (- v u) 2))) #:impl (from-rival)\n  #:fpcore (dist x y z w u v) #:cost 1)\n\n(define-operation (sumprod.2D [x <binary64>] [y <binary64>] [z <binary64>] [w <binary64>]) <binary64>\n  #:spec (+ (* x y) (* z w)) #:impl (from-rival)\n  #:fpcore (sumprod x y z w) #:cost 1)\n\n(define-operation (sumprod.3D [x <binary64>] [y <binary64>] [z <binary64>] [w <binary64>] [u <binary64>] [v <binary64>]) <binary64>\n  #:spec (+ (+ (* x y) (* z w)) (* u v)) #:impl (from-rival)\n  #:fpcore (sumprod x y z w u v) #:cost 1)\n\n(define-operation (hypot.2D [x <binary64>] [y <binary64>]) <binary64>\n  #:spec (sqrt (+ (* x x) (* y y))) #:impl (from-libm 'hypot)\n  #:fpcore (hypot x y) #:cost 1)\n\n(define-operation (hypot.3D [x <binary64>] [y <binary64>] [z <binary64>]) <binary64>\n  #:spec (sqrt (+ (+ (* x x) (* y y)) (* z z))) #:impl (from-rival)\n  #:fpcore (hypot x y z) #:cost 1)\n\n(define-operation (fma.py [x <binary64>] [y <binary64>] [z <binary64>]) <binary64>\n  #:spec (+ (* x y) z) #:impl (from-libm 'fma)\n  #:fpcore (fma x y z) #:cost 1)\n"
  },
  {
    "path": "src/platforms/racket.rkt",
    "content": "#lang s-exp \"../syntax/platform-language.rkt\"\n\n;;; Racket platform, focusing on racket/base and math/base.\n;;; Therefore only one data type, <binary64>, is supported.\n\n(require math/flonum\n         math/base)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BOOLEAN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <bool> #:cost 1)\n\n(define-operations () <bool>\n  [true  #:spec (TRUE)  #:impl (const true)  #:fpcore TRUE  #:cost 1]\n  [false #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost 1])\n\n(define-operations ([x <bool>] [y <bool>]) <bool>\n  [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost 1]\n  [or  #:spec (or x y)  #:impl (lambda v (ormap values v))  #:cost 1])\n\n(define-operation (not [x <bool>]) <bool>\n  #:spec (not x) #:impl not #:cost 1)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <binary64> #:cost 1)\n\n(define-operation (if.f64 [c <bool>] [t <binary64>] [f <binary64>]) <binary64>\n  #:spec (if c t f) #:impl if-impl\n  #:cost (if-cost 1))\n\n(define-operations () <binary64>\n  [PI.rkt       #:spec (PI)       #:impl (const pi)       #:fpcore PI       #:cost 1]\n  [INFINITY.rkt #:spec (INFINITY) #:impl (const +inf.0)   #:fpcore INFINITY #:cost 1]\n  [NAN.rkt      #:spec (NAN)      #:impl (const +nan.0)   #:fpcore NAN      #:cost 1])\n\n(define-operations ([x <binary64>] [y <binary64>]) <bool>\n  [=  #:spec (== x y) #:impl =  #:cost 1]\n  [<  #:spec (< x y)  #:impl <  #:cost 1]\n  [>  #:spec (> x y)  #:impl >  #:cost 1]\n  [<= #:spec (<= x y) #:impl <= #:cost 1]\n  [>= #:spec (>= x y) #:impl >= #:cost 1])\n\n(define ((no-complex fun) . xs)\n  (define res (apply fun xs))\n  (if (real? res) res +nan.0))\n\n(define-operation (-/1 [x <binary64>]) <binary64>\n  #:spec (neg x) #:impl - #:fpcore (- x) #:cost 1)\n\n(define-operations ([x <binary64>]) <binary64>\n [acos      #:spec (acos  x) #:impl (no-complex acos)  #:cost 1]\n [acosh     #:spec (acosh x) #:impl (no-complex acosh) #:cost 1]\n [asin      #:spec (asin  x) #:impl (no-complex asin)  #:cost 1]\n [asinh     #:spec (asinh x) #:impl (no-complex asinh) #:cost 1]\n [atan      #:spec (atan  x) #:impl (no-complex atan)  #:cost 1]\n [atanh     #:spec (atanh x) #:impl (no-complex atanh) #:cost 1]\n [ceiling   #:spec (ceil  x) #:impl ceiling            #:cost 1]\n [cos       #:spec (cos   x) #:impl cos                #:cost 1]\n [cosh      #:spec (cosh  x) #:impl cosh               #:cost 1]\n [exp       #:spec (exp   x) #:impl exp                #:cost 1]\n [abs       #:spec (fabs  x) #:impl abs                #:cost 1]\n [floor     #:spec (floor x) #:impl floor              #:cost 1]\n [log       #:spec (log   x) #:impl (no-complex log)   #:cost 1]\n [round     #:spec (round x) #:impl round              #:cost 1]\n [sin       #:spec (sin   x) #:impl sin                #:cost 1]\n [sinh      #:spec (sinh  x) #:impl sinh               #:cost 1]\n [sqrt      #:spec (sqrt  x) #:impl (no-complex sqrt)  #:cost 1]\n [tan       #:spec (tan   x) #:impl tan                #:cost 1]\n [tanh      #:spec (tanh  x) #:impl tanh               #:cost 1]\n [truncate  #:spec (trunc x) #:impl truncate           #:cost 1])\n\n(define-operations ([x <binary64>] [y <binary64>]) <binary64>\n [+         #:spec (+ x y)         #:impl +                 #:cost 1]\n [-         #:spec (- x y)         #:impl -                 #:cost 1]\n [*         #:spec (* x y)         #:impl *                 #:cost 1]\n [/         #:spec (/ x y)         #:impl /                 #:cost 1]\n [atan/2    #:spec (atan2 x y)     #:impl (no-complex atan) #:cost 1]\n [max       #:spec (fmax x y)      #:impl max               #:cost 1]\n [min       #:spec (fmin x y)      #:impl min               #:cost 1]\n [expt      #:spec (pow x y)       #:impl (no-complex expt) #:cost 1]\n [remainder #:spec (remainder x y) #:impl remainder         #:cost 1])\n\n(define-operation (//1 [x <binary64>]) <binary64>\n  #:spec (/ 1 x) #:impl / #:cost 1)\n\n(define-operation (log/2 [x <binary64>] [y <binary64>]) <binary64>\n  #:spec (/ (log x) (log y)) #:impl log #:fpcore (log x y) #:cost 1)\n\n(define-operation (flsingle [x <binary64>]) <binary64>\n  #:spec x #:impl flsingle #:fpcore (cast x) #:cost 1)\n"
  },
  {
    "path": "src/platforms/reflow.rkt",
    "content": "#lang s-exp \"../syntax/platform-language.rkt\"\n\n;; C/C++ platform with a full libm\n\n(require math/flonum)\n\n(define 64bit-move-cost   0.125)\n(define 32bit-move-cost   0.125)\n(define boolean-move-cost 0.100)\n\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BOOLEAN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <bool> #:cost boolean-move-cost)\n\n(define-operations () <bool>\n  [TRUE  #:spec (TRUE)  #:impl (const true)  #:fpcore TRUE  #:cost boolean-move-cost]\n  [FALSE #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost boolean-move-cost])\n\n(define-operations ([x <bool>] [y <bool>]) <bool>\n  [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost boolean-move-cost]\n  [or  #:spec (or x y)  #:impl (lambda v (ormap values v))  #:cost boolean-move-cost])\n\n(define-operation (not [x <bool>]) <bool>\n  #:spec (not x) #:impl not #:cost boolean-move-cost)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <binary32> #:cost 32bit-move-cost)\n\n(define-operation (if.f32 [c <bool>] [t <binary32>] [f <binary32>]) <binary32>\n  #:spec (if c t f) #:impl if-impl\n  #:cost (if-cost boolean-move-cost))\n\n(define-operations ([x <binary32>] [y <binary32>]) <bool>\n  [==.f32 #:spec (== x y) #:impl =          #:cost 32bit-move-cost]\n  [!=.f32 #:spec (!= x y) #:impl (negate =) #:cost 32bit-move-cost]\n  [<.f32  #:spec (< x y)  #:impl <          #:cost 32bit-move-cost]\n  [>.f32  #:spec (> x y)  #:impl >          #:cost 32bit-move-cost]\n  [<=.f32 #:spec (<= x y) #:impl <=         #:cost 32bit-move-cost]\n  [>=.f32 #:spec (>= x y) #:impl >=         #:cost 32bit-move-cost])\n\n(define-operations () <binary32> #:fpcore (! :precision binary32 _)\n  [PI.f32       #:spec (PI)       #:impl (const (flsingle pi))       #:fpcore PI       #:cost 32bit-move-cost]\n  [E.f32        #:spec (E)        #:impl (const (flsingle (exp 1)))  #:fpcore E        #:cost 32bit-move-cost])\n\n(define-operation (neg.f32 [x <binary32>]) <binary32>\n  #:spec (neg x) #:impl (compose flsingle -)\n  #:fpcore (! :precision binary32 (- x)) #:cost 0.125)\n\n(define-operations ([x <binary32>] [y <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [+.f32 #:spec (+ x y) #:impl (compose flsingle +) #:cost 0.200]\n  [-.f32 #:spec (- x y) #:impl (compose flsingle -) #:cost 0.200]\n  [*.f32 #:spec (* x y) #:impl (compose flsingle *) #:cost 0.250]\n  [/.f32 #:spec (/ x y) #:impl (compose flsingle /) #:cost 0.350])\n\n(define-operations ([x <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [fabs.f32   #:spec (fabs x)   #:impl (from-libm 'fabsf)   #:cost 0.125]\n  [sin.f32    #:spec (sin x)    #:impl (from-libm 'sinf)    #:cost 4.250]\n  [cos.f32    #:spec (cos x)    #:impl (from-libm 'cosf)    #:cost 4.250]\n  [tan.f32    #:spec (tan x)    #:impl (from-libm 'tanf)    #:cost 4.750]\n  [acos.f32   #:spec (acos x)   #:impl (from-libm 'acosf)   #:cost 0.500]\n  [asin.f32   #:spec (asin x)   #:impl (from-libm 'asinf)   #:cost 0.500]\n  [atan.f32   #:spec (atan x)   #:impl (from-libm 'atanf)   #:cost 1.100]\n  [exp.f32    #:spec (exp x)    #:impl (from-libm 'expf)    #:cost 1.375]\n  [log.f32    #:spec (log x)    #:impl (from-libm 'logf)    #:cost 0.750]\n  [sqrt.f32   #:spec (sqrt x)   #:impl (from-libm 'sqrtf)   #:cost 0.250])\n\n(define-operations ([x <binary32>] [y <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [pow.f32       #:spec (pow x y)       #:impl (from-libm 'powf)       #:cost 2.000]\n  [fmax.f32      #:spec (fmax x y)      #:impl (from-libm 'fmaxf)      #:cost 0.250]\n  [fmin.f32      #:spec (fmin x y)      #:impl (from-libm 'fminf)      #:cost 0.250])\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <binary64> #:cost 64bit-move-cost)\n\n(define-operation (if.f64 [c <bool>] [t <binary64>] [f <binary64>]) <binary64>\n  #:spec (if c t f) #:impl if-impl\n  #:cost (if-cost boolean-move-cost))\n\n(define-operations ([x <binary64>] [y <binary64>]) <bool>\n  [==.f64 #:spec (== x y) #:impl =          #:cost 64bit-move-cost]\n  [!=.f64 #:spec (!= x y) #:impl (negate =) #:cost 64bit-move-cost]\n  [<.f64  #:spec (< x y)  #:impl <          #:cost 64bit-move-cost]\n  [>.f64  #:spec (> x y)  #:impl >          #:cost 64bit-move-cost]\n  [<=.f64 #:spec (<= x y) #:impl <=         #:cost 64bit-move-cost]\n  [>=.f64 #:spec (>= x y) #:impl >=         #:cost 64bit-move-cost])\n\n(define-operations () <binary64> #:fpcore (! :precision binary64 _)\n  [PI.f64   #:spec (PI)       #:impl (const pi)      #:fpcore PI       #:cost 64bit-move-cost]\n  [E.f64    #:spec (E)        #:impl (const (exp 1)) #:fpcore E        #:cost 64bit-move-cost])\n\n(define-operation (neg.f64 [x <binary64>]) <binary64>\n  #:spec (neg x) #:impl - #:fpcore (! :precision binary64 (- x)) #:cost 0.125)\n\n(define-operations ([x <binary64>] [y <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [+.f64 #:spec (+ x y) #:impl + #:cost 0.200]\n  [-.f64 #:spec (- x y) #:impl - #:cost 0.200]\n  [*.f64 #:spec (* x y) #:impl * #:cost 0.250]\n  [/.f64 #:spec (/ x y) #:impl / #:cost 0.350])\n\n(define-operations ([x <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [fabs.f64   #:spec (fabs x)   #:impl (from-libm 'fabs)      #:cost 0.125]\n  [sin.f64    #:spec (sin x)    #:impl (from-libm 'sin)       #:cost 4.200]\n  [cos.f64    #:spec (cos x)    #:impl (from-libm 'cos)       #:cost 4.200]\n  [tan.f64    #:spec (tan x)    #:impl (from-libm 'tan)       #:cost 4.650]\n  [acos.f64   #:spec (acos x)   #:impl (from-libm 'acos)      #:cost 0.500]\n  [asin.f64   #:spec (asin x)   #:impl (from-libm 'asin)      #:cost 0.500]\n  [atan.f64   #:spec (atan x)   #:impl (from-libm 'atan)      #:cost 1.100]\n  [exp.f64    #:spec (exp x)    #:impl (from-libm 'exp)       #:cost 1.375]\n  [log.f64    #:spec (log x)    #:impl (from-libm 'log)       #:cost 0.750]\n  [sqrt.f64   #:spec (sqrt x)   #:impl (from-libm 'sqrt)      #:cost 0.250])\n\n(define-operations ([x <binary64>] [y <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [pow.f64       #:spec (pow x y)       #:impl (from-libm 'pow)       #:cost 2.000]\n  [fmax.f64      #:spec (fmax x y)      #:impl (from-libm 'fmax)      #:cost 0.250]\n  [fmin.f64      #:spec (fmin x y)      #:impl (from-libm 'fmin)      #:cost 0.250])\n"
  },
  {
    "path": "src/platforms/rival.rkt",
    "content": "#lang s-exp \"../syntax/platform-language.rkt\"\n\n;;; Rival correctly-rounded platform\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BOOLEAN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <bool> #:cost 1)\n\n(define-operations () <bool>\n  [TRUE  #:spec (TRUE)  #:impl (from-rival) #:fpcore TRUE  #:cost 1]\n  [FALSE #:spec (FALSE) #:impl (from-rival) #:fpcore FALSE #:cost 1])\n\n(define-operations ([x <bool>] [y <bool>]) <bool>\n  [and #:spec (and x y) #:impl (from-rival) #:cost 1]\n  [or  #:spec (or x y)  #:impl (from-rival) #:cost 1])\n\n(define-operation (not [x <bool>]) <bool>\n  #:spec (not x) #:impl not #:cost 1)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <binary32> #:cost 1)\n\n(define-operation (if.f32 [c <bool>] [t <binary32>] [f <binary32>]) <binary32>\n  #:spec (if c t f) #:impl (from-rival)\n  #:cost (if-cost 1))\n\n(define-operations ([x <binary32>] [y <binary32>]) <bool>\n  [==.f32 #:spec (== x y) #:impl (from-rival) #:cost 1]\n  [!=.f32 #:spec (!= x y) #:impl (from-rival) #:cost 1]\n  [<.f32  #:spec (< x y)  #:impl (from-rival) #:cost 1]\n  [>.f32  #:spec (> x y)  #:impl (from-rival) #:cost 1]\n  [<=.f32 #:spec (<= x y) #:impl (from-rival) #:cost 1]\n  [>=.f32 #:spec (>= x y) #:impl (from-rival) #:cost 1])\n\n(define-operations () <binary32> #:fpcore (! :precision binary32 _)\n  [PI.f32 #:spec (PI) #:impl (from-rival) #:fpcore PI #:cost 1]\n  [E.f32  #:spec (E)  #:impl (from-rival) #:fpcore E  #:cost 1])\n\n(define-operation (neg.f32 [x <binary32>]) <binary32>\n  #:spec (neg x) #:impl (from-rival) #:fpcore (! :precision binary32 (- x)) #:cost 1)\n\n(define-operations ([x <binary32>] [y <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [+.f32 #:spec (+ x y) #:impl (from-rival) #:cost 1]\n  [-.f32 #:spec (- x y) #:impl (from-rival) #:cost 1]\n  [*.f32 #:spec (* x y) #:impl (from-rival) #:cost 1]\n  [/.f32 #:spec (/ x y) #:impl (from-rival) #:cost 1])\n\n(define-operations ([x <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [fabs.f32   #:spec (fabs x)   #:impl (from-rival) #:cost 1]\n  [sin.f32    #:spec (sin x)    #:impl (from-rival) #:cost 1]\n  [cos.f32    #:spec (cos x)    #:impl (from-rival) #:cost 1]\n  [tan.f32    #:spec (tan x)    #:impl (from-rival) #:cost 1]\n  [sinh.f32   #:spec (sinh x)   #:impl (from-rival) #:cost 1]\n  [cosh.f32   #:spec (cosh x)   #:impl (from-rival) #:cost 1]\n  [acos.f32   #:spec (acos x)   #:impl (from-rival) #:cost 1]\n  [acosh.f32  #:spec (acosh x)  #:impl (from-rival) #:cost 1]\n  [asin.f32   #:spec (asin x)   #:impl (from-rival) #:cost 1]\n  [asinh.f32  #:spec (asinh x)  #:impl (from-rival) #:cost 1]\n  [atan.f32   #:spec (atan x)   #:impl (from-rival) #:cost 1]\n  [atanh.f32  #:spec (atanh x)  #:impl (from-rival) #:cost 1]\n  [cbrt.f32   #:spec (cbrt x)   #:impl (from-rival) #:cost 1]\n  [ceil.f32   #:spec (ceil x)   #:impl (from-rival) #:cost 1]\n  [erf.f32    #:spec (erf x)    #:impl (from-rival) #:cost 1]\n  [exp.f32    #:spec (exp x)    #:impl (from-rival) #:cost 1]\n  [exp2.f32   #:spec (exp2 x)   #:impl (from-rival) #:cost 1]\n  [floor.f32  #:spec (floor x)  #:impl (from-rival) #:cost 1]\n  [lgamma.f32 #:spec (lgamma x) #:impl (from-rival) #:cost 1]\n  [log.f32    #:spec (log x)    #:impl (from-rival) #:cost 1]\n  [log10.f32  #:spec (log10 x)  #:impl (from-rival) #:cost 1]\n  [log2.f32   #:spec (log2 x)   #:impl (from-rival) #:cost 1]\n  [logb.f32   #:spec (logb x)   #:impl (from-rival) #:cost 1]\n  [rint.f32   #:spec (rint x)   #:impl (from-rival) #:cost 1]\n  [round.f32  #:spec (round x)  #:impl (from-rival) #:cost 1]\n  [sqrt.f32   #:spec (sqrt x)   #:impl (from-rival) #:cost 1]\n  [tanh.f32   #:spec (tanh x)   #:impl (from-rival) #:cost 1]\n  [tgamma.f32 #:spec (tgamma x) #:impl (from-rival) #:cost 1]\n  [trunc.f32  #:spec (trunc x)  #:impl (from-rival) #:cost 1])\n\n(define-operations ([x <binary32>] [y <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [pow.f32       #:spec (pow x y)       #:impl (from-rival) #:cost 1]\n  [atan2.f32     #:spec (atan2 x y)     #:impl (from-rival) #:cost 1]\n  [copysign.f32  #:spec (copysign x y)  #:impl (from-rival) #:cost 1]\n  [fdim.f32      #:spec (fdim x y)      #:impl (from-rival) #:cost 1]\n  [fmax.f32      #:spec (fmax x y)      #:impl (from-rival) #:cost 1]\n  [fmin.f32      #:spec (fmin x y)      #:impl (from-rival) #:cost 1]\n  [fmod.f32      #:spec (fmod x y)      #:impl (from-rival) #:cost 1]\n  [remainder.f32 #:spec (remainder x y) #:impl (from-rival) #:cost 1])\n\n(define-operations ([x <binary32>]) <binary32> #:fpcore (! :precision binary32 _)\n  [erfc.f32  #:spec (- 1 (erf x)) #:impl (from-rival) #:fpcore (erfc x)  #:cost 1]\n  [expm1.f32 #:spec (- (exp x) 1) #:impl (from-rival) #:fpcore (expm1 x) #:cost 1]\n  [log1p.f32 #:spec (log (+ 1 x)) #:impl (from-rival) #:fpcore (log1p x) #:cost 1])\n\n(define-operation (hypot.f32 [x <binary32>] [y <binary32>]) <binary32>\n  #:spec (sqrt (+ (* x x) (* y y))) #:impl (from-rival) #:fpcore (! :precision binary32 (hypot x y)) #:cost 1)\n\n(define-operation (fma.f32 [x <binary32>] [y <binary32>] [z <binary32>]) <binary32>\n  #:spec (+ (* x y) z) #:impl (from-rival) #:fpcore (! :precision binary32 (fma x y z)) #:cost 1)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-representation <binary64> #:cost 1)\n\n(define-operation (if.f64 [c <bool>] [t <binary64>] [f <binary64>]) <binary64>\n  #:spec (if c t f) #:impl (from-rival)\n  #:cost (if-cost 1))\n\n(define-operations ([x <binary64>] [y <binary64>]) <bool>\n  [==.f64 #:spec (== x y) #:impl (from-rival) #:cost 1]\n  [!=.f64 #:spec (!= x y) #:impl (from-rival) #:cost 1]\n  [<.f64  #:spec (< x y)  #:impl (from-rival) #:cost 1]\n  [>.f64  #:spec (> x y)  #:impl (from-rival) #:cost 1]\n  [<=.f64 #:spec (<= x y) #:impl (from-rival) #:cost 1]\n  [>=.f64 #:spec (>= x y) #:impl (from-rival) #:cost 1])\n\n(define-operations () <binary64> #:fpcore (! :precision binary64 _)\n  [PI.f64   #:spec (PI)       #:impl (from-rival) #:cost 1]\n  [E.f64    #:spec (E)        #:impl (from-rival) #:cost 1]\n  [INFINITY #:spec (INFINITY) #:impl (from-rival) #:cost 1]\n  [NAN.f64  #:spec (NAN)      #:impl (from-rival) #:cost 1])\n\n(define-operation (neg.f64 [x <binary64>]) <binary64>\n  #:spec (neg x) #:impl (from-rival) #:fpcore (! :precision binary64 (- x)) #:cost 1)\n\n(define-operations ([x <binary64>] [y <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [+.f64 #:spec (+ x y) #:impl (from-rival) #:cost 1]\n  [-.f64 #:spec (- x y) #:impl (from-rival) #:cost 1]\n  [*.f64 #:spec (* x y) #:impl (from-rival) #:cost 1]\n  [/.f64 #:spec (/ x y) #:impl (from-rival) #:cost 1])\n\n(define-operations ([x <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [fabs.f64   #:spec (fabs x)   #:impl (from-rival) #:cost 1]\n  [sin.f64    #:spec (sin x)    #:impl (from-rival) #:cost 1]\n  [cos.f64    #:spec (cos x)    #:impl (from-rival) #:cost 1]\n  [tan.f64    #:spec (tan x)    #:impl (from-rival) #:cost 1]\n  [sinh.f64   #:spec (sinh x)   #:impl (from-rival) #:cost 1]\n  [cosh.f64   #:spec (cosh x)   #:impl (from-rival) #:cost 1]\n  [acos.f64   #:spec (acos x)   #:impl (from-rival) #:cost 1]\n  [acosh.f64  #:spec (acosh x)  #:impl (from-rival) #:cost 1]\n  [asin.f64   #:spec (asin x)   #:impl (from-rival) #:cost 1]\n  [asinh.f64  #:spec (asinh x)  #:impl (from-rival) #:cost 1]\n  [atan.f64   #:spec (atan x)   #:impl (from-rival) #:cost 1]\n  [atanh.f64  #:spec (atanh x)  #:impl (from-rival) #:cost 1]\n  [cbrt.f64   #:spec (cbrt x)   #:impl (from-rival) #:cost 1]\n  [ceil.f64   #:spec (ceil x)   #:impl (from-rival) #:cost 1]\n  [erf.f64    #:spec (erf x)    #:impl (from-rival) #:cost 1]\n  [exp.f64    #:spec (exp x)    #:impl (from-rival) #:cost 1]\n  [exp2.f64   #:spec (exp2 x)   #:impl (from-rival) #:cost 1]\n  [floor.f64  #:spec (floor x)  #:impl (from-rival) #:cost 1]\n  [lgamma.f64 #:spec (lgamma x) #:impl (from-rival) #:cost 1]\n  [log.f64    #:spec (log x)    #:impl (from-rival) #:cost 1]\n  [log10.f64  #:spec (log10 x)  #:impl (from-rival) #:cost 1]\n  [log2.f64   #:spec (log2 x)   #:impl (from-rival) #:cost 1]\n  [logb.f64   #:spec (logb x)   #:impl (from-rival) #:cost 1]\n  [rint.f64   #:spec (rint x)   #:impl (from-rival) #:cost 1]\n  [round.f64  #:spec (round x)  #:impl (from-rival) #:cost 1]\n  [sqrt.f64   #:spec (sqrt x)   #:impl (from-rival) #:cost 1]\n  [tanh.f64   #:spec (tanh x)   #:impl (from-rival) #:cost 1]\n  [tgamma.f64 #:spec (tgamma x) #:impl (from-rival) #:cost 1]\n  [trunc.f64  #:spec (trunc x)  #:impl (from-rival) #:cost 1])\n\n(define-operations ([x <binary64>] [y <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [pow.f64       #:spec (pow x y)       #:impl (from-rival) #:cost 1]\n  [atan2.f64     #:spec (atan2 x y)     #:impl (from-rival) #:cost 1]\n  [copysign.f64  #:spec (copysign x y)  #:impl (from-rival) #:cost 1]\n  [fdim.f64      #:spec (fdim x y)      #:impl (from-rival) #:cost 1]\n  [fmax.f64      #:spec (fmax x y)      #:impl (from-rival) #:cost 1]\n  [fmin.f64      #:spec (fmin x y)      #:impl (from-rival) #:cost 1]\n  [fmod.f64      #:spec (fmod x y)      #:impl (from-rival) #:cost 1]\n  [remainder.f64 #:spec (remainder x y) #:impl (from-rival) #:cost 1])\n\n(define-operations ([x <binary64>]) <binary64> #:fpcore (! :precision binary64 _)\n  [erfc.f64  #:spec (- 1 (erf x)) #:impl (from-rival) #:fpcore (erfc x)  #:cost 1]\n  [expm1.f64 #:spec (- (exp x) 1) #:impl (from-rival) #:fpcore (expm1 x) #:cost 1]\n  [log1p.f64 #:spec (log (+ 1 x)) #:impl (from-rival) #:fpcore (log1p x) #:cost 1])\n\n(define-operation (hypot.f64 [x <binary64>] [y <binary64>]) <binary64>\n  #:spec (sqrt (+ (* x x) (* y y))) #:impl (from-rival) #:fpcore (! :precision binary64 (hypot x y)) #:cost 1)\n\n(define-operation (fma.f64 [x <binary64>] [y <binary64>] [z <binary64>]) <binary64>\n  #:spec (+ (* x y) z) #:impl (from-rival) #:fpcore (! :precision binary64 (fma x y z)) #:cost 1)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CASTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define-operation (binary64->binary32 [x <binary64>]) <binary32>\n  #:spec x #:fpcore (! :precision binary32 (cast x)) #:impl (from-rival) #:cost 1)\n\n(define-operation (binary32->binary64 [x <binary32>]) <binary64>\n  #:spec x #:fpcore (! :precision binary64 (cast x)) #:impl (from-rival) #:cost 1)\n"
  },
  {
    "path": "src/reports/common.rkt",
    "content": "#lang racket\n(require (only-in xml write-xexpr xexpr?)\n         racket/runtime-path\n         (only-in fpbench\n                  fpcore?\n                  supported-by-lang?\n                  core->c\n                  core->fortran\n                  core->java\n                  core->python\n                  core->julia\n                  core->matlab\n                  core->wls\n                  core->reflow\n                  core->tex\n                  expr->tex\n                  core->js\n                  compilers\n                  [core-common-subexpr-elim core-cse]\n                  *expr-cse-able?*))\n\n(require \"../utils/common.rkt\"\n         \"../syntax/read.rkt\"\n         \"../core/programs.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/sugar.rkt\"\n         \"../syntax/platform.rkt\"\n         \"../syntax/syntax.rkt\")\n\n(provide format-accuracy\n         render-menu\n         render-warnings\n         render-large\n         render-comparison\n         render-specification\n         render-program\n         render-help\n         render-reproduction\n         format-percent\n         write-html\n         program->fpcore\n         fpcore->tex\n         fpcore->string\n         web-resource\n         js-tex-include\n         doc-url\n         core->c\n         core->fortran\n         core->java\n         core->python\n         core->julia\n         core->matlab\n         core->wls\n         core->reflow\n         core->tex\n         expr->tex\n         core->js)\n\n(define (format-accuracy numerator repr #:sign [sign #f] #:unit [unit \"\"])\n  (define denominator (representation-total-bits repr))\n  (cond\n    [(and numerator (positive? denominator))\n     (define percent (~r (- 100 (* (/ numerator denominator) 100)) #:precision '(= 1)))\n     (if (and (positive? numerator) sign)\n         (format \"+~a~a\" percent unit)\n         (format \"~a~a\" percent unit))]\n    [else \"\"]))\n\n(define (write-html xexpr out)\n  (fprintf out \"<!doctype html>\\n\")\n  (write-xexpr xexpr out))\n\n(define (program->fpcore expr ctx #:ident [ident #f])\n  (define body (prog->fpcore expr ctx))\n  (if ident\n      (list 'FPCore ident (context-vars ctx) body)\n      (list 'FPCore (context-vars ctx) body)))\n\n(define (fpcore-add-props core props)\n  (match core\n    [(list 'FPCore name args expr) `(FPCore ,name ,args ,@props ,expr)]\n    [(list 'FPCore args expr) `(FPCore ,args ,@props ,expr)]))\n\n(define (repr->precision-name repr)\n  (dict-ref (repr->prop repr) ':precision (representation-name repr)))\n\n(define (at-least-two-ops? expr)\n  (match expr\n    [(list op args ...) (ormap list? args)]\n    [_ #f]))\n\n(define (doc-url page)\n  (format \"https://herbie.uwplse.org/doc/~a/~a\" *herbie-version* page))\n\n(define-runtime-path web-resource-path \"resources/\")\n\n(define (web-resource [name #f])\n  (if name\n      (build-path web-resource-path name)\n      web-resource-path))\n\n(define/contract (render-menu #:path [path \".\"] name links)\n  (->* (string? (listof (cons/c string? string?))) (#:path string?) xexpr?)\n  `(header (h1 ,name)\n           (img ([src ,(string-append path \"/\" \"logo-car.png\")]))\n           (nav (ul ,@(for/list ([(text url) (in-dict (filter identity links))])\n                        `(li (a ([href ,url]) ,text)))))))\n\n(define/contract (render-warnings warnings)\n  (-> (listof (list/c string? string? (or/c string? #f) (listof string?))) xexpr?)\n  (if (null? warnings)\n      \"\"\n      `(ul ((class \"warnings\"))\n           ,@(for/list ([warning warnings])\n               (match-define (list type message url extra) warning)\n               `(li (h2 ,message\n                        ,(if url\n                             `(a ([href ,url]) \" (more)\")\n                             \"\"))\n                    ,(if (null? extra)\n                         \"\"\n                         `(ol ((class \"extra\"))\n                              ,@(for/list ([line extra])\n                                  `(li ,line)))))))))\n\n(define (render-large #:title [title #f] name . values)\n  `(div ,name\n        \": \"\n        (span ((class \"number\") ,@(if title\n                                      `([title ,title])\n                                      '()))\n              ,@values)))\n\n(define (render-comparison #:title [title #f] name a b)\n  (render-large #:title title name a `(span ((class \"unit\")) \" → \") b))\n\n(define (render-specification test)\n  (define-values (dropdown body)\n    (render-program (test-spec test)\n                    (test-context test)\n                    #:pre (test-pre test)\n                    #:ident (test-identifier test)))\n  `(section (details ([id \"specification\"] (class \"programs\"))\n                     (summary (h2 \"Specification\")\n                              ,dropdown\n                              (a ((class \"help-button float\") [href ,(doc-url \"report.html#spec\")]\n                                                              [target \"_blank\"])\n                                 \"?\"))\n                     ,body)))\n\n(define languages\n  `((\"FPCore\" \"fpcore\" ,(λ (c i) (fpcore->string c))) (\"C\" \"c\" ,core->c)\n                                                      (\"Fortran\" \"f03\" ,core->fortran)\n                                                      (\"Java\" \"java\" ,core->java)\n                                                      (\"Python\" \"py\" ,core->python)\n                                                      (\"Julia\" \"jl\" ,core->julia)\n                                                      (\"MATLAB\" \"mat\" ,core->matlab)\n                                                      (\"Wolfram\" \"wl\" ,core->wls)\n                                                      (\"ReFlow\" \"reflow\" ,core->reflow)\n                                                      (\"TeX\" \"tex\" ,(λ (c i) (core->tex c)))))\n\n(define (fpcore->tex fpcore #:loc [loc #f])\n  (if (supported-by-lang? fpcore \"tex\")\n      (core->tex fpcore #:loc (and loc (cons 2 loc)) #:color \"blue\")\n      \"ERROR\"))\n\n(define (render-program expr ctx #:ident [identifier #f] #:pre [precondition '(TRUE)])\n  (define output-repr (context-repr ctx))\n  (define out-prog\n    (parameterize ([*expr-cse-able?* at-least-two-ops?])\n      (core-cse (program->fpcore expr ctx #:ident identifier))))\n\n  (define output-prec (repr->precision-name output-repr))\n  (define precondition* (prog->fpcore precondition ctx))\n  (define out-prog* (fpcore-add-props out-prog (list ':precision output-prec ':pre precondition*)))\n\n  (define versions\n    (reap [sow]\n          (for ([(lang record) (in-dict languages)])\n            (match-define (list ext converter) record)\n            (when (and (fpcore? out-prog*)\n                       (or (equal? ext \"fpcore\") (supported-by-lang? out-prog* ext)))\n              (define name\n                (if identifier\n                    (symbol->string identifier)\n                    \"code\"))\n              (define out (converter out-prog* name))\n              (sow (cons lang out))))))\n\n  (define math-out (dict-ref versions \"TeX\" \"\"))\n\n  (define dropdown\n    `(select (option \"Math\")\n             ,@(for/list ([lang (in-dict-keys versions)])\n                 `(option ,lang))))\n\n  (define body\n    `(div\n      ,(if (equal? precondition '(TRUE))\n           \"\"\n           `(div\n             ([id \"precondition\"])\n             (div ((class \"program math\")) \"\\\\[\" ,(expr->tex (prog->fpcore precondition ctx)) \"\\\\]\")))\n      (div ((class \"implementation\") [data-language \"Math\"])\n           (div ((class \"program math\")) \"\\\\[\" ,math-out \"\\\\]\"))\n      ,@(for/list ([(lang out) (in-dict versions)])\n          `(div ((class \"implementation\") [data-language ,lang]) (pre ((class \"program\")) ,out)))))\n\n  (values dropdown body))\n\n(define/contract (render-command-line)\n  (-> string?)\n  (format \"herbie shell --seed ~a ~a\"\n          (if (vector? (get-seed))\n              (format \"'~a'\" (get-seed))\n              (get-seed))\n          (string-join (for/list ([rec (changed-flags)])\n                         (match rec\n                           [(list 'enabled class flag) (format \"+o ~a:~a\" class flag)]\n                           [(list 'disabled class flag) (format \"-o ~a:~a\" class flag)]))\n                       \" \")))\n\n(define/contract (render-fpcore test)\n  (-> test? string?)\n  (define output-repr (test-output-repr test))\n  (define output-precision (repr->precision-name output-repr))\n  (define rendered-vars\n    (for/list ([var (in-list (test-vars test))])\n      (define repr-name (dict-ref (test-var-repr-names test) var))\n      (define repr (get-representation repr-name))\n      (cond\n        [(array-representation? repr)\n         (define dims (array-representation-shape repr))\n         (define elem-precision (repr->precision-name (array-representation-base repr)))\n         (if (equal? elem-precision output-precision)\n             (append (list var) dims)\n             (append (list '! ':precision elem-precision var) dims))]\n        [else\n         (define var-precision (repr->precision-name repr))\n         (if (equal? var-precision output-precision)\n             var\n             (list '! ':precision var-precision var))])))\n  (string-join\n   (filter identity\n           (list (if (test-identifier test)\n                     (format \"(FPCore ~a ~a\" (test-identifier test) rendered-vars)\n                     (format \"(FPCore ~a\" rendered-vars))\n                 (format \"  :name ~s\" (test-name test))\n                 (format \"  :precision ~s\" output-precision)\n                 (if (equal? (test-pre test) '(TRUE))\n                     #f\n                     (format \"  :pre ~a\" (prog->fpcore (test-pre test) (test-context test))))\n                 (if (equal? (test-expected test) #t)\n                     #f\n                     (format \"  :herbie-expected ~a\" (test-expected test)))\n                 (and (test-output test)\n                      (not (null? (test-output test)))\n                      (format \"\\n~a\"\n                              (string-join (map (lambda (exp) (format \"  :alt\\n  ~a\\n\" (car exp)))\n                                                (test-output test))\n                                           \"\\n\")))\n                 (format \"  ~a)\" (prog->fpcore (test-input test) (test-context test)))))\n   \"\\n\"))\n\n(define (format-percent num den)\n  (string-append (if (zero? den)\n                     (cond\n                       [(positive? num) \"+∞\"]\n                       [(zero? num) \"0\"]\n                       [(negative? num) \"-∞\"])\n                     (~r (* (/ num den) 100) #:precision '(= 1)))\n                 \"%\"))\n\n(define/contract (render-reproduction test #:bug? [bug? #f])\n  (->* (test?) (#:bug? boolean?) xexpr?)\n\n  `(section\n    ([id \"reproduce\"])\n    (details ,(if bug?\n                  '([open \"open\"])\n                  \"\")\n             (summary (h2 \"Reproduce\")\n                      (a ((class \"help-button float\") [href ,(doc-url \"report.html#reproduction\")]\n                                                      [target \"_blank\"])\n                         \"?\"))\n             (pre ((class \"shell\")) (code ,(render-command-line) \"\\n\" ,(render-fpcore test) \"\\n\"))\n             ,(if bug?\n                  `(p \"Please file a \"\n                      (a ((href \"https://github.com/herbie-fp/herbie/issues\")) \"bug report\")\n                      \" with this information.\")\n                  \"\"))))\n\n(define (render-help url #:float [float? #t])\n  `(a ((class ,(if float? \"help-button float\" \"help-button\")) [href ,(doc-url url)] [target \"_blank\"])\n      \"?\"))\n\n(define js-tex-include\n  '((link ([rel \"stylesheet\"]\n           [href \"https://cdn.jsdelivr.net/npm/katex@0.16.22/dist/katex.min.css\"]\n           [integrity \"sha384-5TcZemv2l/9On385z///+d7MSYlvIEw9FuZTIdZ14vJLqWphw7e7ZPuOiCHJcFCP\"]\n           [crossorigin \"anonymous\"]))\n    (script ([defer \"\"] [src \"https://cdn.jsdelivr.net/npm/katex@0.16.22/dist/katex.min.js\"]\n                        [integrity\n                         \"sha384-cMkvdD8LoxVzGF/RPUKAcvmm49FQ0oxwDF3BGKtDXcEc+T1b2N+teh/OJfpU0jr6\"]\n                        [crossorigin \"anonymous\"]))\n    (script ([defer \"\"]\n             [src \"https://cdn.jsdelivr.net/npm/katex@0.16.22/dist/contrib/auto-render.min.js\"]\n             [integrity \"sha384-hCXGrW6PitJEwbkoStFjeJxv+fSOOQKOPbJxSfM6G5sWZjAyWhXiTIIAmQqnlLlh\"]\n             [crossorigin \"anonymous\"]))))\n"
  },
  {
    "path": "src/reports/core2mathjs.rkt",
    "content": "#lang racket\n\n(require fpbench\n         fpbench/src/fpcore-visitor)\n(provide core->mathjs\n         expr->mathjs\n         mathjs-supported)\n\n(define mathjs-supported\n  (supported-list (negate (curry set-member?\n                                 '(while while* array dim size ref for for* tensor tensor*)))\n                  (curry set-member? '(PI E TRUE FALSE))\n                  (const #t)\n                  ieee754-rounding-modes\n                  #f))\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;; utilities ;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define (fix-name name)\n  (string-join (for/list ([char (~a name)])\n                 (if (regexp-match #rx\"[a-zA-Z0-9_]\" (string char))\n                     (string char)\n                     (format \"_~a_\" (char->integer char))))\n               \"\"))\n\n(define infix-ops '(+ - * / == != < > <= >= not and or))\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;; compiler ;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define (constant->mathjs expr ctx)\n  (match expr\n    ['E \"E\"]\n    ['PI \"Math.PI\"]\n    ['TRUE \"true\"]\n    ['FALSE \"false\"]\n    [(? hex?) ((compose ~a real->double-flonum hex->racket) expr)]\n    [(? number?) (~a (real->double-flonum expr))]\n    [(? symbol?) (~a expr)]))\n\n(define (operator->mathjs op args ctx)\n  (define format-arg (compose trim-infix-parens ~a))\n  (format \"~a(~a)\" op (string-join (map format-arg args) \", \")))\n\n(define (compile-infix-operator op args ctx)\n  (match (cons op args)\n    [(list '- a) (format \"(- ~a)\" a)]\n    [(list 'not a) (format \"!~a\" a)]\n    [(list (or '== '!= '< '> '<= '>=)) (constant->mathjs 'TRUE ctx)]\n    ; binary arithmetic\n    [(list (or '+ '- '* '/) a b) (format \"(~a ~a ~a)\" a op b)]\n    [(list (or '== '< '> '<= '>=) arg args ...)\n     (format \"(~a)\"\n             (string-join (for/list ([a (cons arg args)]\n                                     [b args])\n                            (format \"~a ~a ~a\" a op b))\n                          \" && \"))]\n    [(list '!= args ...)\n     (format \"(~a)\"\n             (string-join (let loop ([args args])\n                            (if (null? args)\n                                '()\n                                (append (for/list ([b (cdr args)])\n                                          (format \"~a != ~a\" (car args) b))\n                                        (loop (cdr args)))))\n                          \" && \"))]\n    [(list 'and a ...) (format \"(~a)\" (string-join (map ~a a) \" && \"))]\n    [(list 'or a ...) (format \"(~a)\" (string-join (map ~a a) \" || \"))]))\n\n(define (compile-operator op args ctx)\n  (if (set-member? infix-ops op)\n      (compile-infix-operator op args ctx)\n      (operator->mathjs op args ctx)))\n\n(define (visit-if/mathjs vtor cond ift iff #:ctx ctx)\n  (format \"(~a ? ~a : ~a)\"\n          (visit/ctx vtor cond ctx)\n          (visit/ctx vtor ift ctx)\n          (visit/ctx vtor iff ctx)))\n\n(define (visit-let_/mathjs vtor let_ vars vals body #:ctx ctx)\n  (define ctx*\n    (for/fold ([ctx* ctx])\n              ([var (in-list vars)]\n               [val (in-list vals)])\n      (define val*\n        (visit/ctx vtor\n                   val\n                   (match let_\n                     ['let ctx]\n                     ['let* ctx*])))\n      (define-values (name-ctx name) (ctx-unique-name ctx* var #f)) ; don't use precision\n      (printf \"~a = ~a;\\n\" name (trim-infix-parens val*))\n      name-ctx))\n  (visit/ctx vtor body ctx*))\n\n(define (visit-!/mathjs vtor props body #:ctx ctx)\n  ; MathJS has no rounding-property syntax, but nested metadata still updates\n  ; compiler context (for names and scoped properties).\n  (define ctx* (ctx-update-props ctx props))\n  (visit/ctx vtor body ctx*))\n\n(define (visit_op/mathjs vtor op args #:ctx ctx)\n  (define args*\n    (for/list ([arg args])\n      (visit/ctx vtor arg ctx)))\n  (compile-operator op args* ctx))\n\n(define (visit-digits/mathjs vtor m e b #:ctx ctx)\n  (visit/ctx vtor (digits->number m e b) ctx))\n\n(define (visit-number/mathjs vtor x #:ctx ctx)\n  (constant->mathjs x ctx))\n\n(define (visit-constant/mathjs vtor x #:ctx ctx)\n  (constant->mathjs x ctx))\n\n(define (visit-symbol/mathjs vtor x #:ctx ctx)\n  (ctx-lookup-name ctx x))\n\n(define-expr-visitor default-compiler-visitor\n                     mathjs-visitor\n                     [visit-if visit-if/mathjs]\n                     [visit-let_ visit-let_/mathjs]\n                     [visit-! visit-!/mathjs]\n                     [visit-op_ visit_op/mathjs]\n                     [visit-digits visit-digits/mathjs]\n                     [visit-number visit-number/mathjs]\n                     [visit-constant visit-constant/mathjs]\n                     [visit-symbol visit-symbol/mathjs])\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;; public ;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n(define (expr->mathjs prog [name \"\"])\n  (parameterize ([*gensym-used-names* (mutable-set)]\n                 [*gensym-collisions* 1]\n                 [*gensym-fix-name* fix-name])\n    ; make compiler context\n    (define ctx (ctx-update-props (make-compiler-ctx) '(:precision binary64 :round nearestEven)))\n\n    ; translate\n    (define p (open-output-string))\n    (define-values (body* ret)\n      (parameterize ([current-output-port p])\n        (define o (visit/ctx mathjs-visitor prog ctx))\n        (values (get-output-string p) (trim-infix-parens o))))\n\n    (format \"~a~a\" body* ret)))\n\n(define (core->mathjs prog [name \"\"])\n  (parameterize ([*gensym-used-names* (mutable-set)]\n                 [*gensym-collisions* 1]\n                 [*gensym-fix-name* fix-name])\n    ; decompose FPCore\n    (define-values (args props body)\n      (match prog\n        [(list 'FPCore (list args ...) props ... body) (values args props body)]\n        [(list 'FPCore name (list args ...) props ... body) (values args props body)]))\n\n    ; make compiler context\n    (define ctx\n      (ctx-update-props (make-compiler-ctx) (append '(:precision binary64 :round nearestEven) props)))\n\n    ; handle variable annotations\n    (define arg-names\n      (for/list ([var args])\n        (match var\n          [(list '! props ... name) (fix-name (~a name))]\n          [_ (fix-name (~a var))])))\n\n    ; translate (body only)\n    (define p (open-output-string))\n    (define-values (body* ret)\n      (parameterize ([current-output-port p])\n        (define o (visit/ctx mathjs-visitor body ctx))\n        (values (get-output-string p) (trim-infix-parens o))))\n\n    (format \"~a~a\" body* ret)))\n"
  },
  {
    "path": "src/reports/data.rkt",
    "content": "#lang racket\n\n(provide (struct-out table-row)\n         (struct-out report-info))\n\n(struct table-row\n        (name identifier\n              status\n              pre\n              precision\n              conversions\n              vars\n              warnings\n              input\n              output\n              spec\n              target-prog\n              start\n              result\n              target\n              time\n              link\n              cost-accuracy)\n  #:prefab)\n\n(struct report-info (date commit branch seed flags points iterations tests) #:prefab)\n"
  },
  {
    "path": "src/reports/history.rkt",
    "content": "#lang racket\n\n(require (only-in xml write-xexpr xexpr?)\n         (only-in fpbench core->tex supported-by-lang?)\n         json\n         math/flonum)\n(require \"../core/rules.rkt\"\n         \"../syntax/sugar.rkt\"\n         \"../syntax/syntax.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/platform.rkt\"\n         \"../core/bsearch.rkt\"\n         \"../core/alternative.rkt\"\n         \"../utils/common.rkt\"\n         \"../syntax/float.rkt\"\n         \"../core/points.rkt\"\n         \"../core/programs.rkt\"\n         \"common.rkt\")\n(provide collect-expressions\n         render-history\n         render-json)\n\n(struct interval (alt-idx start-point end-point expr))\n\n(define (interval->string ival repr)\n  (define start (interval-start-point ival))\n  (define end (interval-end-point ival))\n  (string-join (list (if start\n                         (format \"~a < \" (value->string start repr))\n                         \"\")\n                     (~a (interval-expr ival))\n                     (if (equal? end +nan.0)\n                         \"\"\n                         (format \" < ~a\" (value->string end repr))))))\n\n;; Finds the Rewrite marker in a proof step and returns (dir rule next-step)\n;; where next-step has the marker replaced with its sub-expression\n(define (splice-proof-step step)\n  (let/ec k\n    (let loop ([expr step])\n      (match expr\n        [(list 'Rewrite=> rule sub) (k 'Rewrite=> rule (replace-expression step expr sub))]\n        [(list 'Rewrite<= rule sub) (k 'Rewrite<= rule (replace-expression step expr sub))]\n        [(approx spec impl)\n         (loop spec)\n         (loop impl)]\n        [(hole prec spec) (loop spec)]\n        [(list op args ...) (for-each loop args)]\n        [_ (void)]))\n    (k 'Goal #f step)))\n\n(define (altn-errors altn pcontext ctx errcache mask)\n  (define repr (context-repr ctx))\n  (define err (errors-score-masked (hash-ref errcache (alt-expr altn)) mask))\n  (format-accuracy err repr #:unit \"%\"))\n\n(define (mixed->fpcore expr ctx)\n  (define expr*\n    (let loop ([expr expr])\n      (match expr\n        [(? symbol?) expr]\n        [(? number?) expr]\n        [(? literal?) (literal-value expr)]\n        [(approx _ impl) (loop impl)]\n        [(hole precision spec) (loop spec)]\n        [`(if ,cond ,ift ,iff)\n         `(if ,(loop cond)\n              ,(loop ift)\n              ,(loop iff))]\n        [`(,(? impl-exists? impl) ,args ...)\n         ; use the FPCore operator without rounding properties\n         (define args* (map loop args))\n         (define vars (impl-info impl 'vars))\n         (define pattern\n           (match (impl-info impl 'fpcore)\n             [(list '! _ ... body) body]\n             [body body]))\n         (replace-vars (map cons vars args*) pattern)]\n        [`(,op ,args ...) `(,op ,@(map loop args))])))\n  `(FPCore ,(context-vars ctx) ,expr*))\n\n(define (cached-program->json-string fpcore-cache key prog ctx)\n  (hash-ref! fpcore-cache\n             key\n             (lambda ()\n               (define fpcore (program->fpcore prog ctx))\n               (fpcore->string fpcore))))\n\n(define (program->json-string prog ctx fpcore-cache)\n  (cached-program->json-string fpcore-cache prog prog ctx))\n\n(define (proof->json-string expr ctx fpcore-cache)\n  (cached-program->json-string fpcore-cache expr expr ctx))\n\n(define (mixed->json-string expr ctx fpcore-cache)\n  (hash-ref! fpcore-cache\n             expr\n             (lambda ()\n               (define fpcore (mixed->fpcore expr ctx))\n               (fpcore->string fpcore))))\n\n(define (collect-expressions altn)\n  (reap [sow]\n        (let loop ([altn altn])\n          (when (impl-prog? (alt-expr altn))\n            (sow (alt-expr altn)))\n\n          (match altn\n            [(alt prog 'start (list)) (void)]\n            [(alt prog 'add-preprocessing `(,prev)) (loop prev)]\n            [(alt prog `(evaluate ,start-expr) `(,prev)) (loop prev)]\n            [(alt _ `(regimes ,splitpoints) prevs) (for-each loop prevs)]\n            [(alt prog `(taylor ,start-expr ,pt ,var) `(,prev)) (loop prev)]\n            [(alt prog `(rr ,start-expr ,end-expr ,input ,proof) `(,prev))\n             (loop prev)\n             (when proof\n               (for ([step proof])\n                 (define-values (dir rule expr) (splice-proof-step step))\n                 (when (impl-prog? expr)\n                   (sow expr))))]))))\n\n(define (and-fn a b)\n  (and a b))\n\n(define (make-mask pcontext)\n  (make-vector (pcontext-length pcontext) #f))\n\n;; HTML renderer for derivations\n(define (render-history json ctx)\n  (define err\n    (match (hash-ref json 'error)\n      [(? number? n) (format-accuracy n (context-repr ctx) #:unit \"%\")]\n      [other other]))\n  (define prog (read (open-input-string (hash-ref json 'program))))\n  (match (hash-ref json 'type)\n    [\"start\"\n     (list `(li (p \"Initial program \" (span ((class \"error\")) ,err))\n                (div ((class \"math\")) \"\\\\[\" ,(fpcore->tex prog) \"\\\\]\")))]\n\n    [\"add-preprocessing\" `(,@(render-history (hash-ref json 'prev) ctx) (li \"Add Preprocessing\"))]\n\n    [\"regimes\"\n     (define prevs (hash-ref json 'prevs))\n     `((li ((class \"event\")) \"Split input into \" ,(~a (length prevs)) \" regimes\")\n       (li ,@(apply append\n                    (for/list ([entry (in-list prevs)]\n                               [condition (in-list (hash-ref json 'conditions))])\n                      `((h2 (code \"if \" (span ((class \"condition\")) ,(string-join condition \" or \"))))\n                        (ol ,@(render-history entry ctx))))))\n       (li ((class \"event\")) \"Recombined \" ,(~a (length prevs)) \" regimes into one program.\"))]\n\n    [\"taylor\"\n     (define-values (prev pt var) (apply values (map (curry hash-ref json) '(prev pt var))))\n     `(,@(render-history prev ctx)\n       (li (p \"Taylor expanded in \" ,var \" around \" ,pt)\n           (div ((class \"math\")) \"\\\\[\\\\leadsto \" ,(fpcore->tex prog) \"\\\\]\")))]\n\n    [\"evaluate\"\n     (define prev (hash-ref json 'prev))\n     `(,@(render-history prev ctx)\n       (li (p \"Evaluated real constant\" (span ((class \"error\")) ,err))\n           (div ((class \"math\")) \"\\\\[\\\\leadsto \" ,(fpcore->tex prog) \"\\\\]\")))]\n\n    [\"rr\"\n     (define-values (prev proof) (apply values (map (curry hash-ref json) '(prev proof))))\n     `(,@(render-history prev ctx)\n       (li ,(if (eq? proof (json-null))\n                \"\"\n                (render-proof proof ctx)))\n       (li (p \"Applied rewrites\" (span ((class \"error\")) ,err))\n           (div ((class \"math\")) \"\\\\[\\\\leadsto \" ,(fpcore->tex prog) \"\\\\]\")))]))\n\n(define (errors-score-masked errs mask)\n  (define mask-count (for/sum ([use? (in-vector mask)] #:when use?) 1))\n  (define masked-errs\n    (for/flvector #:length mask-count\n                  ([err (in-flvector errs)] [use? (in-vector mask)] #:when use?)\n                  err))\n  (errors-score (if (zero? mask-count) errs masked-errs)))\n\n(define (render-proof proof-json ctx)\n  `(div ((class \"proof\"))\n        (details\n         (summary \"Step-by-step derivation\")\n         (ol ,@(for/list ([step (in-list proof-json)])\n                 (define-values (direction err rule prog-str)\n                   (apply values (map (curry hash-ref step) '(direction error rule program))))\n                 (define dir\n                   (match direction\n                     [\"goal\" \"goal\"]\n                     [\"rtl\" \"right to left\"]\n                     [\"ltr\" \"left to right\"]))\n                 (define prog (read (open-input-string prog-str)))\n                 (if (equal? dir \"goal\")\n                     \"\"\n                     `(li (p (code ([title ,dir]) ,rule)\n                             (span ((class \"error\"))\n                                   ,(if (number? err)\n                                        (format-accuracy err (context-repr ctx) #:unit \"%\")\n                                        err)))\n                          (div ((class \"math\")) \"\\\\[\\\\leadsto \" ,(fpcore->tex prog) \"\\\\]\"))))))))\n\n(define (render-json altn\n                     pcontext\n                     ctx\n                     errcache\n                     [mask (make-vector (pcontext-length pcontext) #f)]\n                     [fpcore-cache (make-hash)])\n  (define repr (context-repr ctx))\n  (define err\n    (if (impl-prog? (alt-expr altn))\n        (errors-score-masked (hash-ref errcache (alt-expr altn)) mask)\n        \"N/A\"))\n\n  (match altn\n    [(alt prog 'start (list))\n     `#hash((program . ,(program->json-string prog ctx fpcore-cache))\n            (type . \"start\")\n            (error . ,err))]\n\n    [(alt prog `(regimes ,splitpoints) prevs)\n     (define intervals\n       (for/list ([start-sp (cons (sp -1 -1 #f) splitpoints)]\n                  [end-sp splitpoints])\n         (interval (sp-cidx end-sp) (sp-point start-sp) (sp-point end-sp) (sp-bexpr end-sp))))\n\n     `#hash((program . ,(program->json-string prog ctx fpcore-cache))\n            (type . \"regimes\")\n            (error . ,err)\n            (conditions . ,(for/list ([entry prevs]\n                                      [idx (in-naturals)])\n                             (define entry-ivals\n                               (filter (λ (intrvl) (= (interval-alt-idx intrvl) idx)) intervals))\n                             (map (curryr interval->string repr) entry-ivals)))\n            (prevs . ,(for/list ([entry prevs]\n                                 [new-mask (regimes-pcontext-masks pcontext splitpoints prevs ctx)])\n                        (define mask* (vector-map and-fn mask new-mask))\n                        (render-json entry pcontext ctx errcache mask* fpcore-cache))))]\n\n    [(alt prog `(taylor ,start-expr ,pt ,var) `(,prev))\n     `#hash((program . ,(program->json-string prog ctx fpcore-cache))\n            (type . \"taylor\")\n            (prev . ,(render-json prev pcontext ctx errcache mask fpcore-cache))\n            (pt . ,(~a pt))\n            (var . ,(~a var))\n            (error . ,err))]\n\n    [(alt prog `(evaluate ,start-expr) `(,prev))\n     `#hash((program . ,(program->json-string prog ctx fpcore-cache))\n            (type . \"evaluate\")\n            (prev . ,(render-json prev pcontext ctx errcache mask fpcore-cache))\n            (error . ,err))]\n\n    [(alt prog `(rr ,start-expr ,end-expr ,input ,proof) `(,prev))\n     `#hash((program . ,(program->json-string prog ctx fpcore-cache))\n            (type . \"rr\")\n            (prev . ,(render-json prev pcontext ctx errcache mask fpcore-cache))\n            (proof . ,(if proof\n                          (render-proof-json proof pcontext ctx errcache mask fpcore-cache)\n                          (json-null)))\n            (error . ,err))]\n\n    [(alt prog 'add-preprocessing `(,prev))\n     `#hash((program . ,(program->json-string prog ctx fpcore-cache))\n            (type . \"add-preprocessing\")\n            (prev . ,(render-json prev pcontext ctx errcache mask fpcore-cache))\n            (error . ,err))]))\n\n(define (render-proof-json proof pcontext ctx errcache mask fpcore-cache)\n  (for/list ([step proof])\n    (define-values (dir rule expr) (splice-proof-step step))\n    (define-values (err fpcore)\n      (cond\n        [(impl-prog? expr) (values (errors-score-masked (hash-ref errcache expr) mask) expr)]\n        [else (values \"N/A\" expr)]))\n\n    `#hash((error . ,err)\n           (program . ,(if (impl-prog? expr)\n                           (proof->json-string fpcore ctx fpcore-cache)\n                           (mixed->json-string fpcore ctx fpcore-cache)))\n           (direction . ,(match dir\n                           ['Rewrite<= \"rtl\"]\n                           ['Rewrite=> \"ltr\"]\n                           ['Goal \"goal\"]))\n           (rule . ,(~a rule)))))\n"
  },
  {
    "path": "src/reports/make-graph.rkt",
    "content": "#lang racket\n\n(require (only-in xml write-xexpr xexpr?)\n         (only-in fpbench core->tex *expr-cse-able?* [core-common-subexpr-elim core-cse]))\n(require math/flonum)\n\n(require \"../core/alternative.rkt\"\n         \"../utils/common.rkt\"\n         \"../syntax/float.rkt\"\n         \"../syntax/read.rkt\"\n         \"../syntax/types.rkt\"\n         \"../core/bsearch.rkt\"\n         \"../core/points.rkt\"\n         \"common.rkt\"\n         \"history.rkt\")\n\n(provide make-graph\n         dummy-graph)\n\n(define (dummy-graph command)\n  `(html (head (meta ([charset \"utf-8\"]))\n               (title \"Result page for the \" ,(~a command) \" command is not available right now.\")\n               ,@js-tex-include\n               (script ([src \"https://cdn.jsdelivr.net/npm/d3@7\"] [defer \"\"]))\n               (script ([src \"https://cdn.jsdelivr.net/npm/@observablehq/plot@0.6\"] [defer \"\"]))\n               (link ([rel \"stylesheet\"] [type \"text/css\"] [href \"../report.css\"]))\n               (script ([src \"../report.js\"])))\n         (body (h2 \"Result page for the \" ,(~a command) \" command is not available right now.\"))))\n\n(define (make-graph result-hash output? profile?)\n  (define backend (hash-ref result-hash 'backend))\n  (define test (car (load-tests (open-input-string (hash-ref result-hash 'test)))))\n  (define pre (test-pre test))\n  (define time (hash-ref result-hash 'time))\n  (define warnings (hash-ref result-hash 'warnings))\n  (define repr (test-output-repr test))\n  (define ctx (test-context test))\n  (define identifier (test-identifier test))\n\n  (define start-expr (read (open-input-string (hash-ref (hash-ref backend 'start) 'expr))))\n  (define start-cost (hash-ref (hash-ref backend 'start) 'cost))\n  (define start-error (hash-ref (hash-ref backend 'start) 'errors))\n\n  (define targets (hash-ref backend 'target))\n\n  (define end (hash-ref backend 'end))\n  (define end-exprs\n    (for/list ([end-analysis (in-list end)])\n      (read (open-input-string (hash-ref end-analysis 'expr)))))\n  (define end-errors (map (curryr hash-ref 'errors) end))\n  (define end-costs (map (curryr hash-ref 'cost) end))\n  (define end-histories\n    (for/list ([end-analysis (in-list end)])\n      (hash-ref end-analysis 'history)))\n\n  ; Speedup is going to be #f if cost is 0 for each alternative\n  (define speedup\n    (let ([better (filter number?\n                          (for/list ([err end-errors]\n                                     [cost end-costs]\n                                     #:when (<= (errors-score (list->flvector err))\n                                                (errors-score (list->flvector start-error))))\n                            (if (zero? cost) ; catching division by zero\n                                #f\n                                (/ start-cost cost))))])\n      (and (not (null? better)) (apply max better))))\n\n  (define end-error (car end-errors))\n  (define alt-number 0)\n\n  `(html\n    (head (meta ([charset \"utf-8\"]))\n          (title \"Result for \" ,(~a (test-name test)))\n          ,@js-tex-include\n          (script ([src \"https://cdn.jsdelivr.net/npm/d3@7\"] [defer \"\"]))\n          (script ([src \"https://cdn.jsdelivr.net/npm/@observablehq/plot@0.6\"] [defer \"\"]))\n          (link ([rel \"stylesheet\"] [type \"text/css\"] [href \"../report.css\"]))\n          (script ([src \"../report.js\"])))\n    (body\n     ,(render-menu #:path \"..\"\n                   (~a (test-name test))\n                   (if output?\n                       (list '(\"Report\" . \"../index.html\") '(\"Metrics\" . \"timeline.html\"))\n                       (list '(\"Metrics\" . \"timeline.html\"))))\n     (div ([id \"large\"])\n          ,(render-comparison\n            \"Percentage Accurate\"\n            (format-accuracy (errors-score (list->flvector start-error)) repr #:unit \"%\")\n            (format-accuracy (errors-score (list->flvector end-error)) repr #:unit \"%\")\n            #:title (format \"Minimum Accuracy: ~a → ~a\"\n                            (format-accuracy (apply max start-error) repr #:unit \"%\")\n                            (format-accuracy (apply max end-error) repr #:unit \"%\")))\n          ,(render-large \"Time\" (format-time time))\n          ,(render-large \"Alternatives\" (~a (length end-exprs)))\n          ,(render-large \"Speedup\"\n                         (if speedup\n                             (~r speedup #:precision '(= 1))\n                             \"N/A\")\n                         \"×\"\n                         #:title \"Relative speed of fastest alternative that improves accuracy.\"))\n     ,(render-warnings warnings)\n     ,(render-specification test)\n     (figure ([id \"graphs\"])\n             (h2 \"Local Percentage Accuracy vs \"\n                 (span ([id \"variables\"]))\n                 (a ((class \"help-button float\") [href ,(doc-url \"report.html#graph\")]\n                                                 [target \"_blank\"])\n                    \"?\"))\n             (svg)\n             (div ([id \"functions\"]))\n             (figcaption \"The average percentage accuracy by input value. Horizontal axis shows \"\n                         \"value of an input variable; the variable is choosen in the title. \"\n                         \"Vertical axis is accuracy; higher is better. Red represent the original \"\n                         \"program, while blue represents Herbie's suggestion. \"\n                         \"These can be toggled with buttons below the plot. \"\n                         \"The line is an average while dots represent individual samples.\"))\n     (section ([id \"cost-accuracy\"] (class \"section\") [data-benchmark-name ,(~a (test-name test))])\n              ; TODO : Show all Developer Target Accuracy\n              (h2 \"Accuracy vs Speed\"\n                  (a ((class \"help-button float\") [href ,(doc-url \"report.html#cost-accuracy\")]\n                                                  [target \"_blank\"])\n                     \"?\"))\n              (div ((class \"figure-row\"))\n                   (svg)\n                   (div (p \"Herbie found \" ,(~a (length end-exprs)) \" alternatives:\")\n                        (table (thead (tr (th \"Alternative\")\n                                          (th ((class \"numeric\")) \"Accuracy\")\n                                          (th ((class \"numeric\")) \"Speedup\")))\n                               (tbody))))\n              (figcaption \"The accuracy (vertical axis) and speed (horizontal axis) of each \"\n                          \"alternatives. Up and to the right is better. The red square shows \"\n                          \"the initial program, and each blue circle shows an alternative.\"\n                          \"The line shows the best available speed-accuracy tradeoffs.\"))\n     ,(let-values ([(dropdown body) (render-program start-expr ctx #:ident identifier #:pre pre)])\n        `(section ([id \"initial\"] (class \"programs\"))\n                  (h2 \"Initial Program\"\n                      \": \"\n                      (span ((class \"subhead\"))\n                            (data ,(format-accuracy (errors-score (list->flvector start-error))\n                                                    repr\n                                                    #:unit \"%\"))\n                            \" accurate, \"\n                            (data \"1.0×\")\n                            \" speedup\")\n                      ,dropdown\n                      ,(render-help \"report.html#alternatives\"))\n                  ,body))\n     ,@(for/list ([i (in-naturals 1)]\n                  [expr end-exprs]\n                  [errs end-errors]\n                  [cost end-costs]\n                  [history end-histories]\n                  #:unless (equal? start-expr expr))\n         (set! alt-number (add1 alt-number))\n         (define-values (dropdown body) (render-program expr ctx #:ident identifier #:pre pre))\n         `(section\n           ([id ,(format \"alternative~a\" i)] (class \"programs\"))\n           (h2 \"Alternative \"\n               ,(~a alt-number)\n               \": \"\n               (span ((class \"subhead\"))\n                     (data ,(format-accuracy (errors-score (list->flvector errs)) repr #:unit \"%\"))\n                     \" accurate, \"\n                     (data ,(if (zero? cost)\n                                \"N/A\"\n                                (~r (/ start-cost cost) #:precision '(= 1)))\n                           \"×\")\n                     \" speedup\")\n               ,dropdown\n               ,(render-help \"report.html#alternatives\"))\n           ,body\n           (details (summary \"Derivation\") (ol ((class \"history\")) ,@(render-history history ctx)))))\n     ,@(for/list ([i (in-naturals 1)]\n                  [target (in-list targets)])\n         (define target-error (hash-ref target 'errors))\n         (define target-cost (hash-ref target 'cost))\n         (define target-expr (read (open-input-string (hash-ref target 'expr))))\n         (let-values ([(dropdown body) (render-program target-expr ctx #:ident identifier)])\n           `(section ([id ,(format \"target~a\" i)] (class \"programs\"))\n                     (h2 \"Developer Target \"\n                         ,(~a i)\n                         \": \"\n                         (span ((class \"subhead\"))\n                               (data ,(format-accuracy (errors-score (list->flvector target-error))\n                                                       repr\n                                                       #:unit \"%\"))\n                               \" accurate, \"\n                               (data ,(~r (/ start-cost target-cost) #:precision '(= 1)) \"×\")\n                               \" speedup\")\n                         ,dropdown\n                         ,(render-help \"report.html#target\"))\n                     ,body)))\n     ,(render-reproduction test))))\n"
  },
  {
    "path": "src/reports/pages.rkt",
    "content": "#lang racket\n\n(require json\n         racket/engine)\n(require \"../syntax/read.rkt\"\n         \"timeline.rkt\"\n         \"plot.rkt\"\n         \"make-graph.rkt\"\n         \"traceback.rkt\"\n         \"common.rkt\")\n\n(provide all-pages\n         make-page-timeout\n         page-error-handler)\n\n(define (all-pages result-hash)\n  (define good? (equal? (hash-ref result-hash 'status) \"success\"))\n  (define default-pages '(\"graph.html\" \"timeline.html\" \"timeline.json\"))\n  (define success-pages '(\"points.json\" \"profile.json\"))\n  (append default-pages (if good? success-pages empty)))\n\n(define ((page-error-handler result-hash page out) e)\n  (define name (hash-ref result-hash 'name))\n  (eprintf \"Error generating `~a` for \\\"~a\\\":\\n  ~a\\n\" page name (exn-message e))\n  (eprintf \"context:\\n\")\n  (for ([(fn loc) (in-dict (continuation-mark-set->context (exn-continuation-marks e)))])\n    (match loc\n      [(srcloc file line col _ _) (eprintf \"  ~a:~a:~a: ~a\\n\" file line col (or fn \"(unnamed)\"))]\n      [#f (eprintf \"  ~a\\n\" fn)]))\n  (parameterize ([current-error-port out])\n    (display \"<!doctype html><pre>\" out)\n    ((error-display-handler) (exn-message e) e)\n    (display \"</pre>\" out)))\n\n(define (make-page-timeout page out result-hash output? profile? #:timeout [timeout +inf.0])\n  (define e (engine (lambda (_) (make-page page out result-hash output? profile?))))\n  (if (engine-run timeout e)\n      (engine-result e)\n      (display \"<!doctype html><h1>Timeout generating page</h1>\" out)))\n\n(define (make-page page out result-hash output? profile?)\n  (match page\n    [\"graph.html\" (write-html (make-graph-html result-hash output? profile?) out)]\n    [\"timeline.html\"\n     (define name (hash-ref result-hash 'name))\n     (write-html (make-timeline name (hash-ref result-hash 'timeline) #:path \"..\") out)]\n    [\"timeline.json\" (write-json (hash-ref result-hash 'timeline) out)]\n    [\"profile.json\" (write-json (hash-ref result-hash 'profile) out)]\n    [\"points.json\"\n     (write-json (with-handlers ([exn:fail? (lambda _ '())])\n                   (make-points-json result-hash))\n                 out)]))\n\n(define (make-graph-html result-hash output? profile?)\n  (define status (hash-ref result-hash 'status))\n  (match status\n    [\"success\"\n     (define command (hash-ref result-hash 'command))\n     (match command\n       [\"improve\" (make-graph result-hash output? profile?)]\n       [else (dummy-graph command)])]\n    [\"timeout\" (make-traceback result-hash)]\n    [\"failure\" (make-traceback result-hash)]))\n"
  },
  {
    "path": "src/reports/plot.rkt",
    "content": "#lang racket\n\n(require math/bigfloat\n         math/flonum)\n(require \"../core/points.rkt\"\n         \"../syntax/float.rkt\"\n         \"../core/programs.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/read.rkt\"\n         \"../core/alternative.rkt\"\n         \"../core/bsearch.rkt\")\n\n(provide make-points-json\n         regime-var\n         regime-splitpoints\n         real->ordinal\n         splitpoints->json)\n\n(define (bits->tenths x)\n  (string->number (real->decimal-string x 1)))\n\n(define (splitpoints->json vars alt repr)\n  (for/list ([var (in-list vars)])\n    (define split-var? (equal? var (regime-var alt)))\n    (if split-var?\n        (for/list ([val (regime-splitpoints alt)])\n          (real->ordinal (repr->real val repr) repr))\n        '())))\n\n(define (make-points-json result-hash)\n  (define test (car (load-tests (open-input-string (hash-ref result-hash 'test)))))\n  (define backend (hash-ref result-hash 'backend))\n  (define test-points (map first (hash-ref backend 'pcontext)))\n  (define repr (test-output-repr test))\n\n  (define start-errors (hash-ref (hash-ref backend 'start) 'errors))\n  (define target-errors (map (curryr hash-ref 'errors) (hash-ref backend 'target)))\n  (define end-errors (map (curryr hash-ref 'errors) (hash-ref backend 'end)))\n\n  ; Immediately convert points to reals to handle posits\n  (define ordinal-points\n    (for/list ([point (in-list test-points)])\n      (for/list ([x (in-list point)]\n                 [repr (in-list (test-var-reprs test))])\n        ((representation-repr->ordinal repr) (json->value x repr)))))\n\n  (define-values (mins maxs)\n    (for/fold ([mins #f]\n               [maxs #f])\n              ([point (in-list ordinal-points)])\n      (values (if mins\n                  (map min point mins)\n                  point)\n              (if maxs\n                  (map max point maxs)\n                  point))))\n\n  (define vars (test-vars test))\n  (define bits (representation-total-bits repr))\n  (define start-error\n    (for/list ([err (in-list start-errors)])\n      (bits->tenths err)))\n  (define target-error\n    (for/list ([alt-error (in-list target-errors)])\n      (for/list ([err (in-list alt-error)])\n        (bits->tenths err))))\n  (define end-error\n    (for/list ([err (in-list (car end-errors))])\n      (bits->tenths err)))\n\n  (define target-error-entries\n    (for/list ([i (in-naturals)]\n               [error-value (in-list target-error)])\n      (cons (format \"target~a\" (+ i 1)) error-value)))\n\n  (define error-entries\n    (list* (cons \"start\" start-error) (cons \"end\" end-error) target-error-entries))\n\n  (define ticks\n    (for/list ([var (in-list vars)]\n               [idx (in-naturals)]\n               [min-ordinal (in-list mins)]\n               [max-ordinal (in-list maxs)]\n               [repr (in-list (test-var-reprs test))]\n               ; We want to bail out since choose-ticks will crash otherwise\n               #:unless (equal? min-ordinal max-ordinal))\n      (define min-val (repr->real ((representation-ordinal->repr repr) min-ordinal) repr))\n      (define max-val (repr->real ((representation-ordinal->repr repr) max-ordinal) repr))\n      (define real-ticks (choose-ticks min-val max-val repr))\n      (for/list ([val (in-list real-ticks)])\n        (define tick-str\n          (if (or (= val 0) (< 0.01 (abs val) 100))\n              (~r (exact->inexact val) #:precision 4)\n              (string-replace (~r val #:notation 'exponential #:precision 0) \"1e\" \"e\")))\n        (list tick-str (real->ordinal val repr)))))\n\n  (define splitpoints (hash-ref (car (hash-ref backend 'end)) 'splitpoints))\n\n  ; NOTE ordinals currently remain numeric; if we need to detect truncation\n  ; in JSON, we can switch to string encoding.\n  ; Fields:\n  ;   bits: int representing the maximum possible bits of error\n  ;   vars: array of n string variable names\n  ;   points: array of size m like [[x0, x1, ..., xn], ...] where x0 etc.\n  ;     are ordinals representing the real input values\n  ;   error: JSON dictionary where keys are {start, end, target1, ..., targetn}.\n  ;          Each key's value holds an array like [y0, ..., ym] where y0 etc are\n  ;          bits of error for the output on each point\n  ;   ticks_by_varidx: array of size n where each entry is [label, ordinal] pairs\n  ;   splitpoints_by_varidx: array of size n where each entry has ordinal splitpoints\n  `#hasheq((bits . ,bits)\n           (vars . ,(map symbol->string vars))\n           (points . ,ordinal-points)\n           (error . ,error-entries)\n           (ticks_by_varidx . ,ticks)\n           (splitpoints_by_varidx . ,splitpoints)))\n;;  Repr conversions\n\n(define (ordinal->real x repr)\n  (repr->real ((representation-ordinal->repr repr) x) repr))\n\n(define (real->ordinal x repr)\n  ((representation-repr->ordinal repr) (real->repr x repr)))\n\n(define (first-power10 min max repr)\n  (define value\n    (cond\n      [(negative? max) (- (expt 10 (ceiling (/ (log (- max)) (log 10)))))]\n      [else (expt 10 (floor (/ (log max) (log 10))))]))\n  (if (<= value min) #f value))\n\n(define (clamp x lo hi)\n  (min hi (max x lo)))\n\n(define (choose-between min max number repr)\n  ; Returns a given number of ticks, roughly evenly spaced, between min and max\n  ; For any tick, n divisions below max, the tick is an ordinal corresponding to:\n  ;  (a) a power of 10 between n and (n + ε) divisions below max where ε is some tolerance, or\n  ;  (b) a value, n divisions below max\n  (define sub-range (round (/ (- max min) (add1 number))))\n  (define (near x n)\n    (and (<= x n) (<= (abs (/ (- x n) sub-range)) 0.2))) ; <- tolerance\n  (for/list ([itr (in-range 1 (add1 number))])\n    (define power10\n      (first-power10 (ordinal->real (clamp (- max (* (add1 itr) sub-range)) min max) repr)\n                     (ordinal->real (clamp (- max (* itr sub-range)) min max) repr)\n                     repr))\n    (if (and power10 (near (real->ordinal power10 repr) (- max (* itr sub-range))))\n        (real->ordinal power10 repr)\n        (- max (* itr sub-range)))))\n\n(define (pick-spaced-ordinals necessary min max number repr)\n  (define sub-range (/ (- max min) number)) ; size of a division on the ordinal range\n  (define necessary* ; filter out necessary points that are too close\n    (let loop ([necessary necessary])\n      (cond\n        [(< (length necessary) 2) necessary]\n        [(< (- (cadr necessary) (car necessary)) sub-range) (loop (cdr necessary))]\n        [else (cons (car necessary) (loop (cdr necessary)))])))\n  (define all\n    (let loop ([necessary necessary*]\n               [min* min]\n               [start 0])\n      (cond\n        [(>= start number) '()]\n        [(empty? necessary) (choose-between min* max (- number start) repr)]\n        [else\n         (define idx\n           (for/first ([i (in-range number)]\n                       #:when (<= (- (first necessary) (+ min (* i sub-range))) sub-range))\n             i))\n         (append (choose-between min* (first necessary) (- idx start) repr)\n                 (loop (cdr necessary) (first necessary) (add1 idx)))])))\n  (sort (append all necessary*) <))\n\n(define (choose-ticks min max repr)\n  (define tick-count 13)\n  (define necessary\n    (map (curryr real->ordinal repr) (filter (λ (x) (<= min x max)) (list min -1.0 0.0 1.0 max))))\n  (map (curryr ordinal->real repr)\n       (pick-spaced-ordinals necessary\n                             (real->ordinal min repr)\n                             (real->ordinal max repr)\n                             tick-count\n                             repr)))\n\n(define/contract (regime-info altn)\n  (-> alt? (or/c (listof sp?) #f))\n  (let loop ([altn altn])\n    (match altn\n      [(alt _ `(regimes ,splitpoints) prevs) splitpoints]\n      [(alt _ _ (list)) #f]\n      [(alt _ _ (list prev _ ...)) (loop prev)])))\n\n(define (regime-splitpoints altn)\n  (map sp-point (drop-right (regime-info altn) 1)))\n\n(define/contract (regime-var altn)\n  (-> alt? (or/c expr? #f))\n  (define info (regime-info altn))\n  (and info (sp-bexpr (car info))))\n"
  },
  {
    "path": "src/reports/resources/404.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Page Not Found</title>\n  <link rel='stylesheet' type='text/css' href='/report.css'>\n</head>\n<body>\n  <header>\n    <h1>Page Not Found</h1>\n    <img src=\"/logo-car.png\" />\n    <nav>\n      <ul>\n        <li><a href=\"/\">Main page</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    You're looking for a page that does not exist. <a href=\"/\">Turn back</a>!\n  </p>\n</body>\n</html>\n"
  },
  {
    "path": "src/reports/resources/demo.js",
    "content": "CONSTANTS = {\"PI\": \"real\", \"E\": \"real\", \"TRUE\": \"bool\", \"FALSE\": \"bool\"}\n\nFUNCTIONS = {}\n\n\"+ - * / pow copysign fdim fmin fmax fmod hypot remainder atan2\".split(\" \").forEach(function(op) {\n    FUNCTIONS[op] = [[\"real\", \"real\"], \"real\"];\n});\n(\"fabs sqrt exp log sin cos tan asin acos atan sinh cosh tanh asinh acosh atanh \" +\n \"cbrt ceil erf erfc exp2 expm1 floor lgamma log10 log1p log2 logb rint \" + \n \"round tgamma trunc\").split(\" \").forEach(function(op) {\n     FUNCTIONS[op] = [[\"real\"], \"real\"];\n});\nFUNCTIONS[\"fma\"] = [[\"real\", \"real\", \"real\"], \"real\"];\n\"< > == != <= >=\".split(\" \").forEach(function(op) {\n    FUNCTIONS[op] = [[\"real\", \"real\"], \"bool\"];\n});\n\"and or\".split(\" \").forEach(function(op) {\n    FUNCTIONS[op] = [[\"bool\", \"bool\"], \"bool\"];\n});\n\nSECRETFUNCTIONS = {\"^\": \"pow\", \"**\": \"pow\", \"abs\": \"fabs\", \"min\": \"fmin\", \"max\": \"fmax\", \"mod\": \"fmod\"}\n\nfunction tree_errors(tree, expected) /* tree -> list */ {\n    var messages = [];\n    var names = [];\n\n    var rtype = bottom_up(tree, function(node, path, parent) {\n        switch(node.type) {\n        case \"ConstantNode\":\n            if ([\"number\", \"boolean\"].indexOf(node.valueType) === -1) {\n                messages.push(\"Constants that are \" + node.valueType + \"s not supported.\");\n            }\n            return ({\"number\": \"real\", \"boolean\": \"bool\"})[node.valueType] || \"real\";\n        case \"FunctionNode\":\n            node.name = SECRETFUNCTIONS[node.name] || node.name;\n            if (!FUNCTIONS[node.name]) {\n                messages.push(\"Function <code>\" + node.name + \"</code> unsupported.\");\n            } else if (FUNCTIONS[node.name][0].length !== node.args.length) {\n                messages.push(\"Function <code>\" + node.name + \"</code> expects \" +\n                              FUNCTIONS[node.name][0].length + \" arguments\");\n            } else if (\"\"+extract(node.args) !== \"\"+FUNCTIONS[node.name][0]) {\n                messages.push(\"Function <code>\" + node.name + \"</code>\" +\n                              \" expects arguments of type \" +\n                              FUNCTIONS[node.name][0].join(\", \") +\n                              \", got \" + extract(node.args).join(\", \"));\n            }\n            return (FUNCTIONS[node.name] || [[], \"real\"])[1];\n        case \"OperatorNode\":\n            node.op = SECRETFUNCTIONS[node.op] || node.op;\n            if (!FUNCTIONS[node.op]) {\n                messages.push(\"Operator <code>\" + node.op + \"</code> unsupported.\");\n            } else if (FUNCTIONS[node.op][0].length !== node.args.length &&\n                       !(node.op === \"-\" && node.args.length === 1)) {\n                messages.push(\"Operator <code>\" + node.op + \"</code> expects \" +\n                              FUNCTIONS[node.op][0].length + \" arguments\");\n            } else if (\"\"+extract(node.args) !== \"\"+FUNCTIONS[node.op][0] &&\n                       !(node.op === \"-\" && \"\"+extract(node.args) === \"real\") &&\n                       !(is_comparison(node.op) /* TODO improve */)) {\n                messages.push(\"Operator <code>\" + node.op + \"</code>\" +\n                              \" expects arguments of type \" +\n                              FUNCTIONS[node.op][0].join(\", \") +\n                              \", got \" + extract(node.args).join(\", \"));\n            }\n            return (FUNCTIONS[node.op] || [[], \"real\"])[1];\n        case \"SymbolNode\":\n            if (!CONSTANTS[node.name]) {\n                names.push(node.name);\n                return \"real\";\n            } else {\n                return CONSTANTS[node.name];\n            }\n        case \"ConditionalNode\":\n            if (node.condition.res !== \"bool\") {\n                messages.push(\"Conditional has type \" + node.condition.res + \" instead of bool\");\n            }\n            if (node.trueExpr.res !== node.falseExpr.res) {\n                messages.push(\"Conditional branches have different types \" + node.trueExpr.res + \" and \" + node.falseExpr.res);\n            }\n            return node.trueExpr.res;\n        case \"BlockNode\":\n            for (var i = 0; i < tree.blocks.length - 1; i++) {\n                stmt = tree.blocks[i].node;\n                if (stmt.type != \"AssignmentNode\")\n                    messages.push(\"Expected an assignment statement before a semicolon: \" + stmt);\n            }\n            return node.blocks[node.blocks.length - 1].node.res;\n        default:\n            messages.push(\"Unsupported syntax; found unexpected <code>\" + node.type + \"</code>.\")\n            return \"real\";\n        }\n    }).res;\n\n    if (rtype !== expected) {\n        messages.push(\"Expected an expression of type \" + expected + \", got \" + rtype);\n    }\n\n    return messages;\n}\n\nfunction bottom_up(tree, cb) {\n    if (tree.args) {\n        tree.args = tree.args.map(function(node) {return bottom_up(node, cb)});\n    } else if (tree.condition) {\n        tree.condition = bottom_up(tree.condition, cb);\n        tree.trueExpr = bottom_up(tree.trueExpr, cb);\n        tree.falseExpr = bottom_up(tree.falseExpr, cb);\n    } else if (tree.blocks) {\n        for (var i = 0; i < tree.blocks.length - 1; i++) {\n            stmt = tree.blocks[i].node;\n            if (stmt.type != \"AssignmentNode\")\n                throw SyntaxError(\"Expected an assignment statement before a semicolon: \" + stmt);\n            stmt.expr = bottom_up(stmt.expr, cb);\n        }\n\n        tree.blocks[tree.blocks.length - 1].node = bottom_up(tree.blocks[tree.blocks.length - 1].node, cb);\n    }\n\n    tree.res = cb(tree);\n    return tree;\n}\n\nfunction extract(args) {\n    return args.map(function(n) { return n.res });\n}\n\nfunction dump_fpcore(formula) {\n    var tree = math.parse(formula);\n\n    var names = [];\n    var body = dump_tree(tree, names);\n    var precondition = get_precondition_from_input_ranges(formula);\n\n    var dnames = [];\n    for (var i = 0; i < names.length; i++) {\n        if (dnames.indexOf(names[i]) === -1) dnames.push(names[i]);\n    }\n\n    var name = formula.replace(\"\\\\\", \"\\\\\\\\\").replace(\"\\\"\", \"\\\\\\\"\");\n    var fpcore = \"(FPCore (\" + dnames.join(\" \") + \")\\n  :name \\\"\" + name + \"\\\"\";\n    if (precondition) fpcore += \"\\n  :pre \" + precondition;\n\n    return fpcore + \"\\n  \"  + body + \")\";\n}\n\nfunction is_comparison(name) {\n    return [\"==\", \"!=\", \"<\", \">\", \"<=\", \">=\"].indexOf(name) !== -1;\n}\n\nfunction flatten_comparisons(node) {\n    var terms = [];\n    (function collect_terms(node) {\n        if (node.type == \"OperatorNode\" && is_comparison(node.op)) {\n            collect_terms(node.args[0]);\n            collect_terms(node.args[1]);\n        } else {\n            terms.push(node.res);\n        }\n    })(node);\n    var conjuncts = [];\n    var iters = 0;\n    (function do_flatten(node) {\n        if (node.type == \"OperatorNode\" && is_comparison(node.op)) {\n            do_flatten(node.args[0]);\n            var i = iters++; // save old value and increment it\n            var prev = conjuncts[conjuncts.length - 1];\n            if (prev && prev[0] == node.op && prev[2] == terms[i]) {\n                prev.push(terms[i + 1]);\n            } else {\n                conjuncts.push([node.op, terms[i], terms[i+1]]);\n            }\n            do_flatten(node.args[1]);\n        }\n    })(node);\n    var comparisons = [];\n    for (var i = 0; i < conjuncts.length; i++) {\n        comparisons.push(\"(\" + conjuncts[i].join(\" \") + \")\");\n    }\n    if (comparisons.length == 0) {\n        return \"TRUE\";\n    } else if (comparisons.length == 1) {\n        return comparisons[0];\n    } else {\n        return \"(and \" + comparisons.join(\" \") + \")\";\n    }\n}\n\nfunction dump_tree(tree, names) {\n    function rec(node, bound) {\n        switch(node.type) {\n        case \"ConstantNode\":\n            node.res = \"\" + node.value;\n            return node;\n        case \"FunctionNode\":\n            node.args = node.args.map(function(n) { return rec(n, bound) });\n            node.name = SECRETFUNCTIONS[node.name] || node.name;\n            node.res = \"(\" + node.name + \" \" + extract(node.args).join(\" \") + \")\";\n            return node;\n        case \"OperatorNode\":\n            node.args = node.args.map(function(n) { return rec(n, bound) });\n            node.op = SECRETFUNCTIONS[node.op] || node.op;\n            if (is_comparison(node.op)) {\n                node.res = flatten_comparisons(node);\n            } else {\n                node.res = \"(\" + node.op + \" \" + extract(node.args).join(\" \") + \")\";\n            }\n            return node;\n        case \"SymbolNode\":\n            if (!CONSTANTS[node.name] && bound.indexOf(node.name) == -1)\n                names.push(node.name);\n            node.res = node.name;\n            return node;\n        case \"ConditionalNode\":\n            node.condition = rec(node.condition, bound);\n            node.trueExpr  = rec(node.trueExpr, bound);\n            node.falseExpr = rec(node.falseExpr, bound);\n            node.res = \"(if \" + node.condition.res + \n                       \" \" + node.trueExpr.res + \n                       \" \" + node.falseExpr.res + \")\";\n            return node;\n        case \"BlockNode\":\n            str = \"\";\n            for (var i = 0; i < node.blocks.length - 1; i++) {\n                stmt = node.blocks[i].node;\n                if (stmt.type != \"AssignmentNode\")\n                    throw SyntaxError(\"Expected an assignment statement before a semicolon: \" + stmt);\n\n                rec(stmt.expr, bound);\n                str += (\"(let ((\" + stmt.name + \" \" + stmt.expr.res + \")) \");\n\n                if (bound.indexOf(stmt.name) == -1)\n                    bound.push(stmt.name);\n            }\n\n            rec(node.blocks[node.blocks.length - 1].node, bound);\n            node.res = str + node.blocks[node.blocks.length - 1].node.res + \")\".repeat(node.blocks.length - 1);\n            return node;\n        default:\n            throw SyntaxError(\"Invalid tree! \" + node);\n        }\n    }\n\n    rec(tree, []);\n    return tree.res;\n}\n\nfunction get_unused_var_warnings(tree) {\n    let unused = [];\n    bottom_up(tree, function(node) {\n        switch(node.type) {\n        case \"ConstantNode\":\n            return new Set();\n        case \"FunctionNode\":\n        case \"OperatorNode\":\n            used = new Set();\n            extract(node.args).forEach(function(s) {\n                s.forEach(function(n) { used.add(n); });\n            })\n            return used;\n        case \"SymbolNode\":\n            if (!CONSTANTS[node.name])\n                return new Set([node.name]);\n            else\n                return new Set();\n        case \"ConditionalNode\":\n            usedCond = node.condition.res;\n            usedTrue  = node.trueExpr.res;\n            usedFalse = node.falseExpr.res;\n            return new Set([...usedCond, ...usedTrue, ...usedFalse])\n        case \"BlockNode\":\n            bound = [];\n            usedInAssigns = [];\n            for (var i = 0; i < node.blocks.length - 1; i++) {\n                stmt = node.blocks[i].node;\n                if (stmt.type != \"AssignmentNode\")\n                    throw SyntaxError(\"Expected an assignment statement before a semicolon: \" + stmt);\n\n                bound.push(stmt.name);\n                usedInAssigns.push(stmt.expr.res);\n            }\n\n            // Assume each assignment is of the form:\n            //  <assign> ::= <name> = <val>; <body>.\n            // Then\n            //  (i)  <name> is unused if <name> is not in Used(<body>),\n            //  (ii) Used(<expr>) = Used(<val>) U (Used(<body>) \\ { <name> })\n            // Clearly, the assumption is slightly wrong, but this\n            // tells us we just walk backwards checking condition (i)\n            // and updating the used set with (ii).\n            used = node.blocks[node.blocks.length - 1].node.res;\n            for (var i = node.blocks.length - 2; i >= 0; i--) {\n                if (!used.has(bound[i]))\n                    unused.push(\"UnboundVariable: \" + bound[i]);\n                used.delete(bound[i]);\n                used = new Set([...used, ...usedInAssigns[i]]);\n            }\n\n            return used\n        default:\n            throw SyntaxError(\"Invalid tree!\");\n        }\n    });\n\n    return unused;\n}\n\nfunction get_errors() {\n    var tree, errors = [];\n    let parse_fail = false\n    for (var i = 0; i < arguments.length; i++) {\n        try {\n            tree = math.parse(arguments[i][0]);\n            errors = errors.concat(tree_errors(tree, arguments[i][1]));\n        } catch (e) {\n            parse_fail = true\n            errors.push(\"\" + e);\n        }\n    }\n    if (!parse_fail) {\n        const input = document.querySelector(\"[name=formula-math]\")\n        errors = [...errors, ...get_varnames_mathjs(input.value).map(varname => get_input_range_errors(KNOWN_INPUT_RANGES[varname], true).map(s => \"RangeError: \" + varname + \": \" + s)).flat()]\n    }\n    return errors;\n}\n\nfunction get_warnings() {\n    try {\n        const input = document.querySelector(\"[name=formula-math]\")\n        rangeWarnings = get_varnames_mathjs(input.value).map(varname => get_input_range_warnings(KNOWN_INPUT_RANGES[varname]).map(s => \"RangeWarning: \" + varname + \": \" + s)).flat();\n        unusedWarnings = get_unused_var_warnings(math.parse(input.value))\n        return rangeWarnings.concat(unusedWarnings);\n    } catch (e) {\n        return []\n    }\n}\n\nfunction check_errors() {\n    var input = document.querySelector(\"[name=formula-math]\");\n    \n    var errors = get_errors([input.value, \"real\"]);\n    var warnings = get_warnings();\n\n    document.getElementById(\"errors\").innerHTML = errors.length == 0 || !input.value ? \"\" : \"<li>\" + errors.join(\"</li><li>\") + \"</li>\";\n    document.getElementById(\"warnings\").innerHTML = warnings.length == 0 || !input.value ? \"\" : \"<li>\" + warnings.join(\"</li><li>\") + \"</li>\";\n    \n    if (!input.value) {\n        return false;\n    } else if (errors.length > 0) {\n        return false;\n    } else {\n        return true;\n    }\n}\n\nfunction hide_extra_fields() {\n    var $extra = document.querySelector(\"#formula .extra-fields\");\n    var inputs = $extra.querySelectorAll(\"input, select\");\n    for (var i = 0; i < inputs.length; i++) {\n        if (inputs[i].tagName == \"INPUT\" && inputs[i].value) return;\n        if (inputs[i].tagName == \"SELECT\" && inputs[i].selectedIndex) return;\n    }\n    var $a = document.createElement(\"a\");\n    $a.textContent = \"Advanced options »\";\n    $a.classList.add(\"show-extra\");\n    $extra.parentNode.insertBefore($a, $extra.nextSibling);\n    $a.addEventListener(\"click\", function() {\n        $extra.style.display = \"block\";\n        $a.style.display = \"none\";\n    });\n}\n\nvar STATE = null;\n\nfunction Form(form) {\n    this.form = form;\n\n    this.fpcore = form.querySelector(\"[name=formula]\");\n    this.math = form.querySelector(\"[name=formula-math]\");\n    this.extra_fields = form.querySelector(\".extra-fields\");\n\n    this.math_doc = document.getElementById(\"mathjs-instructions\");\n    this.lisp_doc = document.getElementById(\"lisp-instructions\");\n\n    this.input_ranges = document.getElementById(\"input-ranges\");\n    this.extra_links = form.querySelector(\".extra-links\");\n    this.button = form.querySelector(\"[type=submit]\")\n}\n\nfunction get_precondition_from_input_ranges(formula) {\n    const checks = get_varnames_mathjs(formula)\n    .map(name => ([name, KNOWN_INPUT_RANGES[name]]))\n    .filter(([_, range]) => get_input_range_errors(range).length == 0)\n    .map(([name, [start, end]]) => `(<= ${start} ${name} ${end})`)\n    .join(' ')\n    return checks.length == 0 ? \"\" : `(and ${checks})`\n}\n\nfunction setup_state(state, form) {\n    window.STATE = state;\n    form.fpcore.removeAttribute(\"disabled\");\n    form.math.removeAttribute(\"disabled\");\n\n    document.querySelector('#use-fpcore').onclick = function(evt) {\n        if (form.math.value) {\n            if (!check_errors()) {\n                alert(\"Please fix all errors before attempting to use FPCore input.\")\n                return evt.preventDefault();\n            }\n            var fpcore = dump_fpcore(form.math.value)\n            form.fpcore.value = fpcore;\n        }\n        setup_state(\"fpcore\", form);\n    }\n    document.querySelector('#show-example').onclick = function (evt) {\n        form.math.value = \"sqrt(x + 1) - sqrt(x)\"\n        CHECK_ERRORS_AND_DRAW_RANGES()\n        document.querySelector('#x_low').value = \"0\";\n        document.querySelector('#x_high').value = \"1.79e308\";\n        window.KNOWN_INPUT_RANGES['x'] = [0, 1.79e308]\n        update_run_button_mathjs(form)\n    }\n\n    if (state == \"math\") {\n        form.fpcore.style.display = \"none\";\n        form.math.style.display = \"block\";\n        form.input_ranges.style.display = \"table\";\n        document.querySelector('#options').style.display = 'block';\n        document.querySelector(\"#lisp-instructions\").style.display = \"none\";\n        document.querySelector(\"#mathjs-instructions\").style.display = \"block\";\n        update_run_button_mathjs(form)\n    } else {\n        document.querySelector('#options').style.display = 'none';\n        form.fpcore.style.display = \"block\";\n        form.math.style.display = \"none\";\n        form.input_ranges.style.display = \"none\";\n        document.querySelector(\"#lisp-instructions\").style.display = \"block\";\n        document.querySelector(\"#mathjs-instructions\").style.display = \"none\";\n        form.button.classList.remove(\"hidden\");\n        form.button.removeAttribute(\"disabled\");\n    }\n}\n\nfunction get_varnames_mathjs(mathjs_text) {\n    const names = []\n    dump_tree(math.parse(mathjs_text), names)\n    var dnames = [];\n    for (var i = 0; i < names.length; i++) {\n        if (dnames.indexOf(names[i]) === -1) dnames.push(names[i]);\n    }\n    return dnames\n}\n\nfunction update_run_button_mathjs(form) {\n    function no_range_errors([low, high] = [undefined, undefined]) {\n        return low !== '' && high !== '' && !isNaN(Number(low)) && !isNaN(Number(high)) && Number(low) <= Number(high) \n    }\n    const button = document.querySelector('#run_herbie')\n    let varnames;\n    try {\n        varnames = get_varnames_mathjs(form.math.value)\n    } catch (e) {\n        console.log(\"Couldn't get varnames:\", e)\n        button.setAttribute('disabled', 'true')\n        return;\n    }\n    if (form.math.value && varnames.every(varname => no_range_errors(KNOWN_INPUT_RANGES[varname]))) {\n        button.removeAttribute('disabled')\n    } else {\n        console.log('There are still range errors.', )\n        button.setAttribute('disabled', 'true')\n    }\n}\n\nfunction get_input_range_errors([low, high] = [undefined, undefined], empty_if_missing=false) {\n    if ((low === undefined || low === '') || (high === undefined || high === '')) return empty_if_missing ? [] : ['input missing']\n    const A = []\n    if (!(low === undefined || low === '') && isNaN(Number(low))) {\n        A.push(`The start of the range (${low}) is not a number.`)\n    } else if (!Number.isFinite(Number(low))) {\n        A.push(`The start of the range (${low}) is outside the floating point range.`)\n    }\n\n    if (!(high === undefined || high === '') && isNaN(Number(high))) {\n        A.push(`The end of the range (${high}) is not a number.`)\n    } else if (!Number.isFinite(Number(high))) {\n        A.push(`The end of the range (${high}) is outside the floating point range.`)\n    }\n\n    if (Number(low) > Number(high)) A.push(`The start of the range is higher than the end.`)\n    \n    return A\n}\n\nfunction get_input_range_warnings([low, high] = [undefined, undefined]) {\n    if ((low === undefined || low === '') || (high === undefined || high === '')) return []\n    const A = []\n    if (Number(low) == Number(high)) A.push(`This is a single point.`)\n    return A\n}\n\nfunction onload() {\n\n    // Only records ranges the user intentionally set.\n    window.KNOWN_INPUT_RANGES = { /* \"x\" : [-1, 1] */ }\n\n    function hide(selector) { document.querySelector(selector).style.display = 'none' }\n    hide('#formula textarea')\n\n    var form = new Form(document.getElementById(\"formula\"));\n\n    /* STATE represents whether we are working with the mathjs + precondition inputs or the fpcore input. */\n    const params = new URLSearchParams(window.location.search);\n    if (params.get('fpcore')) {\n        form.fpcore.value = params.get('fpcore');\n        STATE = \"fpcore\";\n    }\n    else if (form.math.value) STATE = \"math\";\n    else if (form.fpcore.value) STATE = \"fpcore\";\n    else STATE = \"math\";\n\n    setup_state(STATE, form);\n\n    function html(string) {\n        const t = document.createElement('template');\n        t.innerHTML = string;\n        return t.content;\n    }\n\n    function range_inputs(varname) {\n        const [low, high] = KNOWN_INPUT_RANGES[varname] || [undefined, undefined]\n        \n        const low_id = `${varname}_low`\n        const high_id = `${varname}_high`\n        const default_options = ['-1.79e308', '-1e9', '-1e3', '-1', '0', '1', '1e3', '1e9', '1.79e308']\n        function input_view(id, value, placeholder) {\n            return `\n                <div id=\"${id}_dropdown\" class=\"dropdown\">\n                    <input id=\"${id}\" class=\"input-range\" autocomplete=\"off\" placeholder=\"${placeholder}\" ${value ? `value=\"${value}\"` : ``}>\n                    <div class=\"dropdown-content\">\n                        ${default_options.map(s => `<div>${s}</div>`).join('')}\n                    </div>\n                </div>\n            `\n        }\n        const error_msgs = get_input_range_errors(KNOWN_INPUT_RANGES[varname], true)\n        const warning_msgs = get_warnings(KNOWN_INPUT_RANGES[varname])\n        const view = html(`\n                <tr id=\"${varname}_input\" class=\"input-range-view\">\n                <td class=\"varname\">\n                    ${varname}:\n                </td>\n                <td>${input_view(low_id, low, '-1e3')}</td> <td>to</td> <td>${input_view(high_id, high, '1e3')}</td>\n                </tr>`)\n\n        const low_el = view.querySelector(`#${low_id}`)\n        \n\n\n        function show_errors(root=document) {\n            root.querySelectorAll(`#${varname}_input input`).forEach(input => {\n                input.style['background-color'] = input.value === '' ? '#a6ffff3d' : 'initial'\n            })\n        }\n        function set_input_range({ low, high }) {\n            if (low !== undefined) low_el.value = low\n            if (high !== undefined) high_el.value = high\n            if (!KNOWN_INPUT_RANGES[varname]) { KNOWN_INPUT_RANGES[varname] = [undefined, undefined] }\n            const [old_low, old_high] = KNOWN_INPUT_RANGES[varname]\n            KNOWN_INPUT_RANGES[varname] = [low ?? old_low, high ?? old_high]\n            check_errors()\n            show_errors()\n            update_run_button_mathjs(form)\n        }\n        low_el.addEventListener('input', () => set_input_range({ low: low_el.value }))\n        view.querySelectorAll(`#${low_id}_dropdown .dropdown-content div`).forEach((e, i) => {\n            const handler = () => set_input_range({ low: e.textContent })\n            e.addEventListener('click', handler)\n            e.addEventListener('pointerdown', handler)\n        })\n        \n        const high_el = view.querySelector(`#${high_id}`)\n        high_el.addEventListener('input', () => set_input_range({ high: high_el.value }))\n        view.querySelectorAll(`#${high_id}_dropdown .dropdown-content div`).forEach((e, i) => {\n            const handler = () => set_input_range({ high: e.textContent })\n            e.addEventListener('click', handler)\n            e.addEventListener('pointerdown', handler)\n        })\n\n        check_errors()\n        show_errors(view)\n\n        return view\n    }\n\n    const range_div = document.createElement('DIV')\n    document.querySelector('#formula').appendChild(range_div)\n\n    \n\n    \n    update_run_button_mathjs(form)\n\n    let current_timeout = undefined  // can be used to debounce the input box\n    function check_errors_and_draw_ranges() {\n        if (form.math.value === \"\") document.querySelector('#input-ranges').innerHTML=''\n        let varnames;\n        try {\n            varnames = get_varnames_mathjs(form.math.value)\n        } catch (e) {\n            check_errors()\n            return\n        }\n        const range_div = document.querySelector('#input-ranges')\n        range_div.replaceChildren(...varnames.map(range_inputs))\n    }\n    // Expose the updater so generated range callbacks can trigger a refresh.\n    CHECK_ERRORS_AND_DRAW_RANGES = check_errors_and_draw_ranges\n    check_errors_and_draw_ranges()\n    \n    form.math.addEventListener(\"input\", function () {\n        clearTimeout(current_timeout)\n        current_timeout = setTimeout(check_errors_and_draw_ranges, 400)\n        update_run_button_mathjs(form)\n    })\n    form.math.setAttribute('autocomplete', 'off')  // (because it hides the error output)\n\n    form.form.addEventListener(\"submit\", function(evt) {\n        var fpcore;\n        if (STATE != \"fpcore\") {\n            if (!check_errors()) return evt.preventDefault();\n            fpcore = dump_fpcore(form.math.value)\n        } else {\n            fpcore = form.fpcore.value;\n        }\n        console.log(STATE, fpcore);\n\n        var url = document.getElementById(\"formula\").getAttribute(\"data-progress\");\n        if (url) {\n            form.math.disabled = \"true\";\n            form.fpcore.disabled = \"true\";\n            ajax_submit(url, fpcore);\n            evt.preventDefault();\n            return false;\n        } else {\n            return true;\n        }\n    });\n}\n\nfunction get_progress(loc) {\n    var req2 = new XMLHttpRequest();\n    req2.open(\"GET\", loc);\n    req2.onreadystatechange = function() {\n        if (req2.readyState == 4) {\n            if (req2.status == 202) {\n                document.getElementById(\"progress\").textContent = req2.responseText;\n                const nums = document.getElementById(\"num-jobs\");\n                if (nums != null) {\n                    nums.textContent = req2.getResponseHeader(\"X-Job-Count\");\n                }\n                setTimeout(function() {get_progress(loc)}, 100);\n            } else if (req2.status == 201) {\n                var loc2 = req2.getResponseHeader(\"Location\");\n                var form = new Form(document.getElementById(\"formula\"));\n                form.math.removeAttribute(\"disabled\");\n                form.fpcore.removeAttribute(\"disabled\");\n                form.button.removeAttribute(\"disabled\");\n                window.location.href = loc2;\n            } else {\n                document.getElementById(\"errors\").innerHTML = req2.responseText;\n            }\n        }\n    }\n    req2.send();\n}\n\nfunction ajax_submit(url, lisp) {\n    document.getElementById(\"progress\").style.display = \"block\";\n    var req = new XMLHttpRequest();\n    req.open(\"POST\", url);\n    req.setRequestHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\n    req.onreadystatechange = function() {\n        if (req.readyState == 4) {\n            if (req.status == 201) {\n                var jobcount = req.getResponseHeader(\"X-Job-Count\");\n                var jobelt = document.getElementById(\"num-jobs\")\n                if (jobelt) jobelt.innerHTML = Math.max(jobcount - 1, 0);\n                var loc = req.getResponseHeader(\"Location\");\n                get_progress(loc);\n            } else {\n                document.getElementById(\"errors\").innerHTML = req.responseText;\n            }\n        }\n    }\n    var content = \"formula=\" + encodeURIComponent(lisp);\n    req.send(content);\n}\n\nwindow.addEventListener(\"load\", onload);\n"
  },
  {
    "path": "src/reports/resources/main.css",
    "content": "html {font-family: sans-serif; font-size: 15px; line-height: 1.2;}\n\nbody {min-width: 400px; max-width: 650px; margin: 3em auto;}\n\nh1, h2, h3 {letter-spacing: .125em; font-weight: 600; margin-top: 4em; }\nh1 {font-size: 18px; line-height: 1; margin-bottom: .5em;}\nh2 {font-size: 16px; line-height: 1.125; margin-bottom: .25em; clear: both;}\nh3 {font-size: 14px; line-height: 1.286; margin-bottom: .2em; clear: both;}\n\np, li, dd, blockquote, figcaption {\n  text-align: justify; -moz-hyphens: auto; -webkit-hyphens: auto; hyphens: auto;\n  margin: .5em 0;\n}\n\n.showcase { background: #ddd; padding: 1em; margin: 5em 0; clear: both;}\n.showcase figcaption {font-size: 14px; line-height: 1.1; margin-top: 2em;}\n.before-after { font-size: 24px; text-align: center; line-height: 1.5; }\n.before-after code { padding: 0 .5ex; display: block; }\n.before-after .before { color: darkred; }\n.before-after .after { color: darkgreen; }\n\nheader {margin: 0 0 4em 0;}\nheader h1 {margin: .5em 0 0 0; font-size: 16pt; text-align: center; }\nheader p {font-size: 16px; margin: .5em 0 0 0; text-align: center;}\nheader img {width: 250px; margin: 0 auto; display: block;}\n\n.tool-list { margin-left: 1em; }\n.tool-list dt {float: left; clear:left; margin-right: 1ex; font-weight: bold; }\n.tool-list dd {clear: right; margin-bottom: 1em;}\n\n.author-list {padding: 0; margin: .5em 1em 3em; }\n.author-list li {display: inline; margin: 0; white-space: nowrap;}\n.author-list li:after {content: \",\"}\n.author-list li:last-child:after {content: \"\"}\nsvg {margin: 0 auto; display: block;}\n\npre {padding-left: 2em; font-size: 16px; font-family: monospace;}\n\ndiv.column-container > div {width: 25%; float: left; padding: 0 4%}\ndiv.column-container > div > h3 {margin: auto 10px}\ndiv.column-container > div > ul {list-style: inside none; margin: 0; padding: 0;}\ndiv.column-container:after { content: \".\"; clear: both; display: block; visibility: hidden; height: 0; }\n.column-container + .showcase { margin-top: 4em; }\n\nul {padding-left: 1em;}\na {color: #2A6496; text-decoration: none}\na:hover {text-decoration: underline; color: #295785}\n\n#formula textarea, #formula input { width: 100%; font-size: 125%; background-color: white; border: 1px solid rgba(222, 229, 231, 1); border-radius: 2px; }\n#formula textarea { font-family: monospace; height: 7em; }\n#input-ranges { margin-top: .1em; }\n#input-ranges td {padding-top: .4em; }\n.extra-fields { margin-top: 1em; }\n.extra-links {\n    float: right; margin-top: .2em; cursor: pointer;\n}\n.extra-links a:after {\n     content: \"•\"; color: black; display: inline-block; padding: 0 1ex;\n}\n.extra-links a:last-child:after { content: \"»\"; padding-right: 0;}\n#formula .extra-fields label { display: inline-block; width: 20%; line-height: 3; }\n#formula .extra-fields input, .extra-fields select { width: 80%; font-size: 100%; }\n#errors li { color: #800; }\n#formula button[type=submit].hidden { visibility: hidden; height: 0; }\n#mathjs-instructions, #lis { margin-top: 3em;}\n#mathjs-instructions-test { width: 100%; font-size: 125%; }\ninput.input-range { width: auto !important; }\n.input-range-view { margin-top: 15px; margin-bottom: 15px; }\n.input-range-view .varname { font-size: 125%; }\n.dropdown { position: relative; display: inline-block; }\n.dropdown-content { \n    display: none; position: absolute; background-color: #f9f9f9; \n    min-width: 160px; box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);\n    z-index: 1; }\n.dropdown-content div { padding: 5px; }\n.dropdown-content div:hover {background-color: #f1f1f1}\n.dropdown-content:hover { display: block; }\n.dropdown:focus-within .dropdown-content { display: block; }\n#warnings li { color: #cc5a2a; }\n\n#crashed {\n    border: 3px solid #800;\n    background-color: #fdd;\n    font-size: 133%;\n    padding: 1em;\n}\n\n#progress {\n    font-size: 14px; font-family: sans-serif; background-color: #f1f1f1;\n    padding-left: 0; overflow: scroll; overflow-y: auto;\n}\n#num-jobs { font-weight: bold; }\n\n.function-list dt { font-weight: bold; float: left; width: 200px; clear: left; margin: 0 1em .5em 1em; }\n.function-list dd { clear: right; margin: 0; }\n.function-list dd:after { clear: both; height: 1px; display: block; content: \".\"; visibility: hidden; margin: 0;}\n\n.video { display: block; margin: auto; }\n.abstract { padding: 1em 3em; position: relative; }\n.abstract:before { content: \"“\"; font-size: 600%; position: absolute; top: 0; left: 0; font-family: serif; color: #ccc; }\n.abstract:after { content: \"”\"; font-size: 600%; position: absolute; bottom: -.5em; right: 0; font-family: serif; color: #ccc; }\n.paper-thumb { width: 30%; float: left; margin: 1em; }\n.paper-thumb img { width: 100%; border: 1px solid #ccc; }\n\n#news { list-style: none inside; padding: 0; position: relative; }\n#news li { margin-bottom: 12px; margin-left: 100px; }\n#news time {\n    font-weight: bold; text-align: right;\n    position: absolute; left: 0;\n    display: block; width: 90px;\n}\n#news time:after { content: \":\"; }\n#news .yearmark { border: 0; border-top: 1px solid #bbb; margin: 1em 0; width: 90px; }\n"
  },
  {
    "path": "src/reports/resources/report-page.js",
    "content": "/* The report page uses a dummy-React pattern, where every time the\n * page changes we regenerate the whole HTML content from scratch */\n\n// Here is the loaded data:\n\nvar compareAgainstURL = \"\"\nvar diffAgainstFields = {}\nvar otherJsonData = null\nvar resultsJsonData = null\n\nfunction update() {\n    const bodyNode = document.querySelector(\"body\");\n    bodyNode.replaceChildren.apply(bodyNode, buildBody(resultsJsonData, otherJsonData));\n}\n\nclass DeferredCurveCache {\n    constructor(readTests) {\n        this.readTests = readTests;\n        this.key = null;\n        this.curve = null;\n        this.pending = false;\n    }\n\n    currentKey() {\n        return getCurveCacheKey(this.readTests());\n    }\n\n    get() {\n        this.ensure();\n        const key = this.currentKey();\n        return this.key === key ? this.curve : null;\n    }\n\n    ensure() {\n        const key = this.currentKey();\n        if (this.key === key || this.pending) return;\n        this.pending = true;\n        setTimeout(() => {\n            this.key = this.currentKey();\n            this.curve = calculateMergedCostAccuracy(this.readTests());\n            this.pending = false;\n            update();\n        }, 0);\n    }\n}\n\n// Here is the UI state:\n\nconst filterNames = {\n    \"imp-start\": \"Improved start\",\n    \"apx-start\": \"Approximate start\",\n    \"uni-start\": \"Regressed from start\",\n    \"ex-start\": \"Exact start\",\n    \"eq-start\": \"Equal start\",\n    \"lt-start\": \"Less than start\",\n    \"gt-target\": \"Greater than target\",\n    \"gt-start\": \"Greater than start\",\n    \"eq-target\": \"Equal to target\",\n    \"lt-target\": \"Less than target\",\n    \"error\": \"Error\",\n    \"timeout\": \"Timeout\",\n    \"crash\": \"Crash\",\n}\nvar filterState = Object.fromEntries(Object.keys(filterNames).map(k => [k, true]));\n\nconst filterGroups = {\n    improved: [\n        \"ex-start\", \"eq-start\", \"eq-target\",\n        \"imp-start\", \"gt-target\", \"gt-start\",\n    ],\n    unchanged: [\n        \"lt-target\", \"apx-start\", \"error\",\n    ],\n    regressed: [\n        \"uni-start\", \"lt-start\", \"timeout\", \"crash\",\n    ],\n};\nvar filterGroupState = Object.fromEntries(Object.keys(filterGroups).map(k => [k, true]));\n\nconst radioStates = {\n    output: { title: \"Output Expression\", tolerance: false, },\n    startAcc: { title: \"Input Accuracy\", tolerance: \"%\", },\n    endAcc: { title: \"Output Accuracy\", tolerance: \"%\", },\n    targetAcc: { title: \"Target Accuracy\", tolerance: \"%\", },\n    time: { title: \"Running Time\", tolerance: \"s\", },\n}\nlet radioState = null;\n\n// Controlling the diff process\nvar filterTolerance = 1;\nvar hideDirtyEqual = true\n\n// Collapsable <details> elements\nvar showFilterDetails = false;\nvar showCompareDetails = false;\n\n\nvar filterBySuite = \"\"\nvar filterByWarning = \"\"\n\nvar sortState = {\n    key: \"name\",\n    dir: true, // true = descending, false = ascending\n}\n\n// Next are various strings used in the UI\n\nconst tempXY_A = \"Output vs Input Accuracy\"\nconst tempXY_B = \"Each point represents a Herbie run below. Its horizontal position shows initial accuracy, and vertical position shows final accuracy. Points above the line are improved by Herbie.\"\n\nconst tempPareto_A = \"Accuracy vs Speed\"\nconst tempPareto_B = \"A joint speed-accuracy pareto curve. Accuracy is on the vertical axis, speed is on the horizontal axis. Up and to the right is better. The initial program is shown by the red square.\"\n\nconst resultHelpText = `Color key:\n    Green: improved accuracy\n    Light green: no initial error\n    Orange: no accuracy change\n    Red: accuracy worsened\n    Gray: timeout\n    Dark Gray: error`\nconst targetHelpText = `Color key:\n    Dark green: better than target\n    Green: matched target\n    Orange: improved but did not match target\n    Yellow: no accuracy change\n    `\n\n// Helper functions of various sorts\n\nfunction Element(tagname, props, children) {\n    if (children === undefined) { children = props; props = {}; }\n\n    var $elt = document.createElement(tagname);\n    for (var i in props) if (props.hasOwnProperty(i)) $elt[i] = props[i];\n\n    function addAll(c) {\n        if (!c) return;\n        else if (Array.isArray(c)) c.map(addAll);\n        else if (typeof c == \"string\") $elt.appendChild(document.createTextNode(c))\n        else if (c instanceof Node) $elt.appendChild(c);\n        else {\n            console.error(\"Not an element: \", c);\n            throw \"Invalid element!\"\n        }\n    }\n    addAll(children);\n    return $elt;\n}\n\nfunction calculatePercent(decimal) {\n    return ((100 - (100 * (decimal)))).toFixed(1)\n}\n\nfunction formatTime(ms) {\n    if (ms > 60_000) {\n        return (ms / 60_000).toFixed(1) + \"min\"\n    } else {\n        return (ms / 1000).toFixed(1) + \"s\"\n    }\n}\n\nfunction calculateSpeedup(mergedCostAccuracy) {\n    const initial_accuracy = mergedCostAccuracy[0][1]\n    const frontier = mergedCostAccuracy[1]\n    for (const point of [...frontier].reverse()) {\n        if (point[1] > initial_accuracy) {\n            if (typeof point[0] == 'number') {\n                return point[0].toFixed(1) + \"×\";\n            }\n            else {\n                return point[0];\n            }\n        }\n    }\n}\n\nfunction paretoUnion(curve1, curve2) {\n    const curve1Length = curve1.length;\n    const curve2Length = curve2.length;\n    const output = new Array(curve1Length + curve2Length);\n    let outputLength = 0;\n    let index1 = 0;\n    let index2 = 0;\n\n    while (index1 < curve1Length && index2 < curve2Length) {\n        const point1 = curve1[index1];\n        const point2 = curve2[index2];\n        const cost1 = point1[0];\n        const error1 = point1[1];\n        const cost2 = point2[0];\n        const error2 = point2[1];\n        if (cost1 === cost2 && error1 === error2) {\n            output[outputLength] = point1;\n            outputLength += 1;\n            index1 += 1;\n            index2 += 1;\n        } else if (cost1 <= cost2 && error1 <= error2) {\n            index2 += 1;\n        } else if (cost1 >= cost2 && error1 >= error2) {\n            index1 += 1;\n        } else if (error1 < error2) {\n            output[outputLength] = point1;\n            outputLength += 1;\n            index1 += 1;\n        } else {\n            output[outputLength] = point2;\n            outputLength += 1;\n            index2 += 1;\n        }\n    }\n\n    while (index1 < curve1Length) {\n        output[outputLength] = curve1[index1];\n        outputLength += 1;\n        index1 += 1;\n    }\n    while (index2 < curve2Length) {\n        output[outputLength] = curve2[index2];\n        outputLength += 1;\n        index2 += 1;\n    }\n    output.length = outputLength;\n    return output;\n}\n\nconst PARETO_BLOCK_SIZE = 32;\n\nfunction paretoConvex(points) {\n    const convex = [];\n\n    for (const point of points) {\n        convex.push(point);\n        while (convex.length >= 3) {\n            const point2 = convex[convex.length - 1];\n            const point1 = convex[convex.length - 2];\n            const point0 = convex[convex.length - 3];\n            const m01 = (point1[1] - point0[1]) / (point1[0] - point0[0]);\n            const m12 = (point2[1] - point1[1]) / (point2[0] - point1[0]);\n            if (m12 <= m01) {\n                break;\n            }\n            convex.splice(convex.length - 2, 1);\n        }\n    }\n\n    return convex;\n}\n\nfunction paretoMinimize(points) {\n    const pointsSorted = points.slice().sort((left, right) => left[0] - right[0]);\n    return pointsSorted.reduce((minimized, point) => paretoUnion([point], minimized), []);\n}\n\nfunction paretoShift([cost0, error0], frontier) {\n    return frontier.map(([cost, error]) => [cost0 + cost, error0 + error]);\n}\n\nfunction paretoUnionBalanced(curves) {\n    let level = curves;\n    while (level.length > 1) {\n        const nextLevel = [];\n        for (let index = 0; index < level.length; index += 2) {\n            if (index + 1 >= level.length) {\n                nextLevel.push(level[index]);\n            } else {\n                nextLevel.push(paretoUnion(level[index], level[index + 1]));\n            }\n        }\n        level = nextLevel;\n    }\n    return level[0] || [];\n}\n\n// Merge shifted frontiers in small balanced batches. This keeps the\n// large-large unions that are fast for JS without retaining every\n// shifted frontier at once.\nfunction paretoCombineTwo(combined, frontier) {\n    if (combined.length === 0) {\n        return frontier;\n    }\n\n    let combinedFrontier = [];\n    for (let index = 0; index < combined.length; index += PARETO_BLOCK_SIZE) {\n        const shiftedFrontiers = [];\n        const limit = Math.min(index + PARETO_BLOCK_SIZE, combined.length);\n        for (let pointIndex = index; pointIndex < limit; pointIndex += 1) {\n            shiftedFrontiers.push(paretoShift(combined[pointIndex], frontier));\n        }\n        combinedFrontier = paretoUnion(paretoUnionBalanced(shiftedFrontiers), combinedFrontier);\n    }\n    return paretoConvex(combinedFrontier);\n}\n\nfunction paretoCombine(frontiers) {\n    let level = frontiers.map((frontier) => paretoConvex(paretoMinimize(frontier)));\n    while (level.length > 1) {\n        const nextLevel = [];\n        for (let index = 0; index < level.length; index += 2) {\n            if (index + 1 >= level.length) {\n                nextLevel.push(level[index]);\n            } else {\n                nextLevel.push(paretoCombineTwo(level[index], level[index + 1]));\n            }\n        }\n        level = nextLevel;\n    }\n    return level[0] || [];\n}\n\nfunction calculateMergedCostAccuracy(tests) {\n    const testsLength = tests.length;\n    const costAccuracies = tests.map((test) => test[\"cost-accuracy\"]);\n    const maximumAccuracy = tests.reduce((sum, test) => sum + test.bits, 0);\n    const initialAccuraciesSum = costAccuracies.reduce((sum, costAccuracy) => {\n        if (!costAccuracy || costAccuracy.length === 0) {\n            return sum;\n        }\n        return sum + costAccuracy[0][1];\n    }, 0);\n    const initialAccuracy = maximumAccuracy > 0\n        ? 1 - initialAccuraciesSum / maximumAccuracy\n        : 1.0;\n    const rescaled = costAccuracies\n        .filter((costAccuracy) => costAccuracy && costAccuracy.length > 0)\n        .map((costAccuracy) => {\n            const [initialPoint, bestPoint, otherPoints] = costAccuracy;\n            const initialCost = Number(initialPoint[0]);\n            return [initialPoint, bestPoint].concat(otherPoints).map((point) => [\n                point[0] / initialCost,\n                point[1],\n            ]);\n        });\n    const frontier = paretoCombine(rescaled).map(([cost, accuracy]) => {\n        if (cost === 0) {\n            return [\"N/A\", 1 - accuracy / maximumAccuracy];\n        }\n        return [testsLength / cost, 1 - accuracy / maximumAccuracy];\n    });\n    return [[1.0, initialAccuracy], frontier];\n}\n\nfunction getFilteredTests() {\n    return resultsJsonData.tests.filter(filterTest);\n}\n\nfunction getFilteredBaselineTests() {\n    return getFilteredTests().map(getBaselineTest);\n}\n\nfunction getCurveCacheKey(tests) {\n    return JSON.stringify(tests.map((test) => test.name));\n}\n\nconst jointCostCache = new DeferredCurveCache(getFilteredTests);\nconst otherJointCostCache = new DeferredCurveCache(getFilteredBaselineTests);\n\n//https://stackoverflow.com/questions/196972/convert-string-to-title-case-with-javascript\nfunction toTitleCase(str) {\n    return str.replace(\n        /\\w\\S*/g,\n        function (txt) {\n            return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();\n        }\n    )\n}\n\nfunction buildDropdown(options, selected, placeholder, onChange) {\n    const select = Element(\"select\", [\n        Element(\"option\", { value: \"\", selected: !selected }, [placeholder]),\n        options.map((opt) =>\n            Element(\"option\", { value: opt, selected: selected == opt }, [opt])\n        ),\n    ]);\n    select.addEventListener(\"change\", () => {\n        onChange(select.value);\n        update();\n    });\n    return select;\n}\n\nfunction buildHeader(title) {\n    // The online demo always runs with seed 1; hide the Metrics link there\n    const showMetricsLink = resultsJsonData?.seed != 1\n    return Element(\"header\", {}, [\n        Element(\"h1\", {}, title),\n        Element(\"img\", { src: \"logo-car.png\" }, []),\n        showMetricsLink && Element(\"nav\", {}, [\n            Element(\"ul\", {}, [\n                Element(\"li\", {}, [\n                    Element(\"a\", { href: \"timeline.html\" }, [\"Metrics\"])\n                ])\n            ])\n        ]),\n    ])\n}\n\n// Based on https://observablehq.com/@fil/plot-onclick-experimental-plugin\n// However, simplified because we don't need hit box data\nfunction on(mark, listeners = {}) {\n    const render = mark.render\n    mark.render = function (facet, { x, y }, channels) {\n        const data = this.data\n        const g = render.apply(this, arguments)\n        const r = d3.select(g).selectChildren()\n        for (const [type, callback] of Object.entries(listeners)) {\n            r.on(type, function (event, i) {\n                return callback(event, data[i])\n            })\n        }\n        return g\n    }\n    return mark\n}\n\nfunction plotXY(testsData, otherJsonData) {\n    const filteredTests = getFilteredTests();\n    function onclick(e, d) {\n        window.location = d.link + \"/graph.html\";\n    }\n    let marks = [\n        Plot.line([[0, 0], [1, 1]], { stroke: '#ddd' }),\n    ];\n    if (otherJsonData) {\n        marks.push(Plot.arrow(filteredTests, {\n            x1: d => 1 - getBaselineTest(d).start / 64,\n            y1: d => 1 - getBaselineTest(d).end / 64,\n            x2: d => 1 - d.start / 64,\n            y2: d => 1 - d.end / 64,\n            stroke: \"#900\", strokeWidth: 2,\n        }));\n    }\n    marks.push(on(Plot.dot(filteredTests, {\n        x: d => 1 - d.start / 64, y: d => 1 - d.end / 64,\n        fill: \"#00a\", strokeWidth: 2,\n    }), { click: onclick }));\n    \n    const out = Plot.plot({\n        marks: marks,\n        className: \"clickable\",\n        marginBottom: 0,\n        marginRight: 0,\n        width: '400',\n        height: '400',\n        x: { nice: true, line: true, tickFormat: \"%\", },\n        y: { nice: true, line: true, tickFormat: \"%\", },\n    })\n    out.setAttribute('viewBox', '0 0 420 420')\n    return out;\n}\n\nfunction plotPareto(jsonData, otherJsonData) {\n    const mergedCostAccuracy = jointCostCache.get();\n    if (mergedCostAccuracy === null) {\n        return Element(\"div\", {\n            style: \"max-width: 100%; aspect-ratio: 1;\",\n            \"aria-label\": \"Pareto plot loading\",\n        }, []);\n    }\n\n    const [initial, frontier] = mergedCostAccuracy;\n    let marks = [\n        Plot.dot([initial], {\n            stroke: \"#00a\",\n            symbol: \"square\",\n            strokeWidth: 2,\n        }),\n        Plot.line(frontier, {\n            stroke: \"#00a\",\n            strokeWidth: 2,\n        }),\n    ];\n\n    if (otherJsonData) {\n        const otherMergedCostAccuracy = otherJointCostCache.get();\n        if (otherMergedCostAccuracy === null) {\n            return Element(\"div\", {\n                style: \"max-width: 100%; aspect-ratio: 1;\",\n                \"aria-label\": \"Pareto plot loading\",\n            }, []);\n        }\n\n        const [initial2, frontier2] = otherMergedCostAccuracy;\n        marks = [\n            Plot.dot([initial2], {\n                stroke: \"#900\",\n                symbol: \"square\",\n                strokeWidth: 2,\n            }),\n            Plot.line(frontier2, {\n                stroke: \"#900\",\n                strokeWidth: 2,\n            })\n        ].concat(marks);\n    }\n\n    const out = Plot.plot({\n        marks: marks,\n        width: '400',\n        height: '400',\n        x: { line: true, nice: true, tickFormat: c => c + \"×\" },\n        y: { line: true, nice: true, domain: [0, 1], tickFormat: \"%\", },\n        marginBottom: 0,\n        marginRight: 0,\n    })\n    out.setAttribute('viewBox', '0 0 420 420')\n    return out;\n}\n\nfunction buildCheckboxLabel(classes, text, boolState) {\n    return Element(\"label\", { classList: classes }, [\n        Element(\"input\", { type: \"checkbox\", checked: boolState }, []),\n        text,\n    ]);\n}\n\nfunction buildDiffLine() {\n    const urlInput = Element(\"input\", {\n        id: \"compare-input\", value: compareAgainstURL,\n        placeholder: \"URL to report or JSON file\",\n        size: 60,\n    }, []);\n\n    var unitText = radioStates[radioState]?.tolerance;\n\n    const submitButton = Element(\"button\", \"Compute Diff\")\n    submitButton.addEventListener(\"click\", async (e) => {\n        e.preventDefault();\n        radioState = radioState ?? \"endAcc\";\n        otherJsonData = await fetchBaseline(urlInput.value);\n        update();\n    });\n\n    const toleranceInputField = Element(\"input\", {\n        id: `toleranceID`, value: filterTolerance,\n        size: 10, style: \"text-align:right;\",\n    }, []);\n    toleranceInputField.addEventListener(\"change\", () => {\n        filterTolerance = toleranceInputField.value;\n        update();\n    });\n\n    return [\n        urlInput,\n        unitText && [\" Hiding: ±\", toleranceInputField, unitText],\n        \" \", submitButton\n    ];\n}\n\nfunction buildCompareForm() {\n    const formName = \"compare-form\"\n\n    let radioButtons = [];\n    for (let [i, stateInfo] of Object.entries(radioStates)) {\n        let radioElt = Element(\"input\", {\n            name: formName, id: \"compare-\" + i,\n            type: \"radio\",\n            checked: radioState == i,\n        }, []);\n        radioElt.addEventListener(\"click\", () => {\n            radioState = i;\n            update();\n        });\n\n        let labelElt = Element(\"label\", [radioElt, stateInfo.title]);\n        radioButtons.push(labelElt);\n    }\n\n    const hideEqual = buildCheckboxLabel(\"hide-equal\", \"Hide equal\", hideDirtyEqual)\n    hideEqual.addEventListener(\"click\", () => {\n        hideDirtyEqual = ! hideDirtyEqual;\n        update();\n    })\n\n    return Element(\"form\", {}, [radioButtons, \" \", hideEqual]);\n}\n\nfunction summarizeTests(tests) {\n    return tests.reduce((acc, test) => {\n        acc.totalStart += test.start;\n        acc.totalEnd += test.end;\n        acc.maxAccuracy += test.bits;\n        acc.totalTime += test.time;\n        if (test.status == \"timeout\" || test.status == \"crash\") {\n            acc.crashCount += 1;\n        }\n        return acc;\n    }, { totalStart: 0, totalEnd: 0, maxAccuracy: 0, totalTime: 0, crashCount: 0 });\n}\n\nfunction buildStats(jsonData, mergedCostAccuracy) {\n    const summary = summarizeTests(jsonData.tests);\n    const speedup = mergedCostAccuracy === null ? \"⋯\" : calculateSpeedup(mergedCostAccuracy);\n\n    return Element(\"div\", { id: \"large\" }, [\n        Element(\"div\", {}, [\n            \"Average Percentage Accurate: \",\n            Element(\"span\", { classList: \"number\" }, [\n                calculatePercent(summary.totalStart / summary.maxAccuracy), \"%\",\n                Element(\"span\", { classList: \"unit\" }, [\" → \",]),\n                calculatePercent(summary.totalEnd / summary.maxAccuracy), \"%\" ]),\n        ]),\n        Element(\"div\", {}, [\n            \"Time:\",\n            Element(\"span\", { classList: \"number\" }, [formatTime(summary.totalTime)])\n        ]),\n        Element(\"div\", {}, [\n            \"Bad Runs:\",\n            Element(\"span\", {\n                classList: \"number\",\n                title: \"Crashes and timeouts are considered bad runs.\"\n            }, [`${summary.crashCount}/${jsonData.tests.length}`])\n        ]),\n        Element(\"div\", {}, [\n            \"Speedup:\",\n            Element(\"span\", {\n                classList: \"number\",\n                title: \"Aggregate speedup of fastest alternative that improves accuracy.\"\n            }, [speedup])\n        ]),\n    ]);\n}\n\nfunction buildTableHeader(stringName, help) {\n    const textElement = Element(\"th\", {}, [\n        toTitleCase(stringName),\n        \" \",\n        (stringName != sortState.key ? \"–\" : sortState.dir ?  \"⏶\" : \"⏷\"),\n        help && Element(\"span\", { classList: \"help-button\", title: help }, [\"?\"]),\n    ]);\n    textElement.addEventListener(\"click\", () => {\n        if (stringName == sortState.key) {\n            sortState.dir = !sortState.dir;\n        } else {\n            sortState.key = stringName;\n            sortState.dir = true;\n        }\n        update();\n    })\n    return textElement\n}\n\nfunction buildBody(jsonData, otherJsonData) {\n    const mergedCostAccuracy = jointCostCache.get();\n    const stats = buildStats(jsonData, mergedCostAccuracy);\n\n    const header = buildHeader(\"Herbie Results\")\n\n    const figureRow = Element(\"div\", { classList: \"figure-row\" }, [\n        Element(\"figure\", { id: \"xy\" }, [\n            Element(\"h2\", {}, [tempXY_A]),\n            plotXY(jsonData, otherJsonData),\n            Element(\"figcaption\", {}, [tempXY_B])\n        ]),\n        Element(\"figure\", { id: \"pareto\" }, [\n            Element(\"h2\", {}, [tempPareto_A]),\n            plotPareto(jsonData, otherJsonData),\n            Element(\"figcaption\", {}, [tempPareto_B])\n        ])\n    ])\n\n    const rows = buildTableContents(jsonData)\n    const footer = buildDiffFooter(jsonData, otherJsonData)\n    const resultsTable = Element(\"table\", { id: \"results\" }, [\n        Element(\"thead\", {}, [\n            Element(\"tr\", {}, [\n                buildTableHeader(\"name\"),\n                buildTableHeader(\"start\"),\n                buildTableHeader(\"end\", resultHelpText),\n                buildTableHeader(\"target\", targetHelpText),\n                buildTableHeader(\"time\"),\n            ]),\n        ]),\n        rows,\n        footer\n    ]);\n    return [header, stats, figureRow, buildControls(jsonData, otherJsonData, rows.length), resultsTable]\n}\n\nfunction compareTests(l, r) {\n    let cmp;\n    if (sortState.key == \"name\") {\n        cmp = l.name.localeCompare(r.name);\n    } else {\n        if (l[sortState.key] === false) {\n            cmp = 1;\n        } else if (r[sortState.key] === false) {\n            cmp = -1;\n        } else {\n            cmp = l[sortState.key] - r[sortState.key];\n        }\n    }\n    if (sortState.dir) cmp = -cmp;\n    return cmp;\n}\n\nfunction getBaselineTest(test) {\n    return diffAgainstFields[test.name]\n}\n\nfunction getVisibleTests(jsonData) {\n    const visibleTests = []\n    for (const test of [...jsonData.tests].sort(compareTests)) {\n        if (filterTest(test)) visibleTests.push(test);\n    }\n    return visibleTests\n}\n\nfunction buildTableContents(jsonData) {\n    const visibleTests = getVisibleTests(jsonData);\n    return visibleTests.map((test) => buildRow(test, getBaselineTest(test)));\n}\n\nfunction computeDiffTotal(jsonData) {\n    if (!otherJsonData || !radioState) return 0;\n    let total = 0;\n    for (let test of jsonData.tests) {\n        let other = getBaselineTest(test);\n        if (!other) continue;\n        if (!filterTest(test)) continue;\n\n        if (radioState == \"startAcc\") {\n            const cur = calculatePercent(test.start / test.bits);\n            const base = calculatePercent(other.start / other.bits);\n            total += cur - base;\n        } else if (radioState == \"endAcc\") {\n            const cur = calculatePercent(test.end / test.bits);\n            const base = calculatePercent(other.end / other.bits);\n            total += cur - base;\n        } else if (radioState == \"targetAcc\") {\n            const curMin = getMinimum(test.target);\n            const baseMin = getMinimum(other.target);\n            if (curMin !== false && baseMin !== false) {\n                total += calculatePercent(curMin / test.bits) -\n                         calculatePercent(baseMin / other.bits);\n            }\n        } else if (radioState == \"time\") {\n            total += other.time - test.time;\n        }\n    }\n    return total;\n}\n\nfunction buildDiffFooter(jsonData, otherJsonData) {\n    if (!otherJsonData || !radioState) return [];\n\n    const total = computeDiffTotal(jsonData);\n    let color = \"diff-time-gray\";\n    let text = \"~\";\n\n    if (radioState == \"time\") {\n        if (Math.abs(total) > filterTolerance * 1000) {\n            if (total > 0) {\n                color = \"diff-time-green\";\n                text = \"+ \" + formatTime(total);\n            } else {\n                color = \"diff-time-red\";\n                text = \"-\" + formatTime(Math.abs(total));\n            }\n        }\n    } else {\n        if (Math.abs(total.toFixed(1)) > filterTolerance) {\n            if (total > 0) {\n                color = \"diff-time-green\";\n                text = \"+ \" + total.toFixed(1) + \"%\";\n            } else {\n                color = \"diff-time-red\";\n                text = \"-\" + Math.abs(total).toFixed(1) + \"%\";\n            }\n        }\n    }\n\n    const cells = [\n        Element(\"th\", {}, [\"Total\"]),\n        radioState == \"startAcc\" ? Element(\"td\", { classList: color }, [text]) : Element(\"td\", {}, []),\n        radioState == \"endAcc\" ? Element(\"td\", { classList: color }, [text]) : Element(\"td\", {}, []),\n        radioState == \"targetAcc\" ? Element(\"td\", { classList: color }, [text]) : Element(\"td\", {}, []),\n        radioState == \"time\" ? Element(\"td\", { classList: color }, [text]) : Element(\"td\", {}, []),\n        Element(\"td\", {}, []),\n        Element(\"td\", {}, []),\n    ];\n\n    return Element(\"tfoot\", {}, [Element(\"tr\", {}, cells)]);\n}\n\nfunction getMinimum(target) {\n    if (target === false) {\n        return false\n    }\n\n    return target.reduce((minA, current) => {\n        const currentA = current[1];\n        return currentA < minA ? currentA : minA;\n    }, Infinity);\n}\n\n// Builds either a normal run row or a comparison row when `other` is present.\nfunction buildRow(test, other) {\n    var smallestTarget = getMinimum(test.target)\n\n    if (!other) {\n        var startAccuracy = calculatePercent(test.start / test.bits) + \"%\"\n        var resultAccuracy = calculatePercent(test.end / test.bits) + \"%\"\n        var targetAccuracy = calculatePercent(smallestTarget / test.bits) + \"%\"\n\n        if (test.status == \"imp-start\" || test.status == \"ex-start\" || test.status == \"apx-start\") {\n            targetAccuracy = \"\"\n        }\n        if (test.status == \"timeout\" || test.status == \"error\") {\n            startAccuracy = \"\"\n            resultAccuracy = \"\"\n            targetAccuracy = \"\"\n        }\n        const tr = Element(\"tr\", { classList: test.status }, [\n            Element(\"td\", {}, [test.name]),\n            Element(\"td\", {}, [startAccuracy]),\n            Element(\"td\", {}, [resultAccuracy]),\n            Element(\"td\", {}, [targetAccuracy]),\n            Element(\"td\", {}, [formatTime(test.time)]),\n            Element(\"td\", {}, [\n                Element(\"a\", {\n                    href: `${test.link}/graph.html`\n                }, [\"»\"])]),\n            Element(\"td\", {}, [\n                Element(\"a\", {\n                    href: `${test.link}/timeline.html`\n                }, [\"📊\"])]),\n        ])\n        // TODO fix bug with cmd/ctrl click.\n        tr.addEventListener(\"click\", () => tr.querySelector(\"a\").click())\n        return tr;\n    } else {\n        function timeTD(test) {\n            var timeDiff = test.time - other.time\n            var color, text\n            if (timeDiff > filterTolerance * 1000) {\n                color = \"diff-time-red\";\n                text = \"-\" + formatTime(timeDiff);\n            } else if (timeDiff < -filterTolerance * 1000) {\n                color = \"diff-time-green\";\n                text = \"+ \" + formatTime(Math.abs(timeDiff));\n            } else {\n                color = \"diff-time-gray\";\n                text = \"~\";\n            }\n            var titleText = `current: ${formatTime(test.time)} vs ${formatTime(other.time)}`\n            return Element(\"td\", { classList: color, title: titleText }, [text]);\n        }\n\n        function accuracyTD(testVal, otherVal) {\n            const op = calculatePercent(otherVal / other.bits)\n            const tp = calculatePercent(testVal / test.bits)\n            let diff = op - tp\n            let color = \"diff-time-red\"\n            let tdText = `- ${diff.toFixed(1)}%`\n\n            if (Math.abs(diff.toFixed(1)) <= filterTolerance) {\n                color = \"diff-time-gray\"\n                tdText = \"~\"\n            } else if (diff < 0) {\n                diff = Math.abs(diff)\n                color = \"diff-time-green\"\n                tdText = `+ ${diff.toFixed(1)}%`\n            }\n\n            const titleText = `Original: ${op} vs ${tp}`\n            return Element(\"td\", { classList: color, title: titleText }, [tdText])\n        }\n\n        const startAccuracy = accuracyTD(test.start, other.start)\n        const resultAccuracy = accuracyTD(test.end, other.end)\n        const targetAccuracy = accuracyTD(smallestTarget, other.target)\n\n        var tdStartAccuracy = radioState == \"startAcc\" ? startAccuracy : Element(\"td\", {}, [calculatePercent(test.start / test.bits), \"%\"])\n        var tdResultAccuracy = radioState == \"endAcc\" ? resultAccuracy : Element(\"td\", {}, [calculatePercent(test.end / test.bits), \"%\"])\n        var tdTargetAccuracy = radioState == \"targetAcc\" ? targetAccuracy : Element(\"td\", {}, [calculatePercent(smallestTarget / test.bits), \"%\"])\n        const tdTime = radioState == \"time\" ? timeTD(test) : Element(\"td\", {}, [formatTime(test.time)])\n\n        var testTitle = \"\"\n        if (test.output != other.output) {\n            testTitle = `Current output:\\n${test.output} \\n \\n Comparing to:\\n ${other.output}`\n        }\n        if (test.status == \"imp-start\" ||\n            test.status == \"ex-start\" ||\n            test.status == \"apx-start\") {\n            tdTargetAccuracy = Element(\"td\", {}, [])\n        }\n        if (test.status == \"timeout\" || test.status == \"error\") {\n            tdStartAccuracy = Element(\"td\", {}, [])\n            tdResultAccuracy = Element(\"td\", {}, [])\n            tdTargetAccuracy = Element(\"td\", {}, [])\n        }\n\n        const tr = Element(\"tr\", { classList: test.status }, [\n            Element(\"td\", { title: testTitle }, [test.name]),\n            tdStartAccuracy,\n            tdResultAccuracy,\n            tdTargetAccuracy,\n            tdTime,\n            Element(\"td\", {}, [\n                Element(\"a\", {\n                    href: `${test.link}/graph.html`\n                }, [\"»\"])]),\n            Element(\"td\", {}, [\n                Element(\"a\", {\n                    href: `${test.link}/timeline.html`\n                }, [\"📊\"])]),\n        ])\n        tr.addEventListener(\"click\", () => tr.querySelector(\"a\").click())\n        return tr;\n    }\n}\n\nfunction buildDiffControls() {\n    var summary = Element(\"details\", { open: showCompareDetails }, [\n        Element(\"summary\", {}, [\n            Element(\"h2\", {}, [\"Diff\"]),\n            buildDiffLine(),\n        ]),\n        buildCompareForm(),\n    ])\n\n    summary.addEventListener(\"toggle\", () => {\n        showCompareDetails = summary.open;\n    });\n\n    return summary;\n}\n\nfunction buildControls(jsonData, otherJsonData, diffCount) {\n    var displayingDiv = Element(\"div\", [\n        \"Displaying \" + diffCount + \"/\" + jsonData.tests.length + \" benchmarks\",\n        \" on \", Element(\"code\", jsonData.branch),\n        otherJsonData && [\n            \", compared with baseline \", Element(\"code\", otherJsonData.branch),\n        ],\n    ])\n\n    return Element(\"div\", { classList: \"report-details\" }, [\n        displayingDiv,\n        buildDiffControls(),\n        buildFilterControls(jsonData),\n    ])\n}\n\nfunction buildFilterGroup(name) {\n    let subFilters = filterGroups[name];\n    let label = buildCheckboxLabel(name, toTitleCase(name), filterGroupState[name]);\n    label.addEventListener(\"click\", (e) => {\n        filterGroupState[name] = e.target.checked;\n        for (let filterName of subFilters) {\n            filterState[filterName] = e.target.checked;\n        }\n        update();\n    });\n    return label;\n}\n\nfunction countTestsByStatus(tests) {\n    const counts = {}\n    for (const test of tests) {\n        counts[test.status] = (counts[test.status] ?? 0) + 1\n    }\n    return counts\n}\n\nfunction collectSuites(tests) {\n    const suites = new Set()\n    for (const test of tests) {\n        const linkComponents = test.link.split(\"/\")\n        if (linkComponents.length > 1) {\n            suites.add(linkComponents[0])\n        }\n    }\n    return [...suites]\n}\n\nfunction collectWarnings(tests) {\n    const warnings = new Set()\n    for (const test of tests) {\n        for (const warning of test.warnings)  {\n            warnings.add(warning)\n        }\n    }\n    return [...warnings]\n}\n\nfunction buildFilterControls(jsonData) {\n    const testTypeCounts = countTestsByStatus(jsonData.tests)\n\n    var filterButtons = []\n    for (let f in filterState) {\n        const name = `${filterNames[f]} (${testTypeCounts[f] ?? 0})`\n        const button = buildCheckboxLabel(f + \" sub-filter\", name, filterState[f])\n        button.addEventListener(\"click\", () => {\n            filterState[f] = button.querySelector(\"input\").checked\n            update()\n        })\n        filterButtons.push(button)\n    }\n\n    const suiteDropdown = buildDropdown(\n        collectSuites(jsonData.tests),\n        filterBySuite,\n        \"Filter by suite\",\n        (value) => { filterBySuite = value; },\n    );\n\n    const warningDropdown = buildDropdown(\n        collectWarnings(jsonData.tests),\n        filterByWarning,\n        \"Filter to warning\",\n        (value) => { filterByWarning = value; },\n    );\n\n    let groupButtons = [];\n    for (let i in filterGroupState) {\n        groupButtons.push(buildFilterGroup(i));\n    }\n\n    const filters = Element(\"details\", { id: \"filters\", open: showFilterDetails }, [\n        Element(\"summary\", {}, [\n            Element(\"h2\", {}, \"Filters\"),\n            groupButtons, \" \", suiteDropdown, \" \", warningDropdown,\n        ]),\n        filterButtons,\n    ]);\n    filters.addEventListener(\"toggle\", () => {\n        showFilterDetails = filters.open;\n    });\n    return filters;\n}\n\nfunction showGetJsonError() {\n    const header = buildHeader(\"Error loading results\")\n\n    const is_windows = navigator.userAgent.indexOf(\"Windows\") !== -1;\n    const page_name = window.location.pathname.split(\"/\").at(-1);\n    let page_location;\n    if (is_windows) {\n        page_location = window.location.pathname.split(\"/\").slice(1, -1).join(\"\\\\\");\n    } else {\n        page_location = window.location.pathname.split(\"/\").slice(0, -1).join(\"/\");\n    }\n\n    let reason;\n    if (window.location.protocol == \"file:\") {\n        reason = [\n            Element(\"p\", [\n                \"Modern browsers prevent access over \",\n                Element(\"code\", \"file://\"), \" URLs, which Herbie requires.\",\n            ]),\n            Element(\"p\", [\n                \"You can work around this by starting a local server, like so:\"\n            ]),\n            Element(\"pre\", [\n                is_windows // Python on windows is usually called python, not python3\n                    ? \"python -m http.server -d \" + page_location + \" 8123\"\n                    : \"python3 -m http.server -d \" + page_location + \" 8123\"\n            ]),\n            Element(\"p\", [\n                \"and then navigating to \",\n                Element(\"a\", {\n                    href: \"http://localhost:8123/\" + page_name,\n                }, Element(\"kbd\", \"http://localhost:8123/\" + page_name)),\n            ]),\n        ];\n    }\n    \n    const message = Element(\"section\", {className: \"error\"}, [\n        Element(\"h2\", \"Could not load results\"),\n        reason,\n    ]);\n\n    const body = [header, message];\n\n    const bodyNode = document.querySelector(\"body\");\n    if (bodyNode) {\n        bodyNode.replaceChildren.apply(bodyNode, body);\n    } else {\n        document.addEventListener(\"DOMContentLoaded\", showGetJsonError);\n    }\n}\n\nfunction filterDirtyEqual(baseData, diffData) {\n    if (!hideDirtyEqual) {\n        return false\n    }\n\n    if (radioState == \"output\") {\n        return baseData.output == diffData.output\n    }\n\n    if (radioState == \"startAcc\") {\n        const t = baseData.start / baseData.bits\n        const o = diffData.start / diffData.bits\n        const op = calculatePercent(o)\n        const tp = calculatePercent(t)\n        const diff = op - tp\n        return Math.abs((diff).toFixed(1)) <= filterTolerance\n    }\n\n    if (radioState == \"endAcc\") {\n        const t = baseData.end / baseData.bits\n        const o = diffData.end / diffData.bits\n        const op = calculatePercent(o)\n        const tp = calculatePercent(t)\n        const diff = op - tp\n        return Math.abs((diff).toFixed(1)) <= filterTolerance\n    }\n\n    if (radioState == \"targetAcc\") {\n        const smallestBase = getMinimum(baseData.target)\n        const smallestDiff = getMinimum(diffData.target)\n\n        const t = smallestBase / baseData.bits\n        const o = smallestDiff / diffData.bits\n        const op = calculatePercent(o)\n        const tp = calculatePercent(t)\n        const diff = op - tp\n        return Math.abs((diff).toFixed(1)) <= filterTolerance\n    }\n\n    if (radioState == \"time\") {\n        const timeDiff = baseData.time - diffData.time\n        return Math.abs(timeDiff) < (filterTolerance * 1000)\n    }\n\n    return false\n}\n\nfunction filterSuite(baseData) {\n    const linkComponents = baseData.link.split(\"/\")\n    return filterBySuite &&\n        linkComponents.length > 1 &&\n        // defensive lowerCase\n        filterBySuite.toLowerCase() != linkComponents[0].toLowerCase()\n}\n\nfunction filterWarning(baseData) {\n    return filterByWarning && baseData.warnings.indexOf(filterByWarning) === -1\n}\n\nfunction filterStatus(baseData) {\n    return !filterState[baseData.status]\n}\n\nfunction filterTest(baseData) {\n    const diffData = getBaselineTest(baseData)\n    if (filterDirtyEqual(baseData, diffData)) return false\n    if (filterSuite(baseData)) return false\n    if (filterWarning(baseData)) return false\n    if (filterStatus(baseData)) return false\n    return true\n}\n\nasync function fetchBaseline(url) {\n    if (!url) return;\n\n    if (url.endsWith(\"/\")) url += \"results.json\";\n    compareAgainstURL = url;\n\n    const response = await fetch(url, {\n        headers: { \"content-type\": \"text/plain\" },\n        method: \"GET\",\n        mode: \"cors\",\n    });\n\n    const json = await response.json()\n    if (json.error) return;\n\n    diffAgainstFields = Object.fromEntries(json.tests.map((test) => [test.name, test]));\n    return json;\n}\n\nasync function getResultsJson() {\n    if (resultsJsonData == null) {\n        try {\n            const response = await fetch(\"results.json\", {\n                headers: { \"content-type\": \"application/json\" },\n            });\n            resultsJsonData = (await response.json());\n        } catch (err) {\n            return showGetJsonError();\n        }\n        update();\n    }\n}\n\ngetResultsJson()\n"
  },
  {
    "path": "src/reports/resources/report.css",
    "content": "/* Standard Herbie header */\n\n@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono&family=IBM+Plex+Sans&family=Ruda:wght@400;500&display=swap');\nhtml { font-family: 'IBM Plex Serif', serif; font-size: 16px; line-height: 1.4; }\nbody { max-width: 800px; margin: .5em auto 3em; }\n\na { color: #2A6496; text-decoration: none; cursor: pointer }\na:hover {text-decoration: underline; color: #295785}\n\nheader {\n    line-height: 2; border-bottom: 1px solid #ddd; margin-bottom: 2em;\n    display: flex; flex-direction: row; align-items: bottom;\n    font-family: 'Ruda', serif;\n}\nheader h1 { width: calc(50% - 54px/2); margin: 0; font-size: 125%; line-height: 1.6 }\nheader img { width: 54px; height: 24px; vertical-align: bottom; padding-bottom: 4px; }\nheader nav { width: calc(50% - 54px/2); text-align: right; }\nheader ul { margin: 0; padding: 0; font-weight: bold; }\nheader li { display: inline-block; margin: 0 .5em; }\nheader li::before { content: \"•\"; margin-right: 1em; }\nheader li:first-child::before { content: none; }\n\nsummary h1, summary h2 { display: inline-block; }\n\n#large {\n    margin: 2em 0; display: flex; gap: 3em; justify-content: center;\n    font-family: 'IBM Plex Serif', serif; color: #888;\n}\n#large .number {\n    font-size: 2em; display: block; font-family: 'Ruda', serif; color: black;\n    margin-top: -.2em;\n}\n#large .unit { font-family: 'IBM Plex Serif', serif; color: #aaa; }\n@media print { #large { margin-top: 0; }}\n\n/* Plots at the top */\n\n.figure-row { display: flex; flex-direction: row; gap: 1em; align-items: start; }\nfigure, section { flex: 1; border: 1px solid #ddd; padding: 1ex; margin: 1em 0; align-self: start; }\nsection.error { border: 2px solid #a40000; background: #ef2929; color: white; }\nsection.error a { color: #ffdb4c; }\nh2 { font-size: 1em; font-family: 'IBM Plex Serif', serif; margin: 0; }\ndata { font-family: 'Ruda'; }\nh2 .subhead { font-weight: normal; }\nsvg .domain, svg .tick { color: #888; }\nsvg text { font-family: 'IBM Plex Serif', serif; }\nfigcaption { font-size: 80%; color: #666; padding-top: 1ex; }\nsvg.clickable circle:hover { stroke: #00a; stroke-width: 10; cursor: pointer; }\n\n/* Flag list / configuration */\n\n#about { margin: 3em 0; }\n#about th { font-weight: bold; text-align: left; padding-right: 1em; }\n\n#flag-list { position: relative; }\n#flag-list kbd:not(:last-child):after { content: \", \"; }\n#flag-list a { float: right; margin: 0 .5em; }\n#flag-list a:before { content: \"(\"; }\n#flag-list a:after { content: \")\"; }\n#flag-list #changed-flags { display: none; }\n#flag-list #all-flags { display: block; }\n#flag-list.changed-flags #changed-flags { display: block; }\n#flag-list.changed-flags #all-flags { display: none; }\n\n/* Result color pallette */\n:root {\n    --accent-text: #4a4a4a;\n    --accent-title: #888;\n    --accent-board: #ddd;\n    --result-green: #87fc70;\n    --result-light-green: #e0f8d8;\n    --result-light-orange: #ff9500;\n    --result-orange: #ff9500;\n    --result-red-orange: #ff5e3a;\n    --result-red: #ff0000;\n    --result-yellow: #ffdb4c;\n    --result-timeout: #8e8e93;\n    --result-error: #4a4a4a;\n    --accent-blue: #0000aa;\n}\n\n/* Result table filters */\nlabel.imp-start {accent-color: var(--result-green);}\nlabel.apx-start {accent-color: var(--result-orange);}\nlabel.uni-start {accent-color: var(--result-red-orange);}\nlabel.ex-start {accent-color: var(--result-light-green);}\nlabel.eq-start {accent-color: var(--result-green);}\nlabel.lt-start {accent-color: var(--result-yellow);}\nlabel.gt-target {accent-color: var(--result-green);}\nlabel.gt-start {accent-color: var(--result-green);}\nlabel.eq-target {accent-color: var(--result-green);}\nlabel.lt-target {accent-color: var(--result-orange);}\nlabel.crash {accent-color: var(--result-red);}\nlabel.error {accent-color: var(--result-error);}\nlabel.timeout {accent-color: var(--result-timeout);}\n#filters label {margin: 0; display: inline-block; padding: .4ex; color: var(--accent-text);}\n#filters summary {accent-color: var(--accent-blue);}\n#filters .sub-filter {column-width: 11.5rem;}\n\n/* Compare Reports */\n.diff-time-red {color: red;}\n.diff-time-green {color: green;}\n.diff-time-gray {color: gray;}\n.diff-status {color: #0000aa;}\n.report-details {border: 1px solid var(--accent-board); padding: 1ex; margin: 0 0 1em 0;}\n.report-details h2 {font-size: 16px;}\n.report-details h3 {font-size: 14px;}\n.report-details h2, h3 {color: var(--accent-title); line-height: 1.4;}\n.report-details form { display: inline;}\n.report-details > details summary h2 {padding-right: 1em;}\n.report-details > details > div > h3 {margin: 0; display: inline; padding-right: 1em; color: var(--accent-title);}\n\n/* Table of results */\n\n#results { border-collapse: collapse; width:100%; }\n#results th, #results td { border: 1px solid #ddd; padding: .5em; }\n\n#results th { white-space: pre; color: #888; font-family: 'IBM Plex Serif', serif; }\n#results td { text-align: right; overflow: hidden; font-size: 15pt; font-family: 'Ruda', serif; font-weight: 500; }\n#results tbody tr:hover { background-color: #f8f8f8; cursor: pointer; }\n\n#results td:nth-child(1) { text-align: left; word-break: break-all; }\n#results td:nth-child(6) {width: 0;}\n\ntr.imp-start  td:nth-child(3) {background-color:#87fc70;}\ntr.apx-start  td:nth-child(3) {background-color:#ff9500;}\ntr.uni-start  td:nth-child(3) {background-color:#ff5e3a;color:#f7f7f7;}\ntr.ex-start   td:nth-child(3) {background-color:#e0f8d8;}\n\ntr.gt-target  td:nth-child(3) {background-color:#87fc70;}\ntr.gt-target  td:nth-child(4) {background-color:#0bd318;}\ntr.eq-target  td:nth-child(3) {background-color:#87fc70;}\ntr.eq-target  td:nth-child(4) {background-color:#87fc70;}\ntr.lt-target  td:nth-child(3) {background-color:#87fc70;}\ntr.lt-target  td:nth-child(4) {background-color:#ff9500;}\ntr.eq-start   td:nth-child(3) {background-color:#ff9500;}\ntr.eq-start   td:nth-child(4) {background-color:#ffdb4c;}\ntr.lt-start   td:nth-child(3) {background-color:#ff5e3a;color: #f7f7f7;}\ntr.lt-start   td:nth-child(4) {background-color:#ffdb4c;color: #f7f7f7;}\n\ntr.crash      td:nth-child(3) {background-color:#ff9d87; color:#ed2b00; border: 2px solid #ff5e3a; margin: -2px; }\ntr.error      td:nth-child(3) {background-color:#4a4a4a;color:#f7f7f7;}\ntr.timeout    td:nth-child(3) {background-color:#8e8e93;color:#f7f7f7;}\n\n#results.no-target td:nth-child(4) {display: none;}\n#results.no-target th:nth-child(4) {display: none;}\n\n/* Help button */\n\n.help-button {\n display: inline-block; background: #999;\n font-size: .8em; color: #eee; line-height: 1.3em;\n height: 1.25em; width: 1.25em; border-radius: .625em;\n text-align: center; margin-left: .5ex;\n position: relative; bottom: .125em;\n}\n.help-button:hover { background: #444; color: #eee; text-decoration: none; cursor: pointer; }\n.help-button.float { float: right; font-size: 120%; font-weight: normal; }\n\n\n/* Detail page layout */\nsection { display: flow-root; }\n\n/* Warnings */\n\n.warnings { list-style: inside none; padding: 0; }\n.warnings > li {\n    margin: .25em 0; padding: .5em; background: #ffdb4c; border: 2px solid #ff9500;\n    overflow: hidden;\n}\n.warnings h2 { font-size: 100%; font-weight: normal; margin: 0; }\n.warnings h2:before { content: \"Warning: \"; font-weight: bold; }\n.warnings h2 a { float: right; }\n.warnings ol { list-style: inside none; padding: 0 1em; }\n.warnings ol li { margin: .25em 0; }\n\n/* Big block for program input output */\n\n.programs { position: relative; }\n.programs select { position: absolute; right: 3em; }\n.program { display: inline-block; text-align: left; }\n#precondition { margin: 2em 0; }\n#precondition:before { content: \"Precondition:\"; display: block; color: #444; margin-left: -2em; }\n/* Allow line breaks in display equations (see https://katex.org/docs/issues.html) */\n.katex-display > .katex { white-space: normal }\n.katex-display .base { margin: 0.25em 0 }\n.katex-display { margin: 0.5em 0; }\n.katex-display .arraycolsep { width: 0 !important; }\n#preprocess { padding: 0 1em 1em; margin: 0 -1em 1em; border-bottom: 2px solid white; }\n#preprocess:before { content: \"Preprocess\"; float: left; color: #444; }\n\n/* Error graphs */\n\n#functions { display: flex; flex-direction: row; gap: 1em; margin-top: 1ex; }\n#functions:before { content: \"Show: \"; }\n\n#cost-accuracy p { font-size: 1em; font-family: 'IBM Plex Serif', serif; margin: 0; }\n#cost-accuracy table { width: 374px; padding: 1ex 0; }\n#cost-accuracy thead th { color: #888; border-bottom: 1px solid #888; }\n#cost-accuracy thead th.numeric { text-align: right; }\n#cost-accuracy tbody th { font-weight: normal; }\n#cost-accuracy tbody td { font-family: 'Ruda', serif; text-align: right; font-weight: 400; }\n#cost-accuracy tbody td.better { font-weight: 800; color: #050; }\n\n/* Try it out section */\n\n#try-result output { font-size: 108%; margin: 0 .5em; float: right; }\n#try-result div { overflow: auto; }\n#try-result table { line-height: 1.5; margin-top: .25em; }\n#try-result { width: 39%; float: right; }\n#try-result p.header { margin: 0 0 .5em; font-size: 120%; color: #444; border-bottom: 1px solid #ccc; line-height: 1.5; }\n#try-result label:after { content: \":\"; }\n\n#try-inputs-wrapper { width: 59%; display: inline-block; }\n\n#try-inputs ol { list-style: none; padding: 0; display: inline-block; margin: 0 0 0 -1em; }\n#try-inputs ol label { min-width: 4ex; text-align: right; margin-right: .5em; display: inline-block; }\n#try-inputs li { margin-left: 1em; display: inline-block; font-size: 110%; font-family: monospace; line-height: 2; }\n#try-inputs label:after { content: \":\"; }\n#try-inputs input { padding: 1px 4px; width: 25ex; }\n#try-inputs p.header { margin: 0 0 .5em; font-size: 120%; color: #444; border-bottom: 1px solid #ccc; line-height: 1.5; }\n\n#try-error { color:  red; font-size: 120%; display: none; }\n.error #try-error { display: block; }\n#try-result.error table { display: none; }\n\n/* Derivation */\n\n.history, .history ol { list-style: none inside; width: 800px; margin: 0 0 2em; padding: 0; }\n\n.history li p { width: 250px; display: inline-block; margin: 0 25px 0 0; }\n.history li .error { display: block; color: #666; }\n.history li > div { display: inline-block; margin: 0; width: 500px; vertical-align: middle; }\n.history li > div > div { margin: 0; display: inline-block; text-align: right !important; }\n\n.history h2 { margin: 1.333em 0 .333em; }\n.history li { margin: .5em 0; border-top: 1px solid #ddd; padding-top: .5em; }\n.history li:first-child { border-top: none; padding-top: 0; }\n.history .rule { text-decoration: underline; }\n.history .event { display: block; margin: .5em 0; }\n\n.history .proof { width: 100%; overflow: auto; }\n.history .proof table { padding: 0 .5em; }\n.history .proof table th { text-align: left; font-weight: normal; }\n.history .proof table th .info { display: block; color: #666; }\n.history .proof table td { text-align: left; }\n\n/* Process / debug info */\n\n#process-info { background: #ddd; padding: 0; }\n#process-info p.header { font-size: 110%; padding: 1em 1em .5em; margin: 0; }\n\n.timeline {\n    height: 2em; border: 1px solid #888; border-width: 1px 0px; margin-bottom: 1em;\n    display: flex;\n}\n.timeline-phase { height: 2em; background: var(--phase-color); display: inline-block; }\n@media print {\n    .timeline { border: none; }\n    .timeline-phase { outline: 1px solid black; }\n}\n\n/* Blocks of information */\n\n.timeline-block { border-left: 1ex solid var(--phase-color); padding: 1px 1ex;}\n.timeline-block h3 { margin: 0; font-size: 110%; font-weight: normal; }\n.timeline-block p { margin: 0; }\n.timeline-block h3 .time { float: right; }\n\n.timeline-block dl { font-size: 90%; }\n.timeline-block dt { min-width: 6em; float: left; font-size: 100%; }\n.timeline-block dd { margin: 0 0 1ex 6em; max-width: 100%; overflow: auto; }\ntable.times { border-spacing: 15px 5px; }\ntable th { text-align: left; }\ntable.times td { text-align: right; min-width: 8ex; vertical-align: baseline; }\ntable.times td:last-child { text-align: left; }\ntable.states { min-width: 50%; }\ntable.states td:last-child, table.states tfoot { font-weight: bold; }\ntable pre { padding: 0; margin: 0; text-align: left; font-size: 110%; }\n\n/* Timeline colors -- Uses Tango color scheme */\n\n.timeline-sample   { --phase-color: #edd400; }\n.timeline-analyze  { --phase-color: #fce94f; }\n\n.timeline-eval     { --phase-color: #204a87; }\n.timeline-prune    { --phase-color: #3465a4; }\n.timeline-reconstruct { --phase-color: #729fcf; }\n.timeline-gc       { --phase-color: #888a85; }\n.timeline-localize { --phase-color: #729fcf; }\n\n.timeline-rewrite  { --phase-color: #4e9a06; }\n.timeline-simplify { --phase-color: #73d216; }\n.timeline-derivations{ --phase-color: #8ae234; }\n\n.timeline-preprocess { --phase-color: #5c3566; }\n.timeline-series   { --phase-color: #ad7fa8; }\n\n.timeline-regimes  { --phase-color: #a40000; }\n.timeline-bsearch  { --phase-color: #cc0000; }\n\n/* Bogosity colors */\n\n.bogosity {\n    display: flex; margin-bottom: 1em; height: 1em;\n    border-radius: .5em; overflow: clip;\n}\n.bogosity > div { background: var(--phase-color); display: inline-block; }\n@media print {\n    .bogosity { border: none; }\n    .bogosity > div { outline: 1px solid black; }\n}\n\n.bogosity-valid { --phase-color: #4e9a06; }\n.bogosity-infinite { --phase-color: #8ae234; }\n.bogosity-unknown { --phase-color: #000000; }\n.bogosity-unsamplable { --phase-color: #a40000; }\n.bogosity-invalid { --phase-color: #204a87; }\n.bogosity-precondition { --phase-color: #729fcf; }\n\n/* Code sample to reproduce */\n\npre.shell code:before { content: \"$ \"; font-weight: bold; }\n\n/* Target / expected code block */\n\n#comparison table { width: 300px; display: inline-table; vertical-align: top; }\n#comparison table th { text-align: left; }\n#comparison table td { text-align: right; }\n#comparison div { display: inline-block; width: 500px; }\n\n/* Formatting backtraces */\n\n#backtrace table { width: 100%; }\n#backtrace th[colspan] { text-align: left; }\n#backtrace th { text-align: right; }\n#backtrace td:nth-child(3), #backtrace td:nth-child(4) { text-align: right; }\n#backtrace td.procedure { font-family: monospace; }\n\n/* Formatting profile info */\n\n.loaded .load-text { display: none; }\n.load-text { text-align: center; font-size: 140%; color: #888; }\n\na.delete { color: currentColor; }\na.delete:hover { color: #ed2b00; text-decoration: line-through; }\n#profile { border: 1px solid #ddd; }\n#profile input {\n    width: 100%; padding: .5ex 1ex; box-sizing: border-box;\n    border: none; border-bottom: 1px solid #ddd; font-size: 150%;\n}\n#profile .profile-row { margin: 1em 0; }\n.profile-row div { display: flex; }\n#profile .edge { color: #888; margin-left: 2em; }\n#profile .node { font-size: 120%; }\n#profile .path, #profile .name { font-family: monospace; white-space: nowrap; }\n#profile .path { flex-grow: 1; overflow: hidden; text-overflow: ellipsis; }\n#profile .path:before { content: \" (\"; }\n#profile .path:after { content: \") \"; }\n.profile-row > div > * { padding: 0 .5em; }\n#profile .pct { width: 4em; text-align: right; }\n"
  },
  {
    "path": "src/reports/resources/report.html",
    "content": "<!doctype html>\n<title>Herbie results</title>\n<meta charset=\"utf-8\">\n<link rel=\"stylesheet\" type=\"text/css\" href=\"report.css\">\n<script defer src=\"https://cdn.jsdelivr.net/npm/d3@7\"></script>\n<script defer src=\"https://cdn.jsdelivr.net/npm/@observablehq/plot@0.6\"></script>\n<script defer src=\"report-page.js\"></script>\n"
  },
  {
    "path": "src/reports/resources/report.js",
    "content": "window.COMPONENTS = []\n\nfunction Component(selector, fns) {\n    this.selector = selector;\n    this.fns = fns;\n    window.COMPONENTS.push(this);\n}\n\nfunction ComponentInstance(elt, component) {\n    for (var i in component.fns) {\n        if (component.fns.hasOwnProperty(i)) {\n            this[i] = component.fns[i].bind(this);\n        }\n    }\n    this.elt = elt;\n}\n\nfunction Element(tagname, props, children) {\n    if (children === undefined) { children = props; props = {}; }\n\n    var $elt = document.createElement(tagname);\n    for (var i in props) if (props.hasOwnProperty(i)) $elt[i] = props[i];\n\n    function addAll(c) {\n        if (!c) return;\n        else if (Array.isArray(c)) c.map(addAll);\n        else if (typeof c == \"string\") $elt.appendChild(document.createTextNode(c))\n        else if (c instanceof Node) $elt.appendChild(c);\n        else {\n            console.error(\"Not an element: \", c);\n            throw \"Invalid element!\"\n        }\n    }\n    addAll(children);\n    return $elt;\n}\n\n\nvar TogglableFlags = new Component(\"#flag-list\", {\n    setup: function() {\n        this.elt.classList.add(\"changed-flags\");\n        this.button = Element(\"a\", {id: \"flag-list-toggle\"}, \"see all\");\n        this.button.addEventListener(\"click\", this.toggle);\n        this.elt.insertBefore(this.button, this.elt.children[0]);\n    },\n    toggle: function() {\n        this.elt.classList.toggle(\"changed-flags\");\n        var changed_only = this.elt.classList.contains(\"changed-flags\");\n        this.button.innerText = changed_only ? \"see all\" : \"see diff\";\n    }\n});\n\n\n// Cicular color wheel representing error values limited to size 10\nconst colors = [\n    { line: { stroke: '#d00' }, dot: { stroke: '#d002'} },\n    { line: { stroke: '#00a' }, dot: { stroke: '#00a2'} },\n    { line: { stroke: '#080' }, dot: { stroke: '#0802'} },\n    { line: { stroke: '#0d0' }, dot: { stroke: '#0d02'} },\n    { line: { stroke: '#a00' }, dot: { stroke: '#a002'} },\n    { line: { stroke: '#0a0' }, dot: { stroke: '#0a02'} },\n    { line: { stroke: '#00d' }, dot: { stroke: '#00d2'} },\n    { line: { stroke: '#008' }, dot: { stroke: '#0082'} },\n    { line: { stroke: '#d80' }, dot: { stroke: '#d802'} },\n    { line: { stroke: '#00f' }, dot: { stroke: '#00f2'} },\n    { line: { stroke: '#f00' }, dot: { stroke: '#f002'} }\n];\n\nconst ClientGraph = new Component('#graphs', {\n    setup: async function() {\n        const points = await fetch(\"points.json\", {\n                headers: {\"content-type\": \"text/plain\"},\n                method: \"GET\",\n                mode: 'cors'\n        });\n        this.points_json = await points.json();\n        this.all_vars = this.points_json.vars;\n        this.$variables = this.elt.querySelector(\"#variables\");\n        this.$functions = this.elt.querySelector(\"#functions\");\n        await this.render(this.all_vars[0], ['start', 'end']);\n    },\n\n    render_variables: function($elt, selected_var_name, selected_functions) {\n        $elt.replaceChildren(\n            Element(\"select\", {\n                oninput: (e) => this.render(e.target.value, selected_functions),\n            }, this.all_vars.map(v =>\n                Element(\"option\", {\n                    value: v,\n                    selected: selected_var_name == v,\n                }, v)\n            )));\n    },\n\n    render_functions: function($elt, selected_var_name, selected_functions) {\n        const toggle = (option, options) => options.includes(option) ? options.filter(o => o != option) : [...options, option]\n\n        // this.points_json.error is a dictionary where keys are indices \"1\", \"2\", ..., \"n\".\n        // The values for each key is broken up into two parts : error_type and actual error values\n        // error_type is the first element in the list value with 1...n being the remianing values\n        // Types of error type is \"start\", \"end\", \"target1\", \"target2\", ..., \"targetm\" \n\n        var curr_list = []\n        let i = 0\n\n        for (const key in this.points_json.error) {\n            const error_type = this.points_json.error[key][0]\n            const line = colors[i % colors.length].line\n            \n            let description\n            \n            if (error_type === \"start\") {\n                description = \"Initial program\"\n            } else if (error_type === \"end\") {\n                description = \"Most accurate alternative\"\n            } else {\n                description = \"Developer Target \" + error_type.slice(\"target\".length)\n            }\n\n            curr_list.push( Element(\"label\", [\n                Element(\"input\", {\n                    type: \"checkbox\",\n                    style: \"accent-color: \" + line.stroke,\n                    checked: selected_functions.includes(error_type),\n                    onclick: (e) => this.render(selected_var_name, toggle(error_type, selected_functions))\n                }, []),\n                Element(\"span\", { className: \"functionDescription\" }, [\n                    \" \", description]),\n            ]))\n\n            i += 1\n        }\n\n        $elt.replaceChildren.apply(\n            $elt,\n            curr_list,\n        );\n    },\n    \n    sliding_window: function(A, size) {\n        const half = Math.floor(size / 2)\n        const running_sum = A.reduce((acc, v) => (acc.length > 0 ? acc.push(v.y + acc[acc.length - 1]) : acc.push(v.y), acc), [])\n        return running_sum.reduce((acc, v, i) => {\n            const length = \n                  (i - half) < 0 ? half + i\n                  : (i + half) >= running_sum.length ? (running_sum.length - (i - half))\n                  : size\n            const top =\n                  (i + half) >= running_sum.length ? running_sum[running_sum.length - 1]\n                  : running_sum[i + half]\n            const bottom =\n                  (i - half) < 0 ? 0\n                  : running_sum[i - half]\n            acc.push({average: (top - bottom) / length, x: A[i].x, length})\n            return acc\n        }, [])\n    },\n\n    plot: async function(varName, function_names) {\n        const functionMap = new Map()\n\n        for (const key in this.points_json.error) {\n            if (this.points_json.error[key][1] !== false) {\n                // Error type -> Actual Error points\n                functionMap.set(this.points_json.error[key][0], this.points_json.error[key].slice(1))\n            }\n        }\n\n        const index = this.all_vars.indexOf(varName)\n        // NOTE ticks and splitpoints include all vars, so we must index\n        const { bits, points, error, ticks_by_varidx, splitpoints_by_varidx } = this.points_json\n        const ticks = ticks_by_varidx[index]\n        if (!ticks) {\n            return Element(\"div\", \"The function could not be plotted on the given range for this input.\")\n        }\n        const tick_strings = ticks.map(t => t[0])\n        const tick_ordinals = ticks.map(t => t[1])\n        const tick_0_index = tick_strings.indexOf(\"0\")\n\n        const grouped_data = points.map((p, i) => ({\n            input: p,\n            error: Object.fromEntries(function_names.map(name => ([name, functionMap.get(name)[i]])))\n        }))\n\n        const domain = [Math.min(...tick_ordinals), Math.max(...tick_ordinals)]\n\n        let splitpoints = splitpoints_by_varidx[index].map(p => {\n            return Plot.ruleX([p], { stroke: \"#888\" });\n        });\n        if (tick_strings.includes(\"0\")) {\n            splitpoints.push(Plot.ruleX([\n                tick_ordinals[tick_strings.indexOf(\"0\")]\n            ], { stroke: \"#888\" }));\n        }\n\n        let marks = []\n        let i = 0\n        for (let [name, _] of functionMap) {\n            const line = colors[i % colors.length].line\n            const dot = colors[i % colors.length].dot\n\n            i += 1\n\n            const key_fn = fn => (a, b) => fn(a) - fn(b)\n            const index = this.all_vars.indexOf(varName)\n            const data = grouped_data.map(({ input, error }) => ({\n                x: input[index],\n                y: 1 - error[name] / bits\n            })).sort(key_fn(d => d.x))\n                  .map(({ x, y }, i) => ({ x, y, i }))\n            const compress = (L, out_len, chunk_compressor = points => points[0]) => L.reduce((acc, pt, i) => i % Math.floor(L.length / out_len) == 0 ? (acc.push(chunk_compressor(L.slice(i, i + Math.floor(L.length / out_len)))), acc) : acc, [])\n            const bin_size = 128\n            const sliding_window_data = compress(\n                this.sliding_window(data, bin_size), 800, points => ({\n                    average: points.reduce((acc, e) => e.average + acc, 0) / points.length,\n                    x: points.reduce((acc, e) => e.x + acc, 0) / points.length\n                }))\n            marks = marks.concat([\n                Plot.dot(compress(data, 800), {\n                    x: \"x\", y: \"y\", r: 1.3,\n                    title: d => `x: ${d.x} \\n i: ${d.i} \\n bits of error: ${d.y}`,\n                    ...dot\n                }),\n                Plot.line(sliding_window_data, {\n                    x: \"x\",\n                    y: \"average\",\n                    strokeWidth: 2, ...line,\n                }),\n            ]);\n        }\n        const out = Plot.plot({\n            width: '800',\n            height: '300',\n            marks: splitpoints.concat(marks),\n            x: {\n                tickFormat: d => tick_strings[tick_ordinals.indexOf(d)],\n                ticks: tick_ordinals, label: varName,\n                line: true, grid: true,\n                domain,\n            },\n            y: { line: true, domain: [0, 1], tickFormat: \"%\",},\n            marginBottom: 0,\n            marginRight: 0,\n        });\n        out.setAttribute('viewBox', '0 0 820 320')\n        return out\n    },\n\n    render: async function(selected_var_name, selected_functions) {\n        this.render_variables(this.$variables, selected_var_name, selected_functions);\n        this.render_functions(this.$functions, selected_var_name, selected_functions);\n        let $svg = this.elt.querySelector(\"svg\");\n        this.elt.replaceChild(await this.plot(selected_var_name, selected_functions), $svg);\n    }\n})\n\n\nconst CostAccuracy = new Component('#cost-accuracy', {\n    setup: async function() {\n        const $svg = this.elt.querySelector(\"svg\");\n        const $tbody = this.elt.querySelector(\"tbody\");\n\n        let response = await fetch(\"../results.json\", {\n            headers: {\"content-type\": \"text/plain\"},\n            method: \"GET\",\n            mode: \"cors\",\n        });\n        let results_json = await response.json();\n        \n        // find right test by iterating through results_json\n        for (let test of results_json.tests) {\n            if (test.name == this.elt.dataset.benchmarkName) {\n                let [initial_pt, best_pt, rest_pts] = test[\"cost-accuracy\"];\n\n                let target_pts = test[\"target\"]\n                rest_pts = [best_pt].concat(rest_pts)\n\n                $svg.replaceWith(await this.plot(test, initial_pt, target_pts, rest_pts));\n                $tbody.replaceWith(await this.tbody(test, initial_pt, target_pts, rest_pts));\n                break;\n            }\n        }\n    },\n\n    plot: async function(benchmark, initial_pt, target_pts, rest_pts) {\n        const bits = benchmark[\"bits\"];\n\n        // The line differs from rest_pts in two ways:\n        // - We filter to the actual pareto frontier, in case points moved\n        // - We make a broken line to show the real Pareto frontier\n        let line = []\n        let last = null;\n        rest_pts.forEach((pt, i) => {\n            let target = \"alternative\" + (i + 1);\n            if (!document.getElementById(target)) return;\n            if (!last || pt[1] > last[1]) {\n                if (last) line.push([pt[0], last[1]]);\n                line.push([pt[0], pt[1]]);\n                last = pt;\n            }\n        })\n\n        const out = Plot.plot({\n            marks: [\n                Plot.line(line, {\n                    x: d => initial_pt[0]/d[0],\n                    y: d => 1 - d[1]/bits,\n                    stroke: \"#00a\", strokeWidth: 1, strokeOpacity: .2,\n                }),\n                Plot.dot(rest_pts, {\n                    x: d => initial_pt[0]/d[0],\n                    y: d => 1 - d[1]/bits,\n                    fill: \"#00a\", r: 3,\n                }),\n                Plot.dot([initial_pt], {\n                    x: d => initial_pt[0]/d[0],\n                    y: d => 1 - d[1]/bits,\n                    stroke: \"#d00\", symbol: \"square\", strokeWidth: 2\n                }),\n                target_pts && Plot.dot(target_pts, {\n                    x: d => initial_pt[0]/d[0],\n                    y: d => 1 - d[1]/bits,\n                    stroke: \"#080\", symbol: \"circle\", strokeWidth: 2\n                }),\n            ].filter(x=>x),\n            marginBottom: 0,\n            marginRight: 0,\n            width: '400',\n            height: '200',\n            x: { line: true, nice: true, tickFormat: c => c + \"×\" },\n            y: { nice: true, line: true, domain: [0, 1], tickFormat: \"%\" },\n        })\n        out.setAttribute('viewBox', '0 0 420 220')\n        return out\n    },\n\n    tbody: async function(benchmark, initial_pt, target_pts, rest_pts) {\n        const bits = benchmark[\"bits\"];\n        const initial_accuracy = 100*(1 - initial_pt[1]/bits);\n\n        let alt_number = 0;\n        return Element(\"tbody\", [\n            Element(\"tr\", [\n                Element(\"th\", \"Initial program\"),\n                Element(\"td\", initial_accuracy.toFixed(1) + \"%\"),\n                Element(\"td\", \"1.0×\")\n            ]),\n            rest_pts.map((d, i) => {\n                let target = \"alternative\" + (i + 1);\n                if (!document.getElementById(target)) return;\n                let accuracy = 100*(1 - d[1]/bits);\n                let speedup = initial_pt[0]/d[0];\n                alt_number++;\n                return Element(\"tr\", [\n                    Element(\"th\", [\n                        Element(\"a\", { href: \"#\" + target}, \"Alternative \" + alt_number) \n                    ]),\n                    Element(\"td\", { className: accuracy >= initial_accuracy ? \"better\" : \"\" },\n                            accuracy.toFixed(1) + \"%\"),\n                    Element(\"td\", { className: speedup >= 1 ? \"better\" : \"\" },\n                            speedup.toFixed(1) + \"×\")\n            ])}),\n\n            target_pts && target_pts.map((d, i) => {\n                let accuracy = 100*(1 - d[1]/bits);\n                let speedup = initial_pt[0]/d[0];\n                return Element(\"tr\", [\n                    Element(\"th\", \n                        Element(\"a\", { href: \"#target\" + (i + 1)},\n                            \"Developer Target \" + (i + 1))),\n                    Element(\"td\", { className: accuracy >= initial_accuracy ? \"better\" : \"\" },\n                            accuracy.toFixed(1) + \"%\"),\n                    Element(\"td\", { className: speedup >= 1 ? \"better\" : \"\" },\n                            speedup.toFixed(1) + \"×\")\n            ])}),\n        ]);\n    }\n});\n\nvar RenderMath = new Component(\".math\", {\n    depends: function() {\n        if (typeof window.renderMathInElement === \"undefined\") throw \"KaTeX unavailable\";\n    },\n    setup: function() {\n        renderMathInElement(this.elt);\n    },\n});\n\nvar Timeline = new Component(\".timeline\", {\n    setup: function() {\n        var ts = this.elt.querySelectorAll(\".timeline-phase\");\n        for (var i = 0; i < ts.length; i++) {\n            var timespan = +ts[i].getAttribute(\"data-timespan\");\n            var type = ts[i].getAttribute(\"data-type\");\n            ts[i].style.flexGrow = timespan;\n            ts[i].title = type + \" (\" + Math.round(timespan/100)/10 + \"s)\";\n        }\n    }\n});\n\nvar Bogosity = new Component(\".bogosity\", {\n    setup: function() {\n        var ts = this.elt.children;\n        for (var i = 0; i < ts.length; i++) {\n            var timespan = +ts[i].getAttribute(\"data-timespan\");\n            ts[i].style.flexGrow = timespan;\n        }\n    }\n});\n\nvar Implementations = new Component(\".programs\", {\n    setup: function() {\n        this.dropdown = this.elt.querySelector(\"select\");\n        this.programs = this.elt.querySelectorAll(\".implementation\");\n        this.elt.addEventListener(\"change\", this.change);\n        this.change();\n    },\n    change: function() {\n        var lang = this.dropdown.options[this.dropdown.selectedIndex].text;\n        for (var i = 0; i < this.programs.length; i++) {\n            var $prog = this.programs[i];\n            if ($prog.dataset[\"language\"] == lang) {\n                $prog.style.display = \"block\";\n            } else {\n                $prog.style.display =  \"none\";\n            }\n        }\n    },\n});\n\nfunction pct(val, base) {\n    return Math.floor(val/base * 10000) / 100 + \"%\";\n}\n\nfunction time(s) {\n    return Math.floor(s / 1000 * 100) / 100 + \"s\";\n}\n\nfunction path(p) {\n    if (!p) {\n        return \"???\";\n    } else if (p[0] == \"/\") {\n        var r = p.substr(p.toLowerCase().indexOf(\"/racket\") + 1);\n        var ds = r.split(\"/\");\n        if (ds[1] == \"share\" && ds[2] == \"pkgs\") {\n            return \"/\" + ds.slice(3).join(\"/\");\n        } else if (ds[1] == \"collects\") {\n            return \"/\" + ds.slice(2).join(\"/\");\n        } else {\n            return \"/\" + ds.join(\"/\");\n        }\n    } else {\n        return p;\n    }\n}\n\nvar Profile = new Component(\"#profile\", {\n    setup: function() {\n        var text = this.elt.querySelector(\".load-text\");\n        fetch(\"profile.json\")\n            .then(response => response.json())\n            .catch(function(error) { text.textContent = \"Error loading profile data\" })\n            .then(data => this.render(data))\n    },\n    render: function(json) {\n        this.json = json;\n        this.search = Element(\"input\", {\n            placeholder: \"Search for a function...\",\n            autocomplete: \"off\",\n            name: \"profilefn\",\n        }, []);\n        this.search.setAttribute(\"list\", \"profilefns\");\n        var form = Element(\"form\", { method: \"GET\", action: \"\" }, [\n            this.search,\n            Element(\"datalist\", { id: \"profilefns\" }, [\n                json.nodes.map(n => n.id && Element(\"option\", n.id))\n            ]),\n        ]);\n        form.addEventListener(\"submit\", this.doSearch);\n        this.elt.appendChild(form);\n        this.elt.appendChild(this.mkNode(json.nodes[json.nodes[0].callees[0].callee]));\n        this.elt.classList.add(\"loaded\");\n    },\n    mkNode: function(node) {\n        var that = this;\n        var nelt = Element(\"div\", { className: \"node\" }, [\n            Element(\"a\", { className: \"name delete\" }, node.id || \"???\"),\n            Element(\"span\", { className: \"path\" }, path(node.src)),\n            Element(\"span\", {\n                className: \"pct\",\n                title: \"Self-time: \" + pct(node.self, that.json.cpu_time) }, [\n                    time(node.total),\n                ]),\n        ]);\n        var elt = Element(\"div\", { className: \"profile-row\" }, [\n            node.callers.sort((e1, e2) => e1.caller_time - e2.caller_time).map(function(edge) {\n                var other = that.json.nodes[edge.caller];\n                elt = Element(\"div\", { className: \"edge\" }, [\n                    Element(\"a\", { className: \"name\" }, other.id || \"???\"),\n                    Element(\"span\", { className: \"path\" }, path(other.src)),\n                    Element(\"span\", { className: \"pct\" }, pct(edge.caller_time, node.total)),\n                ]);\n                elt.children[0].addEventListener(\"click\", that.addElt(other));\n                return elt;\n            }),\n            nelt,\n            node.callees.sort((e1, e2) => e2.callee_time - e1.callee_time).map(function(edge) {\n                var other = that.json.nodes[edge.callee];\n                elt = Element(\"div\", { className: \"edge\" }, [\n                    Element(\"a\", { className: \"name\" }, other.id || \"???\"),\n                    Element(\"span\", { className: \"path\" }, path(other.src)),\n                    Element(\"span\", { className: \"pct\" }, pct(edge.callee_time, node.total)),\n                ]);\n                elt.children[0].addEventListener(\"click\", that.addElt(other));\n                return elt;\n            }),\n        ]);\n        nelt.children[0].addEventListener(\"click\", function() { elt.remove(); });\n        return elt;\n    },\n    addElt: function(other) {\n        var that = this;\n        return function() {\n            var newelt = that.mkNode(other)\n            that.elt.appendChild(newelt);\n            newelt.scrollTo();\n            return newelt;\n        }\n    },\n    doSearch: function(e) {\n        e.preventDefault();\n        var term = this.search.value;\n        var elt = this.addElt(this.json.nodes.find(n => n.id == term))();\n        elt.scrollTo();\n        this.search.value = \"\";\n        return false;\n    }\n})\n\nfunction makelabel(i, base, factor) {\n    var num = i;\n    var den = 1;\n\n    if (base > 0) num *= Math.pow(10, base);\n    else if (base < 0) den *= Math.pow(10, -base);\n\n    if (factor > 0) num *= Math.pow(2, factor);\n    if (factor < 0) den *= Math.pow(2, -factor);\n\n    return num / den;\n}\n\nfunction histogram(id, xdata, ydata, options) {\n    var width = options?.width ?? 676;\n    var height = options?.height ?? 60;\n    var margin = 5;\n    var labels = 10;\n    var ticks = 5;\n    var bucketnum = options?.buckets ?? 25;\n    var bucketwidth = Math.round(width / bucketnum);\n\n    var canvas = document.getElementById(id);\n    if (xdata.length == 0 || (ydata && xdata.length != ydata.length)) { return canvas.remove(); }\n\n    canvas.setAttribute(\"width\", margin + width + margin + \"px\");\n    canvas.setAttribute(\"height\", labels + margin + height + ticks + margin + labels + \"px\");\n    var ctx = canvas.getContext(\"2d\");\n      \n    ctx.beginPath();\n    ctx.strokeStyle = \"black\";\n    ctx.moveTo(margin, labels + margin + height);\n    ctx.lineTo(margin + width, labels + margin + height);\n    ctx.stroke();\n    \n    var xma = options?.max ?? Math.max.apply(null, xdata);\n      \n    var buckets = Array(bucketnum);\n    var sum = 0;\n    buckets.fill(0);\n    for (var i = 0; i < xdata.length; i++) {\n        var j = Math.floor(xdata[i] / xma * buckets.length);\n        var weight = ydata ? ydata[i] : xdata[i];\n        buckets[Math.min(j, buckets.length-1)] += weight;\n        sum += weight;\n    }\n    var yma = Math.max.apply(null, buckets);\n    \n    ctx.fillStyle = \"rgba(0, 0, 0, .2)\";\n    for (var i = 0; i < buckets.length; i++) {\n        ctx.fillRect(margin + i/buckets.length*width, labels + margin + height, width/buckets.length, -height*buckets[i]/yma);\n    }\n\n    ctx.fillStyle = \"black\";\n    ctx.textBaseline = \"bottom\";\n    ctx.textAlign = \"center\";\n    for (var i = 0; i < buckets.length; i++) {\n        if (buckets[i] == 0) continue;\n        ctx.fillText(Math.round(buckets[i] / sum * 100) + \"%\", margin + (i + .5)/buckets.length * width, labels + height*(1 - buckets[i]/yma));\n    }\n    \n    ctx.textBaseline = \"top\";\n    var base = Math.round(Math.log10(xma)) - 1\n    var step = Math.pow(10, base);\n\n    var factor;\n    if (xma / step > 20) factor = +1;\n    else if (xma / step < 10) factor = -1;\n    else factor = 0;\n\n    step *= Math.pow(2, factor);\n\n    for (var i = 0; i < 10 * Math.sqrt(10); i++) {\n        var pos = i * step;\n        if (pos > xma) break;\n        ctx.beginPath();\n        ctx.moveTo(pos / xma * width + margin, labels + margin + height);\n        ctx.lineTo(pos / xma * width + margin, labels + margin + height + ticks);\n        var label = makelabel(i, base, factor);\n        ctx.fillText(label, pos / xma * width + margin, labels + margin + height + ticks + margin);\n        ctx.stroke();\n    }\n}\n\nfunction run_components() {\n    for (var i = 0; i < window.COMPONENTS.length; i++) {\n        var component = window.COMPONENTS[i];\n        var elts = document.querySelectorAll(component.selector);\n\n        try {\n            if (elts.length > 0 && component.fns.depends) component.fns.depends();\n        } catch (e) {\n            console.error(e);\n            continue;\n        }\n\n        for (var j = 0; j < elts.length; j++) {\n            var instance = new ComponentInstance(elts[j], component);\n            console.log(\"Initiating\", component.selector, \"component at\", elts[j]);\n            try {\n                instance.setup();\n            } catch (e) {\n                console.error(e);\n            }\n        }\n    }\n}\n\nwindow.addEventListener(\"load\", run_components);\n"
  },
  {
    "path": "src/reports/timeline.rkt",
    "content": "#lang racket\n(require json\n         (only-in xml write-xexpr xexpr?)\n         racket/date)\n(require \"../utils/common.rkt\"\n         \"data.rkt\"\n         \"common.rkt\"\n         \"../syntax/platform.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/float.rkt\"\n         \"../config.rkt\"\n         \"../syntax/batch.rkt\")\n(provide make-timeline)\n\n(define timeline-phase? (hash/c symbol? any/c))\n(define timeline? (listof timeline-phase?))\n\n;; This first part handles timelines for a single Herbie run\n\n(define (make-timeline name timeline #:info [info #f] #:path [path \".\"])\n  `(html (head (meta ([charset \"utf-8\"]))\n               (title \"Metrics for \" ,(~a name))\n               (link ([rel \"stylesheet\"] [type \"text/css\"]\n                                         [href ,(if info \"report.css\" \"../report.css\")]))\n               (script ([src ,(if info \"report.js\" \"../report.js\")])))\n         (body ,(render-menu (~a name)\n                             #:path path\n                             (if info\n                                 `((\"Report\" . \"index.html\"))\n                                 `((\"Details\" . \"graph.html\"))))\n               ,(if info\n                    (render-about info)\n                    \"\")\n               ,(render-timeline timeline)\n               ,(render-profile))))\n\n(define/contract (render-timeline timeline)\n  (-> timeline? xexpr?)\n  (define time (apply + (map (curryr dict-ref 'time) timeline)))\n  `(section\n    ([id \"process-info\"])\n    (p ((class \"header\")) \"Time bar (total: \" (span ((class \"number\")) ,(format-time time)) \")\")\n    (div ((class \"timeline\"))\n         ,@(for/list ([n (in-naturals)]\n                      [curr timeline])\n             `(div ((class ,(format \"timeline-phase timeline-~a\" (dict-ref curr 'type)))\n                    [data-id ,(format \"timeline~a\" n)]\n                    [data-type ,(~a (dict-ref curr 'type))]\n                    [data-timespan ,(~a (dict-ref curr 'time))]))))\n    ,@(for/list ([phase timeline]\n                 [n (in-naturals)])\n        (render-phase phase n time))))\n\n(define/contract (render-phase curr n total-time)\n  (-> timeline-phase? integer? real? xexpr?)\n  (define time (dict-ref curr 'time))\n  (define type (dict-ref curr 'type))\n\n  `(div ((class ,(format \"timeline-block timeline-~a\" type)) [id ,(format \"timeline~a\" n)])\n        (h3 (a ([href ,(format \"#timeline~a\" n)]) ,(~a type))\n            (span ((class \"time\")) ,(format-time time) \" (\" ,(format-percent time total-time) \")\"))\n        (dl ,@(dict-call curr render-phase-memory 'memory 'gc-time)\n            ,@(dict-call curr render-phase-algorithm 'method)\n            ,@(dict-call curr render-phase-accuracy 'accuracy 'oracle 'baseline)\n            ,@(dict-call curr render-phase-pruning 'kept)\n            ,@(dict-call curr render-phase-error 'min-error)\n            ,@(dict-call curr render-phase-egraph 'egraph)\n            ,@(dict-call curr render-phase-stop 'stop)\n            ,@(dict-call curr render-phase-counts 'count)\n            ,@(dict-call curr render-phase-alts/shared 'alts 'batch)\n            ,@(dict-call curr render-phase-inputs 'inputs 'outputs)\n            ,@(dict-call curr render-phase-times 'times)\n            ,@(dict-call curr render-phase-series 'series)\n            ,@(dict-call curr render-phase-bstep 'bstep)\n            ,@(dict-call curr render-phase-branches 'branch 'batch)\n            ,@(dict-call curr render-phase-sampling 'sampling)\n            ,@(dict-call curr (curryr simple-render-phase \"Symmetry\") 'symmetry)\n            ,@(dict-call curr render-phase-outcomes 'outcomes)\n            ,@(dict-call curr render-phase-compiler 'compiler)\n            ,@(dict-call curr render-phase-mixed-sampling 'mixsample)\n            ,@(dict-call curr render-phase-bogosity 'bogosity)\n            ,@(dict-call curr render-phase-allocations 'allocations))))\n\n(define/reset id-counter 0)\n\n(define (make-id)\n  (id-counter (+ 1 (id-counter)))\n  (id-counter))\n\n(define (dict-call d f . args)\n  (if (andmap (curry dict-has-key? d) args)\n      (apply f (map (curry dict-ref d) args))\n      '()))\n\n(define (render-phase-algorithm algorithm)\n  `((dt \"Algorithm\")\n    (dd (table ((class \"times\"))\n               ,@(for/list ([alg (in-list (sort (group-by identity algorithm) > #:key length))])\n                   `(tr (td ,(~r (length alg) #:group-sep \" \") \"×\") (td ,(~a (car alg)))))))))\n\n(define (render-phase-bogosity bogosity)\n  (match-define (list domain-info) bogosity)\n  (define total (round (apply + (hash-values domain-info))))\n\n  (define tags '(valid unknown infinite unsamplable invalid precondition))\n\n  `((dt \"Bogosity\") (dd (div ((class \"bogosity\"))\n                             ,@(for/list ([tag tags])\n                                 `(div ((class ,(format \"bogosity-~a\" tag))\n                                        [data-id ,(format \"bogosity-~a\" tag)]\n                                        [data-type ,(~a tag)]\n                                        [data-timespan ,(~a (hash-ref domain-info tag 0))]\n                                        [title\n                                         ,(format \"~a (~a)\"\n                                                  tag\n                                                  (format-percent (hash-ref domain-info tag 0)\n                                                                  total))])))))))\n\n(define (format-value v)\n  (cond\n    [(real? v) (~a v)]\n    [(equal? (hash-ref v 'type) \"real\") (hash-ref v 'value)]\n    [else\n     (define repr-name (hash-ref v 'type))\n     (define repr (get-representation (read (open-input-string repr-name))))\n     (value->string ((representation-ordinal->repr repr) (string->number (hash-ref v 'ordinal)))\n                    repr)]))\n\n(define (render-phase-bstep iters)\n  `((dt \"Steps\") (dd (table (tr (th \"Time\") (th \"Left\") (th \"Right\"))\n                            ,@(for/list ([rec (in-list iters)])\n                                (match-define (list time v1 v2) rec)\n                                `(tr (td ,(format-time time))\n                                     (td (pre ,(format-value v1)))\n                                     (td (pre ,(format-value v2)))))))))\n\n(define (render-phase-egraph iters)\n  (define costs (map third iters))\n  (define last-useful-iter (last (filter (compose (curry = (apply min costs)) third) iters)))\n  `((dt \"Iterations\") (dd (p \"Useful iterations: \"\n                             ,(~a (first last-useful-iter))\n                             \" (\"\n                             ,(format-time (fourth last-useful-iter))\n                             \")\")\n                          (table ((class \"times\"))\n                                 (tr (th \"Iter\") (th \"Nodes\") (th \"Cost\"))\n                                 ,@(for/list ([rec (in-list (reverse iters))])\n                                     (match-define (list iter nodes cost t) rec)\n                                     `(tr (td ,(~a iter)) (td ,(~a nodes)) (td ,(~a cost))))))))\n\n(define (render-phase-stop data)\n  (match-define (list (list reasons counts) ...) (sort data > #:key second))\n  `((dt \"Stop Event\") (dd (table ((class \"times\"))\n                                 ,@(for/list ([reason reasons]\n                                              [count counts])\n                                     `(tr (td ,(~r count #:group-sep \" \") \"×\") (td ,(~a reason))))))))\n\n(define (average . values)\n  (/ (apply + values) (length values)))\n\n(define (render-phase-mixed-sampling mixsample)\n  (define total-time (apply + (map first mixsample)))\n  (define (format-memory-bytes bytes)\n    (format \"~a MiB\" (~r (/ bytes (expt 2 20)) #:precision '(= 1))))\n  `((dt \"Precisions\")\n    (dd (details\n         (summary \"Click to see histograms. Total time spent on operations: \"\n                  ,(format-time total-time))\n         ,@(map first\n                (sort (for/list ([rec (in-list (group-by second mixsample))]) ; group by operator\n                        ; rec = '('(time op precision) ... '(time op precision))\n                        (define n (random 100000))\n                        (define op (second (car rec)))\n                        (define precisions (map third rec))\n                        (define times (map first rec))\n                        (define memories (map fourth rec))\n\n                        (define time-per-op (round (apply + times)))\n                        (define memory-per-op (apply + memories))\n\n                        (list `(details (summary (code ,op)\n                                                 \": \"\n                                                 ,(format-time time-per-op)\n                                                 \" (\"\n                                                 ,(format-percent time-per-op total-time)\n                                                 \" of total, \"\n                                                 ,(format-memory-bytes memory-per-op)\n                                                 \")\")\n                                        (canvas ([id ,(format \"calls-~a\" n)]\n                                                 [title\n                                                  \"Histogram of precisions of the used operation\"]))\n                                        (script \"histogram(\\\"\"\n                                                ,(format \"calls-~a\" n)\n                                                \"\\\", \"\n                                                ,(jsexpr->string precisions)\n                                                \", \"\n                                                ,(jsexpr->string times)\n                                                \", \"\n                                                \"{\\\"max\\\" : \"\n                                                ,(~a (*max-mpfr-prec*))\n                                                \"})\"))\n                              time-per-op))\n                      >\n                      #:key second))))))\n\n(define (render-phase-sampling sampling)\n  (define total (round (apply + (hash-values (cadr (car sampling))))))\n  (define fields\n    '((\"Valid\" . valid) (\"Unknown\" . unknown)\n                        (\"Precondition\" . precondition)\n                        (\"Infinite\" . infinite)\n                        (\"Domain\" . invalid)\n                        (\"Can't\" . unsamplable)))\n  `((dt \"Search\") (dd (table ((class \"times\"))\n                             (tr (th \"Probability\")\n                                 ,@(for/list ([(name sym) (in-dict fields)])\n                                     `(th ,name))\n                                 (th \"Iter\"))\n                             ,@(for/list ([(n table) (in-dict (sort sampling < #:key first))])\n                                 `(tr (td ,(format-percent (hash-ref (car table) 'valid 0)\n                                                           (+ (hash-ref (car table) 'valid 0)\n                                                              (hash-ref (car table) 'unknown 0))))\n                                      ,@(for/list ([(name sym) (in-dict fields)])\n                                          `(td ,(format-percent (hash-ref (car table) sym 0) total)))\n                                      (td ,(~a n))))))))\n\n(define (simple-render-phase info name)\n  (if (positive? (length (first info)))\n      `((dt ,name) (dd ,@(map (lambda (s) `(p ,(~a s))) (first info))))\n      empty))\n\n(define (render-phase-accuracy accuracy oracle baseline)\n  (define rows\n    (sort (for/list ([acc accuracy]\n                     [ora oracle]\n                     [bas baseline])\n            (list (- acc ora) (- bas acc)))\n          >\n          #:key first))\n\n  (define bits (map first rows))\n  (define total-remaining (apply + accuracy))\n\n  `((dt \"Accuracy\") (dd (p \"Total \"\n                           ,(format-bits (apply + bits) #:unit #t)\n                           \" remaining\"\n                           \" (\"\n                           ,(format-percent (apply + bits) total-remaining)\n                           \")\"\n                           (p \"Threshold costs \"\n                              ,(format-bits (apply + (filter (curry > 1) bits)))\n                              \"b\"\n                              \" (\"\n                              ,(format-percent (apply + (filter (curry > 1) bits)) total-remaining)\n                              \")\")\n                           ,@(if (> (length rows) 1)\n                                 `((table ((class \"times\"))\n                                          ,@(for/list ([rec (in-list rows)]\n                                                       [_ (in-range 5)])\n                                              (match-define (list left gained) rec)\n                                              `(tr (td ,(format-bits left #:unit #t))\n                                                   (td ,(format-percent gained (+ left gained)))))))\n                                 '())))))\n\n(define (render-phase-pruning kept-data)\n  (match-define (list kept) kept-data)\n  (define (altnum kind [col #f])\n    (define rec (hash-ref kept kind))\n    (match col\n      [#f (first rec)]\n      [0 (- (first rec) (second rec))]\n      [1 (second rec)]))\n  (define kept-alts (+ (altnum 'new 1) (altnum 'fresh 1)))\n  (define done-alts (+ (altnum 'done 1) (altnum 'picked 1)))\n  `((dt \"Pruning\")\n    (dd (p ,(~a (+ kept-alts done-alts))\n           \" alts after pruning (\"\n           ,(~a kept-alts)\n           \" fresh and \"\n           ,(~a done-alts)\n           \" done)\")\n        (table\n         ((class \"states\"))\n         (thead (tr (th) (th \"Pruned\") (th \"Kept\") (th \"Total\")))\n         (tbody ,@(for/list ([type '(new fresh picked done)])\n                    `(tr (th ,(string-titlecase (~a type)))\n                         (td ,(~r (altnum type 0) #:group-sep \" \"))\n                         (td ,(~r (altnum type 1) #:group-sep \" \"))\n                         (td ,(~r (altnum type) #:group-sep \" \")))))\n         (tfoot\n          (tr (th \"Total\")\n              (td ,(~r (apply + (map (curryr altnum 0) '(new fresh picked done))) #:group-sep \" \"))\n              (td ,(~r (apply + (map (curryr altnum 1) '(new fresh picked done))) #:group-sep \" \"))\n              (td ,(~r (apply + (map altnum '(new fresh picked done))) #:group-sep \" \"))))))))\n\n(define (render-phase-memory mem gc-time)\n  (match-define (list live alloc) (car mem))\n  `((dt \"Memory\") (dd ,(~r (/ live (expt 2 20)) #:group-sep \" \" #:precision '(= 1))\n                      \"MiB live, \"\n                      ,(~r (/ alloc (expt 2 20)) #:group-sep \" \" #:precision '(= 1))\n                      \"MiB allocated; \"\n                      ,(format-time gc-time)\n                      \" collecting garbage\")))\n\n(define (render-phase-error min-error-table)\n  (match-define (list min-error repr-name) (car min-error-table))\n  (define repr (get-representation (read (open-input-string repr-name))))\n  `((dt \"Accuracy\") (dd ,(format-accuracy min-error repr #:unit \"%\") \"\")))\n\n(define (render-phase-counts alts)\n  `((dt \"Counts\") ,@(for/list ([rec (in-list alts)])\n                      (match-define (list inputs outputs) rec)\n                      `(dd ,(~r inputs #:group-sep \" \") \" → \" ,(~r outputs #:group-sep \" \")))))\n\n(define (render-phase-alts/shared alts shared-batch)\n  (match-define (list (? hash? shared-batch*)) shared-batch)\n  (define nodes (hash-ref shared-batch* 'nodes))\n  (define (single-root-jsexpr root)\n    (hash 'nodes nodes 'roots (list root)))\n  `((dt \"Alt Table\")\n    (dd (details (summary \"Click to see full alt table\")\n                 (table ((class \"times\"))\n                        (thead (tr (th \"Status\") (th \"Accuracy\") (th \"Program\")))\n                        ,@\n                        (for/list ([rec (in-list alts)])\n                          (match-define (list root status score repr-name) rec)\n                          (define repr (get-representation (read (open-input-string repr-name))))\n                          `(tr ,(match status\n                                  [\"next\" `(td (span ([title \"Selected for next iteration\"]) \"▶\"))]\n                                  [\"done\" `(td (span ([title \"Selected in a prior iteration\"]) \"✓\"))]\n                                  [\"fresh\" `(td)])\n                               (td ,(format-accuracy score repr #:unit \"%\") \"\")\n                               (td (pre ,(jsexpr->batch-exprs (single-root-jsexpr root)))))))))))\n\n(define (render-phase-times times)\n  (define hist-id (make-id))\n  `((dt \"Calls\")\n    (dd (p ,(~r (length times) #:group-sep \" \") \" calls:\")\n        (canvas ([id ,(format \"calls-~a\" hist-id)]\n                 [title\n                  \"Weighted histogram; height corresponds to percentage of runtime in that bucket.\"]))\n        (script ,(format \"histogram('calls-~a', \" hist-id) ,(jsexpr->string (map first times)) \")\")\n        (table ((class \"times\"))\n               ,@(for/list ([rec (in-list (sort times > #:key first))]\n                            [_ (in-range 5)])\n                   (match-define (list time batch-jsexpr) rec)\n                   `(tr (td ,(format-time time)) (td (pre ,(jsexpr->batch-exprs batch-jsexpr)))))))))\n\n(define (render-phase-series times)\n  (define hist-id (make-id))\n  `((dt \"Calls\")\n    (dd (p ,(~a (length times)) \" calls:\")\n        (canvas ([id ,(format \"calls-~a\" hist-id)]\n                 [title\n                  \"Weighted histogram; height corresponds to percentage of runtime in that bucket.\"]))\n        (script ,(format \"histogram('calls-~a', \" hist-id) ,(jsexpr->string (map first times)) \")\")\n        (table ((class \"times\"))\n               (thead (tr (th \"Time\") (th \"Variable\") (th \"Point\")))\n               ,@(for/list ([rec (in-list (sort times > #:key first))]\n                            [_ (in-range 5)])\n                   (match-define (list time var transform) rec)\n                   `(tr (td ,(format-time time)) (td (pre ,var)) (td ,transform)))))))\n\n(define (render-phase-compiler compiler)\n  (match-define (list (list sizes compileds) ...) compiler)\n  (define size (apply + sizes))\n  (define compiled (apply + compileds))\n  `((dt \"Compiler\") (dd (p \"Compiled \"\n                           ,(~r size #:group-sep \" \")\n                           \" to \"\n                           ,(~r compiled #:group-sep \" \")\n                           \" computations \"\n                           \"(\"\n                           ,(format-percent (- size compiled) size)\n                           \" saved)\"))))\n\n(define (render-phase-branches branches shared-batch)\n  (match-define (list (? hash? shared-batch*)) shared-batch)\n  (define (single-root-jsexpr root)\n    (hash 'nodes (hash-ref shared-batch* 'nodes) 'roots (list root)))\n  `((dt \"Results\")\n    (dd (table ((class \"times\"))\n               (thead (tr (th \"Accuracy\") (th \"Segments\") (th \"Branch\")))\n               ,@(for/list ([rec (in-list branches)])\n                   (match-define (list branch-root score splits repr-name) rec)\n                   (define repr (get-representation (read (open-input-string repr-name))))\n                   `(tr (td ,(format-accuracy score repr #:unit \"%\") \"\")\n                        (td ,(~a splits))\n                        (td (pre ,(jsexpr->batch-exprs (single-root-jsexpr branch-root))))))))))\n\n(define (render-phase-outcomes outcomes)\n  `((dt \"Samples\") (dd (table ((class \"times\"))\n                              ,@(for/list ([rec (in-list (sort outcomes > #:key first))])\n                                  (match-define (list time precision category count) rec)\n                                  `(tr (td ,(format-time time))\n                                       (td ,(~r count #:group-sep \" \") \"×\")\n                                       (td ,(~a precision))\n                                       (td ,(~a category))))))))\n\n(define (batch-jsexpr? x)\n  (and (hash? x) (hash-has-key? x 'nodes)))\n\n(define (jsexpr->exprs x)\n  (if (batch-jsexpr? x)\n      (jsexpr->batch-exprs x)\n      (string-join (map ~a x) \"\\n\")))\n\n(define (render-phase-inputs inputs outputs)\n  `((dt \"Calls\") (dd ,@(for/list ([input-jsexpr inputs]\n                                  [output-jsexpr outputs]\n                                  [n (in-naturals 1)])\n                         `(details (summary \"Call \" ,(~a n))\n                                   (table (thead (tr (th \"Inputs\")))\n                                          (tr (td (pre ,(jsexpr->exprs input-jsexpr)))))\n                                   (table (thead (tr (th \"Outputs\")))\n                                          (tr (td (pre ,(jsexpr->exprs output-jsexpr))))))))))\n\n(define (render-phase-allocations allocations)\n  (define sorted (sort allocations > #:key second))\n  (define total (apply + (map second sorted)))\n  `((dt \"Allocations\")\n    (dd (table ((class \"times\"))\n               (thead (tr (th \"Allocated\") (th \"Percent\") (th \"Phase\")))\n               ,@(for/list ([rec (in-list sorted)])\n                   (match-define (list type alloc) rec)\n                   `(tr (td ,(~r (/ alloc (expt 2 20)) #:group-sep \" \" #:precision '(= 1)) \" MiB\")\n                        (td ,(format-percent alloc total))\n                        (td (code ,(~a type)))))\n               (tfoot (tr (td ,(~r (/ total (expt 2 20)) #:group-sep \" \" #:precision '(= 1)) \" MiB\")\n                          (td ,(format-percent total total))\n                          (td (code \"total\"))))))))\n\n;; This next part handles summarizing several timelines into one details section for the report page.\n\n(define (render-about info)\n  (match-define (report-info date commit branch seed flags points iterations tests) info)\n\n  `(table ((id \"about\"))\n          (tr (th \"Date:\") (td ,(date->string date)))\n          (tr (th \"Commit:\")\n              (td (abbr ([title ,commit])\n                        ,(with-handlers ([exn:fail:contract? (const commit)])\n                           (substring commit 0 8)))\n                  \" on \"\n                  ,branch))\n          (tr (th \"Seed:\") (td ,(~a seed)))\n          (tr (th \"Parameters:\")\n              (td ,(~a (*num-points*)) \" points for \" ,(~a (*num-iterations*)) \" iterations\"))\n          (tr (th \"Flags:\")\n              (td ((id \"flag-list\"))\n                  (div ((id \"all-flags\"))\n                       ,@(for*/list ([(class flags) (*flags*)]\n                                     [flag flags])\n                           `(kbd ,(~a class) \":\" ,(~a flag))))\n                  (div ((id \"changed-flags\"))\n                       ,@(if (null? (changed-flags))\n                             '(\"default\")\n                             (for/list ([rec (in-list (changed-flags))])\n                               (match-define (list delta class flag) rec)\n                               `(kbd ,(match delta\n                                        ['enabled \"+o\"]\n                                        ['disabled \"-o\"])\n                                     \" \"\n                                     ,(~a class)\n                                     \":\"\n                                     ,(~a flag)))))))))\n\n(define (render-profile)\n  `(section ([id \"profile\"]) (h1 \"Profiling\") (p ((class \"load-text\")) \"Loading profile data...\")))\n"
  },
  {
    "path": "src/reports/traceback.rkt",
    "content": "#lang racket\n\n(require (only-in xml write-xexpr xexpr?))\n(require \"../utils/common.rkt\"\n         \"../syntax/read.rkt\"\n         \"common.rkt\")\n\n(provide make-traceback)\n\n(define (make-traceback result-hash)\n  (match (hash-ref result-hash 'status)\n    [\"timeout\" (render-timeout result-hash)]\n    [\"failure\" (render-failure result-hash)]\n    [status (error 'make-traceback \"unexpected status ~a\" status)]))\n\n(define (render-failure result-hash)\n  (define test (car (load-tests (open-input-string (hash-ref result-hash 'test)))))\n  (define warnings (hash-ref result-hash 'warnings))\n  (define backend (hash-ref result-hash 'backend))\n\n  ; unpack the exception\n  (match-define (list 'exn type msg url extra traceback) backend)\n\n  `(html\n    (head (meta ((charset \"utf-8\")))\n          (title \"Exception for \" ,(~a (test-name test)))\n          (link ((rel \"stylesheet\") (type \"text/css\") (href \"../report.css\")))\n          ,@js-tex-include\n          (script ([src \"../report.js\"])))\n    (body ,(render-menu (~a (test-name test))\n                        (list '(\"Report\" . \"../index.html\") '(\"Metrics\" . \"timeline.html\")))\n          ,(render-warnings warnings)\n          ,(render-specification test)\n          ,(if type\n               `(section ([id \"user-error\"] (class \"error\"))\n                         (h2 ,(~a msg) \" \" (a ([href ,url]) \"(more)\")))\n               \"\")\n          ,(if type\n               \"\"\n               `(,@(render-reproduction test #:bug? #t)\n                 (section ([id \"backtrace\"]) (h2 \"Backtrace\") ,(render-traceback msg traceback)))))))\n\n(define (render-loc loc)\n  (match loc\n    [(list file line col) `((td ,(~a file)) (td ,(~a line)) (td ,(~a col)))]\n    [#f `((td ([colspan \"3\"]) \"unknown\"))]))\n\n(define (render-traceback msg traceback)\n  `(table (thead (th ([colspan \"2\"]) ,msg) (th \"L\") (th \"C\"))\n          (tbody ,@(for/list ([(name loc) (in-dict traceback)])\n                     `(tr (td ((class \"procedure\")) ,(~a name)) ,@(render-loc loc))))))\n\n(define (render-timeout result-hash)\n  (define test (car (load-tests (open-input-string (hash-ref result-hash 'test)))))\n  (define time (hash-ref result-hash 'time))\n  (define warnings (hash-ref result-hash 'warnings))\n\n  `(html (head (meta ((charset \"utf-8\")))\n               (title \"Timeout for \" ,(~a (test-name test)))\n               (link ((rel \"stylesheet\") (type \"text/css\") (href \"../report.css\")))\n               ,@js-tex-include\n               (script ([src \"../report.js\"])))\n         (body ,(render-menu (~a (test-name test))\n                             (list '(\"Report\" . \"../index.html\") '(\"Metrics\" . \"timeline.html\")))\n               ,(render-warnings warnings)\n               ,(render-specification test)\n               (section ([id \"user-error\"] (class \"error\"))\n                        (h2 \"Timeout after \" ,(format-time time))\n                        (p \"Use the \" (code \"--timeout\") \" flag to change the timeout.\")))))\n"
  },
  {
    "path": "src/syntax/batch.rkt",
    "content": "#lang racket\n\n(require \"syntax.rkt\"\n         \"../utils/common.rkt\"\n         \"../utils/dvector.rkt\")\n\n(provide progs->batch ; List<Expr> -> (Batch, List<Batchref>)\n\n         expr-recurse\n         (struct-out batch)\n         batch-empty ; Batch\n         batch-push!\n         batch-add! ; Batch -> (or Expr Batchref Expr<Batchref>) -> Batchref\n         batch-copy-only!\n         batch-length ; Batch -> Integer\n         batch-tree-size ; Batch -> List<Batchref> -> Integer\n         batch-free-vars ; Batch -> (Batchref -> Set<Var>)\n         in-batch ; Batch -> Sequence<Node>\n         batch-reachable ; Batch -> List<Batchref> -> (Node -> Boolean) -> List<Batchref>\n         batch-exprs\n         batch-recurse\n         batch-get-nodes\n         batch->jsexpr\n         jsexpr->batch-exprs\n\n         (struct-out batchref)\n         deref) ; Batchref -> Expr\n\n;; Batches store these recursive structures, flattened\n(struct batch ([nodes #:mutable] [index #:mutable]))\n\n(struct batchref (batch idx) #:transparent)\n\n;; --------------------------------- CORE BATCH FUNCTION ------------------------------------\n\n(define (batch-empty)\n  (batch (make-dvector) (make-hash)))\n\n(define (in-batch batch [start 0] [end #f] [step 1])\n  (in-dvector (batch-nodes batch) start end step))\n\n(define (batch-get-nodes b)\n  (dvector->vector (batch-nodes b)))\n\n;; This function defines the recursive structure of expressions\n(define (expr-recurse expr f)\n  (match expr\n    [(approx spec impl) (approx (f spec) (f impl))]\n    [(hole precision spec) (hole precision (f spec))]\n    [(list op) (list op)]\n    [(list op arg1) (list op (f arg1))]\n    [(list op arg1 arg2) (list op (f arg1) (f arg2))]\n    [(list op arg1 arg2 arg3) (list op (f arg1) (f arg2) (f arg3))]\n    [(list op args ...) (cons op (map f args))]\n    [_ expr]))\n\n(define (batch-length b)\n  (dvector-length (batch-nodes b)))\n\n(define (batch-push! b term)\n  (define hashcons (batch-index b))\n  (batchref b (hash-ref! hashcons term (lambda () (dvector-add! (batch-nodes b) term)))))\n\n(define (batch-add! b expr)\n  (define (munge prog)\n    (match prog\n      [(batchref b* idx*)\n       (assert-batch-brf! b prog)\n       idx*]\n      [_ (batchref-idx (batch-push! b (expr-recurse prog munge)))]))\n  (batchref b (munge expr)))\n\n(define (deref x)\n  (match-define (batchref b idx) x)\n  (expr-recurse (dvector-ref (batch-nodes b) idx) (lambda (ref) (batchref b ref))))\n\n(define (progs->batch exprs #:vars [vars '()])\n  (define out (batch-empty))\n  (for ([var (in-list vars)])\n    (batch-push! out var))\n  (define brfs\n    (for/list ([expr (in-list exprs)])\n      (batch-add! out expr)))\n  (values out brfs))\n\n;; batch-recurse iterates only over its children\n;; A lot of parts of Herbie rely on that\n(define (batch-recurse batch f)\n  (define out (make-dvector (batch-length batch)))\n  (define visited (make-dvector (batch-length batch) #f))\n  (λ (brf)\n    (assert-batch-brf! batch brf)\n    (let loop ([brf brf])\n      (define idx (batchref-idx brf))\n      (cond\n        [(and (> (dvector-capacity visited) idx) (dvector-ref visited idx)) (dvector-ref out idx)]\n        [else\n         (define res (f brf loop))\n         (dvector-set! out idx res)\n         (dvector-set! visited idx #t)\n         res]))))\n\n(define (assert-batch-brf! batch . brfs)\n  (unless (andmap (compose (curry equal? batch) batchref-batch) brfs)\n    (error 'assert-batch-brf! \"One of batchrefs does not belong to the provided batch\")))\n\n;; Function returns indices of children nodes within a batch for given roots,\n;;   where a child node is a child of a root + meets a condition - (condition node)\n(define (batch-reachable batch brfs #:condition [condition (const #t)])\n  ; Little check\n  (apply assert-batch-brf! batch brfs)\n  (define len (batch-length batch))\n  (define child-mask (make-vector len #f))\n  (for ([brf (in-list brfs)])\n    (vector-set! child-mask (batchref-idx brf) #t))\n  (for ([i (in-range (sub1 len) -1 -1)]\n        [node (in-batch batch (sub1 len) -1 -1)]\n        [child (in-vector child-mask (sub1 len) -1 -1)]\n        #:when child)\n    (cond\n      [(condition node) (expr-recurse node (λ (n) (vector-set! child-mask n #t)))]\n      [else (vector-set! child-mask i #f)]))\n  ; Return batchrefs of children nodes in ascending order\n  (for/list ([child (in-vector child-mask)]\n             [i (in-naturals)]\n             #:when child)\n    (batchref batch i)))\n\n;; Function constructs a vector of expressions for the given nodes of a batch\n(define (batch-exprs batch)\n  (batch-recurse batch (lambda (brf recurse) (expr-recurse (deref brf) recurse))))\n\n;; Function constructs a vector of expressions for the given nodes of a batch\n(define (batch-copy-only! batch batch*)\n  (batch-recurse batch*\n                 (lambda (brf recurse)\n                   (batch-push! batch (expr-recurse (deref brf) (compose batchref-idx recurse))))))\n\n(define (batch-free-vars batch)\n  (batch-recurse batch\n                 (lambda (brf recurse)\n                   (define node (deref brf))\n                   (cond\n                     [(symbol? node) (set node)]\n                     [(approx? node) (recurse (approx-impl node))]\n                     [else\n                      (define arg-free-vars (mutable-set))\n                      (expr-recurse node (lambda (i) (set-union! arg-free-vars (recurse i))))\n                      arg-free-vars]))))\n\n(define (batch-tree-size batch brfs)\n  (define counts\n    (batch-recurse batch\n                   (lambda (brf recurse)\n                     (define args (reap [sow] (expr-recurse (deref brf) sow)))\n                     (apply + 1 (map recurse args)))))\n  (apply + (map counts brfs)))\n\n;; Converts a batch + roots to a JSON-compatible structure\n;; Returns: (hash 'nodes [...] 'roots [idx1 idx2 ...])\n;; Nodes are: atoms (symbols->strings, numbers) or [op-string idx1 idx2 ...]\n(define (batch->jsexpr b brfs)\n  (define batch* (batch-empty))\n  (define copy-f (batch-copy-only! batch* b))\n  (define brfs* (map copy-f brfs))\n  (define nodes\n    (for/list ([node (in-batch batch*)])\n      (match node\n        [(? symbol?) (~a node)]\n        [(? number?) (~a node)]\n        [(approx spec impl) (list \"approx\" spec impl)]\n        [(hole precision spec) (list \"hole\" (~a precision) spec)]\n        [(list op args ...) (cons (~a op) args)]\n        [_ (~a node)])))\n  (hash 'nodes nodes 'roots (map batchref-idx brfs*)))\n\n;; Converts a jsexpr batch to a single SSA-style string with O(n) size\n(define (jsexpr->batch-exprs jsexpr)\n  (define nodes (hash-ref jsexpr 'nodes))\n  (define roots (hash-ref jsexpr 'roots))\n  (define node-vec (list->vector nodes))\n\n  ;; Pass 0: mark only the part of the graph reachable from roots.\n  (define reachable? (make-vector (vector-length node-vec) #f))\n  (let loop ([stack roots])\n    (cond\n      [(null? stack) #t]\n      [(vector-ref reachable? (car stack)) (loop (cdr stack))]\n      [else\n       (define idx (car stack))\n       (vector-set! reachable? idx #t)\n       (match (vector-ref node-vec idx)\n         [(list _ args ...) (loop (append args (cdr stack)))]\n         [_ (loop (cdr stack))])]))\n\n  ;; Pass 1: count references to each node\n  (define ref-counts (make-vector (vector-length node-vec) 0))\n  (for ([root roots])\n    (vector-set! ref-counts root (+ 1 (vector-ref ref-counts root))))\n  (for ([i (in-naturals)]\n        [node (in-vector node-vec)]\n        [reachable (in-vector reachable?)]\n        #:when reachable)\n    (match node\n      [(list _ args ...)\n       (for ([arg (in-list args)])\n         (vector-set! ref-counts arg (+ 1 (vector-ref ref-counts arg))))]\n      ;; Never dedup constants & variables\n      [_ (vector-set! ref-counts i -inf.0)]))\n\n  ;; Pass 2: build expressions, using %N for multiply-referenced nodes\n  (define exprs (make-vector (vector-length node-vec) #f))\n  (for ([i (in-naturals)]\n        [node (in-vector node-vec)]\n        [reachable (in-vector reachable?)]\n        #:when reachable)\n    (vector-set! exprs\n                 i\n                 (match node\n                   [(list op args ...)\n                    (format \"(~a ~a)\"\n                            op\n                            (string-join (for/list ([arg (in-list args)])\n                                           (if (> (vector-ref ref-counts arg) 1)\n                                               (format \"%~a\" arg)\n                                               (vector-ref exprs arg)))))]\n                   [_ (~a node)])))\n\n  ;; Output: one line per multi-ref node, then root expressions\n  (define bindings\n    (for/list ([i (in-naturals)]\n               [reachable (in-vector reachable?)]\n               #:when reachable\n               #:when (> (vector-ref ref-counts i) 1))\n      (format \"%~a = ~a\" i (vector-ref exprs i))))\n  (define return-exprs\n    (for/list ([root roots])\n      (if (> (vector-ref ref-counts root) 1)\n          (format \"%~a\" root)\n          (vector-ref exprs root))))\n  (string-join (append bindings return-exprs) \"\\n\"))\n;; --------------------------------- TESTS ---------------------------------------\n\n; Tests for progs->batch and batch-exprs\n(module+ test\n  (require rackunit)\n  (define (test-munge-unmunge expr)\n    (define-values (batch brfs) (progs->batch (list expr)))\n    (check-equal? (list expr) (map (batch-exprs batch) brfs)))\n\n  (define (f64 x)\n    (literal x 'binary64))\n\n  (test-munge-unmunge '(* 1/2 (+ (exp x) (neg (/ 1 (exp x))))))\n  (test-munge-unmunge\n   '(+ 1 (neg (* 1/2 (+ (exp (/ (sin 3) (cos 3))) (/ 1 (exp (/ (sin 3) (cos 3)))))))))\n  (test-munge-unmunge '(cbrt x))\n  (test-munge-unmunge (list 'x))\n  (test-munge-unmunge `(+.f64 (sin.f64 ,(approx '(* 1/2 (+ (exp x) (neg (/ 1 (exp x)))))\n                                                '(+.f64 ,(f64 3)\n                                                        (*.f64 ,(f64 25) (sin.f64 ,(f64 6))))))\n                              ,(f64 4))))\n\n; Tests for remove-zombie-nodes\n(module+ test\n  (require rackunit)\n  (define (zombie-test #:nodes nodes #:roots roots)\n    (define in-batch (batch nodes (make-hash)))\n    (define brfs (map (curry batchref in-batch) roots))\n    (define out-batch (batch-empty))\n    (define copy-f (batch-copy-only! out-batch in-batch))\n    (define brfs* (map copy-f brfs))\n    (check-equal? (map (batch-exprs out-batch) brfs*) (map (batch-exprs in-batch) brfs))\n    (batch-nodes out-batch))\n\n  (check-equal? (create-dvector 2 0 '(sqrt 1) '(pow 0 2))\n                (zombie-test #:nodes (create-dvector 0 1 '(sqrt 0) 2 '(pow 3 2)) #:roots (list 4)))\n  (check-equal? (create-dvector 0 '(sqrt 0) '(exp 1))\n                (zombie-test #:nodes (create-dvector 0 6 '(pow 0 1) '(* 2 0) '(sqrt 0) '(exp 4))\n                             #:roots (list 5)))\n  (check-equal? (create-dvector 0 1/2 '(+ 0 1))\n                (zombie-test #:nodes (create-dvector 0 1/2 '(+ 0 1) '(* 2 0)) #:roots (list 2)))\n\n  (check-equal? (create-dvector 1/2 '(exp 0) 0 (approx 1 2))\n                (zombie-test #:nodes (create-dvector 0 1/2 '(+ 0 1) '(* 2 0) '(exp 1) (approx 4 0))\n                             #:roots (list 5)))\n  (check-equal?\n   (create-dvector 1/2 'x '(* 1 1) 2 (approx 2 3) '(pow 0 4))\n   (zombie-test #:nodes (create-dvector 'x 2 1/2 '(sqrt 1) '(cbrt 1) '(* 0 0) (approx 5 1) '(pow 2 6))\n                #:roots (list 7)))\n  (check-equal?\n   (create-dvector 1/2 'x '(* 1 1) 2 (approx 2 3) '(pow 0 4) '(sqrt 3))\n   (zombie-test #:nodes (create-dvector 'x 2 1/2 '(sqrt 1) '(cbrt 1) '(* 0 0) (approx 5 1) '(pow 2 6))\n                #:roots (list 7 3))))\n\n; Tests for batch->jsexpr and jsexpr->batch-exprs\n(module+ test\n  (require rackunit)\n  (define (test-json-tostring expr expected)\n    (define-values (batch brfs) (progs->batch (list expr)))\n    (define jsexpr (batch->jsexpr batch brfs))\n    (define str (jsexpr->batch-exprs jsexpr))\n    (check-equal? str expected))\n\n  ; No sharing - just the expression\n  (test-json-tostring '(+ x y) \"(+ x y)\")\n  ; Shared subexpressions get their own bindings\n  (test-json-tostring '(* 1/2 (+ (exp x) (neg (/ 1 (exp x)))))\n                      \"%2 = (exp x)\\n(* 1/2 (+ %2 (neg (/ 1 %2))))\")\n  ; Shared constants/variables are inlined\n  (test-json-tostring '(sqrt (+ (* x x) (* y y))) \"(sqrt (+ (* x x) (* y y)))\"))\n"
  },
  {
    "path": "src/syntax/float.rkt",
    "content": "#lang racket\n\n(require math/base\n         math/bigfloat\n         math/flonum)\n(require \"../utils/common.rkt\"\n         \"../syntax/types.rkt\"\n         \"../utils/errors.rkt\")\n\n(provide repr-ulps\n         ulps->bits\n         midpoint\n         two-midpoints\n         random-generate\n         </total\n         <=/total\n         value->string\n         value->json\n         json->value\n         real->repr\n         repr->real)\n\n(define (repr-ulps repr)\n  (match (representation-type repr)\n    [`(array ,_ ,_)\n     (define elem-repr (array-representation-elem repr))\n     (define elem-ulps (repr-ulps elem-repr))\n     (lambda (x y) (for/sum ([x1 (in-vector x)] [y1 (in-vector y)]) (elem-ulps x1 y1)))]\n    ['bool (lambda (x y) (if (equal? x y) 1 2))]\n    ['real\n     (define ->ordinal (representation-repr->ordinal repr))\n     (define special? (representation-special-value? repr))\n     (define max-error (+ 1 (expt 2 (representation-total-bits repr))))\n     (define finite-ulps\n       (if (eq? repr <binary64>)\n           (lambda (x y) (+ 1 (abs (flonums-between x y))))\n           (lambda (x y) (+ 1 (abs (- (->ordinal y) (->ordinal x)))))))\n     (lambda (x y)\n       (if (or (special? x) (special? y))\n           max-error\n           (finite-ulps x y)))]))\n\n;; Returns the midpoint of the representation's ordinal values,\n;; not the real-valued midpoint\n(define (midpoint p1 p2 repr)\n  (match (representation-type repr)\n    [`(array ,_ ,_)\n     (define elem-repr (array-representation-elem repr))\n     (for/vector #:length (vector-length p1)\n                 ([x1 (in-vector p1)]\n                  [y1 (in-vector p2)])\n       (midpoint x1 y1 elem-repr))]\n    ['bool (and p1 p2)]\n    ['real\n     ((representation-ordinal->repr repr) (floor (/ (+ ((representation-repr->ordinal repr) p1)\n                                                       ((representation-repr->ordinal repr) p2))\n                                                    2)))]))\n\n(define (repr-round repr dir point)\n  ((representation-repr->bf repr) (parameterize ([bf-rounding-mode dir])\n                                    ((representation-bf->repr repr) point))))\n\n(define (two-midpoints repr lo hi)\n  ; Midpoint is taken in repr-space, but values are stored in bf\n  (define <-ordinal (compose (representation-repr->bf repr) (representation-ordinal->repr repr)))\n  (define ->ordinal (compose (representation-repr->ordinal repr) (representation-bf->repr repr)))\n\n  (define lower (<-ordinal (floor (/ (+ (->ordinal hi) (->ordinal lo)) 2))))\n  (define higher (repr-round repr 'up (bfnext lower))) ; repr-next\n\n  (and (bf>= lower lo)\n       (bf<= higher hi) ; False if lo and hi were already close together\n       (cons lower higher)))\n\n(define (ulps->bits x)\n  (real->double-flonum (log x 2)))\n\n(define (random-generate repr)\n  (match (representation-type repr)\n    [`(array ,_ ,_)\n     (define elem-repr (array-representation-elem repr))\n     (define len (array-representation-len repr))\n     (for/vector #:length len\n                 ([_ (in-range len)])\n       (random-generate elem-repr))]\n    ['bool (zero? (random-integer 0 2))]\n    ['real\n     (define bits (sub1 (representation-total-bits repr)))\n     ((representation-ordinal->repr repr) (random-integer (- (expt 2 bits)) (expt 2 bits)))]))\n\n(define (=/total x1 x2 repr)\n  (define ->ordinal (representation-repr->ordinal repr))\n  (define special? (representation-special-value? repr))\n  (or (= (->ordinal x1) (->ordinal x2)) (and (special? x1) (special? x2))))\n\n(define (</total x1 x2 repr)\n  (define special? (representation-special-value? repr))\n  (define ->ordinal (representation-repr->ordinal repr))\n  (cond\n    [(special? x1) #f]\n    [(special? x2) #t]\n    [else (< (->ordinal x1) (->ordinal x2))]))\n\n(define (<=/total x1 x2 repr)\n  (or (</total x1 x2 repr) (=/total x1 x2 repr)))\n\n(define (value->json x repr)\n  (match x\n    [(? vector?)\n     (define elem-repr (array-representation-elem repr))\n     (for/list ([v (in-vector x)])\n       (value->json v elem-repr))]\n    [(? real?)\n     (match x\n       [(? rational?) x]\n       [(or -inf.0 -inf.f) (hash 'type \"real\" 'value \"-inf\")]\n       [(or +inf.0 +inf.f) (hash 'type \"real\" 'value \"+inf\")]\n       [(or +nan.0 +nan.f) (hash 'type \"real\" 'value \"NaN\")])]\n    [_\n     (hash 'type\n           (~a (representation-name repr))\n           'ordinal\n           (~a ((representation-repr->ordinal repr) x)))]))\n\n(define (json->value x repr)\n  (match x\n    [(? list?)\n     (define elem-repr (array-representation-elem repr))\n     (for/vector ([v (in-list x)])\n       (json->value v elem-repr))]\n    [(? real?) (exact->inexact x)]\n    [(? hash?)\n     (match (hash-ref x 'type)\n       [\"real\"\n        (match (hash-ref x 'value)\n          [\"-inf\" -inf.0]\n          [\"+inf\" +inf.0]\n          [\"NaN\" +nan.0]\n          [_ +nan.0])]\n       [_ ((representation-ordinal->repr repr) (string->number (hash-ref x 'ordinal)))])]))\n\n(define (value->string n repr)\n  ;; Prints a number with relatively few digits\n  (define ->bf (representation-repr->bf repr))\n  (define <-bf (representation-bf->repr repr))\n  ;; Linear search because speed not an issue\n  (let loop ([precision 16])\n    (cond\n      [(> precision (*max-mpfr-prec*))\n       (warn 'value-to-string #:url \"faq.html#value-to-string\" \"Could not uniquely print ~a\" n)\n       n]\n      [else\n       (parameterize ([bf-precision precision])\n         (define bf (->bf n))\n         (if (=/total n (<-bf bf) repr)\n             (match (bigfloat->string bf)\n               [\"-inf.bf\" \"-inf.0\"]\n               [\"+inf.bf\" \"+inf.0\"]\n               [\"+nan.bf\" \"+nan.0\"]\n               [x x])\n             (loop (+ precision 4))))]))) ; 2^4 > 10\n\n(define (real->repr x repr)\n  (match (representation-type repr)\n    [`(array ,_ ,_)\n     (define elem-repr (array-representation-elem repr))\n     (for/vector ([v (in-vector x)])\n       (real->repr v elem-repr))]\n    ['real\n     (parameterize ([bf-precision (representation-total-bits repr)])\n       ((representation-bf->repr repr) (bf x)))]\n    ['bool x]))\n\n(define (repr->real x repr)\n  (match (representation-type repr)\n    [`(array ,_ ,_)\n     (define elem-repr (array-representation-elem repr))\n     (for/vector ([v (in-vector x)])\n       (repr->real v elem-repr))]\n    ['real (bigfloat->real ((representation-repr->bf repr) x))]\n    ['bool x]))\n"
  },
  {
    "path": "src/syntax/generators.rkt",
    "content": "#lang racket\n\n(require math/flonum\n         math/bigfloat\n         ffi/unsafe)\n\n(require \"rival.rkt\"\n         \"../config.rkt\"\n         \"types.rkt\"\n         \"batch.rkt\")\n\n(provide from-rival\n         from-ffi\n         from-libm\n         from-bigfloat\n         define-generator\n         (struct-out generator))\n\n(struct generator (gen))\n\n(define-syntax-rule (define-generator ((name args ...) spec ctx)\n                      body ...)\n  (define (name args ...)\n    (generator (lambda (spec ctx)\n                 body ...))))\n\n; ----------------------- RIVAL GENERATOR ---------------------------\n\n(define/reset caches\n              '()\n              (lambda ()\n                (for ([cache (caches)])\n                  (hash-clear! cache))))\n\n(define-generator ((from-rival #:cache? [cache? #t]) spec ctx)\n  (define-values (batch brfs) (progs->batch (list spec)))\n  (define compiler (make-real-compiler batch brfs (list ctx)))\n  (define fail ((representation-bf->repr (context-repr ctx)) +nan.bf))\n  (define (compute . pt)\n    (define-values (_ exs) (real-apply compiler (list->vector pt)))\n    (if exs\n        (first exs)\n        fail))\n  (cond\n    [cache?\n     (define cache (make-hash))\n     (caches (cons cache (caches)))\n     (lambda pt (hash-ref! cache pt (lambda () (apply compute pt))))]\n    [else compute]))\n\n; ----------------------- FFI GENERATOR -----------------------------\n\n;; Looks up a function `name` with type signature `itype -> ... -> otype`\n;; in the given FFI library and returns the function or `#f` if it\n;; cannot be found.\n;; ```\n;; (make-ffi <lib> (<name> <itype> ... <otype>))\n;; ```\n(define (make-ffi lib name itypes otype)\n  ; Repr matching\n  (define (repr->ffi repr)\n    (match (representation-name repr)\n      ['binary64 _double]\n      ['binary32 _float]\n      ['integer _int]\n      [else (raise-syntax-error 'repr->type \"unknown type\" repr)]))\n  (get-ffi-obj name lib (_cprocedure (map repr->ffi itypes) (repr->ffi otype)) (const #f)))\n\n(define-generator ((from-ffi lib name) spec ctx)\n  (let ([itypes (context-var-reprs ctx)]\n        [otype (context-repr ctx)])\n    (or (make-ffi lib name itypes otype)\n        (error 'ffi-generator \"Could not find FFI implementation of `~a ~a ~a`\" otype name itypes))))\n\n(define libm-lib (ffi-lib #f))\n(define (from-libm name)\n  (from-ffi libm-lib name))\n\n; ----------------------- BIGFLOAT GENERATOR ------------------------\n\n(define (repr->bf x type)\n  ((representation-repr->bf type) x))\n\n(define (bf->repr x type)\n  ((representation-bf->repr type) x))\n\n(define-generator ((from-bigfloat name) spec ctx)\n  (let* ([itypes (context-var-reprs ctx)]\n         [otype (context-repr ctx)]\n         [op (dynamic-require '(lib \"math/bigfloat\") name)]\n         [working-precision (representation-total-bits otype)])\n    (lambda pt\n      (define pt* (map repr->bf pt itypes))\n      (define bf-out\n        (parameterize ([bf-precision working-precision])\n          (apply op pt*)))\n      (bf->repr bf-out otype))))\n"
  },
  {
    "path": "src/syntax/load-platform.rkt",
    "content": "#lang racket\n(require racket/runtime-path)\n(require \"../config.rkt\"\n         \"../utils/errors.rkt\"\n         \"platform.rkt\")\n(provide activate-platform!)\n\n(define-runtime-module-path herbie10-platform \"../platforms/herbie10.rkt\")\n(define-runtime-module-path herbie20-platform \"../platforms/herbie20.rkt\")\n(define-runtime-module-path c-platform \"../platforms/c.rkt\")\n(define-runtime-module-path c-windows-platform \"../platforms/c-windows.rkt\")\n(define-runtime-module-path racket-platform \"../platforms/racket.rkt\")\n(define-runtime-module-path math-platform \"../platforms/math.rkt\")\n(define-runtime-module-path rival-platform \"../platforms/rival.rkt\")\n\n(define default-platforms\n  (hash \"herbie10\"\n        herbie10-platform\n        \"herbie20\"\n        herbie20-platform\n        \"c\"\n        c-platform\n        \"c-windows\"\n        c-windows-platform\n        \"racket\"\n        racket-platform\n        \"math\"\n        math-platform\n        \"rival\"\n        rival-platform))\n\n(define platforms (make-hash))\n\n(define (activate-platform! name)\n  (define path (hash-ref default-platforms name (string->path name)))\n  (define platform (hash-ref! platforms name (lambda () (dynamic-require path 'platform))))\n\n  (unless platform\n    (raise-herbie-error \"unknown platform `~a`, found (~a)\"\n                        name\n                        (string-join (map ~a (hash-keys platforms)) \", \")))\n\n  (*platform-name* name)\n  (*active-platform* platform))\n"
  },
  {
    "path": "src/syntax/matcher.rkt",
    "content": ";; Minimal pattern matcher/substituter for S-expressions\n\n#lang racket\n\n(provide pattern-match\n         pattern-substitute)\n\n;; Unions two bindings. Returns #f if they disagree.\n(define (merge-bindings binding1 binding2)\n  (and binding1\n       binding2\n       (let/ec quit\n         (for/fold ([binding binding1]) ([(k v) (in-dict binding2)])\n           (dict-update binding\n                        k\n                        (λ (x)\n                          (if (equal? x v)\n                              v\n                              (quit #f)))\n                        v)))))\n\n;; Pattern matcher that returns a substitution or #f.\n;; A substitution is an association list of symbols and expressions.\n(define (pattern-match pattern expr)\n  (match* (pattern expr)\n    [((? number?) _) (and (equal? pattern expr) '())]\n    [((? symbol?) _) (list (cons pattern expr))]\n    [((list phead prest ...) (list head rest ...))\n     (and (equal? phead head)\n          (= (length prest) (length rest))\n          (for/fold ([bindings '()])\n                    ([pat (in-list prest)]\n                     [term (in-list rest)])\n            (merge-bindings bindings (pattern-match pat term))))]\n    [(_ _) #f]))\n\n(define (pattern-substitute pattern bindings)\n  ; pattern binding -> expr\n  (match pattern\n    [(? number?) pattern]\n    [(? symbol?) (dict-ref bindings pattern)]\n    [(list phead pargs ...) (cons phead (map (curryr pattern-substitute bindings) pargs))]))\n"
  },
  {
    "path": "src/syntax/platform-language.rkt",
    "content": "#lang racket\n\n(require \"platform.rkt\"\n         \"syntax.rkt\"\n         \"types.rkt\"\n         \"generators.rkt\"\n         \"../utils/errors.rkt\"\n         \"../config.rkt\"\n         rival/eval/types)\n\n(provide define-representation\n         define-operation\n         define-operations\n         fpcore-context\n         if-impl\n         if-cost\n         (rename-out [platform-module-begin #%module-begin])\n         (except-out (all-from-out racket) #%module-begin)\n         (all-from-out \"platform.rkt\")\n         (all-from-out \"generators.rkt\")\n         (all-from-out \"types.rkt\"))\n\n;; Core error checking code\n(define (check-spec! name ctx spec)\n  (match-define (context vars repr var-reprs) ctx)\n  (define env (map cons vars (map representation-type var-reprs)))\n  (define otype (representation-type repr))\n\n  (define (infer spec)\n    (match spec\n      [(? number?) 'real]\n      [(? symbol? x) (dict-ref env x (lambda () (rival-type spec env)))]\n      [(list 'array elems ...)\n       (if (null? elems)\n           #f\n           (let ([elem-ty (infer (first elems))])\n             (and elem-ty\n                  (for/and ([elem (in-list (rest elems))])\n                    (equal? elem-ty (infer elem)))\n                  `(array ,elem-ty ,(length elems)))))]\n      [(list 'ref arr idx)\n       (match (infer arr)\n         [`(array ,elem-ty ,_) elem-ty]\n         [_ #f])]\n      [_ (rival-type spec env)]))\n  (define spec-type (infer spec))\n\n  (match spec-type\n    [(== otype) (void)]\n    [#f (error name \"expression ~a is ill-typed, expected `~a`\" spec otype)]\n    [actual-ty (error name \"expression ~a has type `~a`, expected `~a`\" spec actual-ty otype)]))\n\n(define (check-fpcore! name fpcore)\n  (match (fpcore-parameterize fpcore)\n    [`(! ,props ... (,op ,args ...))\n     (unless (even? (length props))\n       (error 'define-operation \"~a: unmatched property in ~a\" name fpcore))\n     (unless (symbol? op)\n       (error 'define-operation \"~a: expected symbol `~a`\" name op))\n     (for ([arg (in-list args)]\n           #:unless (or (symbol? arg) (number? arg)))\n       (error 'define-operation \"~a: expected terminal `~a`\" name arg))]\n    [`(,op ,args ...)\n     (unless (symbol? op)\n       (error 'define-operation \"~a: expected symbol `~a`\" name op))\n     (for ([arg (in-list args)]\n           #:unless (or (symbol? arg) (number? arg)))\n       (error 'define-operation \"~a: expected terminal `~a`\" name arg))]\n    [(? symbol?) (void)]\n    [_ (error 'define-operation \"Invalid fpcore for ~a: ~a\" name fpcore)]))\n\n(define (check-fl-proc! name ctx fl-proc spec)\n  (define fl-proc*\n    (match fl-proc\n      [(? generator?) ((generator-gen fl-proc) spec ctx)]\n      [(? procedure?) fl-proc]))\n  (unless (procedure-arity-includes? fl-proc* (length (context-vars ctx)) #t)\n    (error 'define-operation\n           \"Procedure `~a` accepts ~a arguments, but ~a is provided\"\n           name\n           (procedure-arity fl-proc*)\n           (length (context-vars ctx))))\n  fl-proc*)\n\n(define (check-cost! name cost)\n  (match cost\n    [(? number?) (values cost +)]\n    [(? procedure?) (values 0 cost)]\n    [_ (error 'define-operation \"Invalid cost for ~a: ~a\" name cost)]))\n\n;; Functions for the core operations\n\n(define fpcore-context (make-parameter '_))\n\n(define (fpcore-parameterize spec)\n  (let loop ([ctx (fpcore-context)])\n    (match ctx\n      ['_ spec]\n      [(list arg ...) (map loop arg)]\n      [_ ctx])))\n\n(define/contract (create-operator-impl! name\n                                        ctx\n                                        #:spec spec\n                                        #:impl fl-proc\n                                        #:fpcore fpcore\n                                        #:cost cost)\n  (-> symbol?\n      context?\n      #:spec any/c\n      #:impl (or/c procedure? generator?)\n      #:fpcore any/c\n      #:cost (or/c real? procedure?)\n      operator-impl?)\n  (check-spec! name ctx spec)\n  (check-fpcore! name fpcore)\n  (define fl-proc* (check-fl-proc! name ctx fl-proc spec))\n  (define-values (cost* aggregate*) (check-cost! name cost))\n  (operator-impl name ctx spec (fpcore-parameterize fpcore) fl-proc* cost* aggregate*))\n\n(define (platform-register-representation! platform #:repr repr #:cost cost)\n  (define reprs (platform-representations platform))\n  (define repr-costs (platform-representation-costs platform))\n  ; Duplicate check\n  (when (hash-has-key? reprs (representation-name repr))\n    (raise-herbie-error \"Duplicate representation ~a in platform ~a\"\n                        (representation-name repr)\n                        (*platform-name*)))\n  ; Update tables\n  (hash-set! reprs (representation-name repr) repr)\n  (hash-set! repr-costs (representation-name repr) cost))\n\n(define (platform-register-implementation! platform impl)\n  ; Reprs check\n  (define reprs (platform-representations platform))\n  (define otype (context-repr (operator-impl-ctx impl)))\n  (define itype (context-var-reprs (operator-impl-ctx impl)))\n  (define impl-reprs (map representation-name (remove-duplicates (cons otype itype))))\n  (for ([repr-name (in-list impl-reprs)]\n        #:unless (hash-has-key? reprs repr-name))\n    (raise-herbie-error \"Platform ~a missing representation ~a for ~a implementation\"\n                        (*platform-name*)\n                        repr-name\n                        (operator-impl-name impl)))\n  ; Duplicate check\n  (define impls (platform-implementations platform))\n  (when (hash-has-key? impls (operator-impl-name impl))\n    (raise-herbie-error \"Impl ~a is already registered in platform ~a\"\n                        (operator-impl-name impl)\n                        (*platform-name*)))\n  ; Update table\n  (hash-set! impls (operator-impl-name impl) impl))\n\n;; Macros for the core operations\n\n(begin-for-syntax\n  (define (parse-keyword-fields stx fields-stx allowed-keywords op-name)\n    (define (oops! why [sub-stx #f])\n      (raise-syntax-error op-name why stx sub-stx))\n\n    (define result-hash (make-hasheq))\n\n    (let loop ([fields fields-stx])\n      (syntax-case fields ()\n        [() result-hash]\n        [(kw val rest ...)\n         (keyword? (syntax-e #'kw))\n         (let ([kw-sym (string->symbol (keyword->string (syntax-e #'kw)))])\n           (unless (member kw-sym allowed-keywords)\n             (oops! (format \"unknown keyword ~a\" (syntax-e #'kw)) #'kw))\n           (when (hash-has-key? result-hash kw-sym)\n             (oops! (format \"multiple ~a clauses\" (syntax-e #'kw)) #'kw))\n           (hash-set! result-hash kw-sym #'val)\n           (loop #'(rest ...)))]\n        [(kw)\n         (keyword? (syntax-e #'kw))\n         (oops! (format \"expected value after keyword ~a\" (syntax-e #'kw)) #'kw)]\n        [_ (oops! \"bad syntax\" fields)]))))\n\n(define-syntax (make-operator-impl stx)\n  (define (oops! why [sub-stx #f])\n    (raise-syntax-error 'make-operator-impl why stx sub-stx))\n  (syntax-case stx (:)\n    [(_ (id [var : repr] ...) rtype . fields)\n     (let ([op-name #'id]\n           [vars (syntax->list #'(var ...))])\n       (unless (identifier? op-name)\n         (oops! \"expected identifier\" op-name))\n       (for ([var (in-list vars)]\n             #:unless (identifier? var))\n         (oops! \"expected identifier\" var))\n\n       (define keywords (parse-keyword-fields stx #'fields '(spec fpcore impl cost) op-name))\n\n       (unless (hash-has-key? keywords 'spec)\n         (raise-syntax-error op-name \"missing `#:spec` keyword\" stx))\n       (unless (hash-has-key? keywords 'impl)\n         (raise-syntax-error op-name \"missing `#:impl` keyword\" stx))\n       (unless (hash-has-key? keywords 'cost)\n         (raise-syntax-error op-name \"missing `#:cost` keyword\" stx))\n\n       ;; Build argument list for create-operator-impl!\n       ;; Quote spec and fpcore, leave impl and cost unquoted\n       ;; Default fpcore to spec if not provided\n       (with-syntax ([spec-val (hash-ref keywords 'spec)]\n                     [fpcore-val (hash-ref keywords 'fpcore (hash-ref keywords 'spec))]\n                     [impl-val (hash-ref keywords 'impl)]\n                     [cost-val (hash-ref keywords 'cost)])\n         #'(create-operator-impl! 'id\n                                  (context '(var ...) rtype (list repr ...))\n                                  #:spec 'spec-val\n                                  #:impl impl-val\n                                  #:fpcore 'fpcore-val\n                                  #:cost cost-val)))]\n    [_ (oops! \"bad syntax\")]))\n\n(define platform-being-defined (make-parameter #f))\n\n(define-syntax-rule (define-representation repr #:cost cost)\n  (platform-register-representation! (platform-being-defined) #:repr repr #:cost cost))\n\n(define-syntax-rule (define-operation (name [arg irepr] ...) orepr flags ...)\n  (let ([impl (make-operator-impl (name [arg : irepr] ...) orepr flags ...)])\n    (platform-register-implementation! (platform-being-defined) impl)))\n\n;; Language definition and syntactic sugar / helpers\n\n(define-syntax (platform-module-begin stx)\n  (with-syntax ([local-platform (datum->syntax stx 'platform)])\n    (syntax-case stx ()\n      [(_ content ...)\n       #'(#%module-begin (define local-platform (make-empty-platform))\n                         (define old-platform-being-defined (platform-being-defined))\n                         (platform-being-defined local-platform)\n                         content ...\n                         (platform-being-defined old-platform-being-defined)\n                         (provide local-platform)\n                         (module+ main\n                           (display-platform local-platform))\n                         (module test racket/base\n                           ))])))\n\n(define-syntax (define-operations stx)\n  (syntax-case stx ()\n    [(_ ([arg irepr] ...) orepr #:fpcore fc [name flags ...] ...)\n     #'(parameterize ([fpcore-context 'fc])\n         (define-operation (name [arg irepr] ...) orepr flags ...) ...)]\n    [(_ ([arg irepr] ...) orepr [name flags ...] ...)\n     #'(begin\n         (define-operation (name [arg irepr] ...) orepr flags ...) ...)]))\n\n(define (if-impl c t f)\n  (if c t f))\n\n(define ((if-cost base) c t f)\n  (+ base c (max t f)))\n"
  },
  {
    "path": "src/syntax/platform.rkt",
    "content": "#lang racket\n\n(require racket/runtime-path)\n(require \"../utils/common.rkt\"\n         \"../utils/errors.rkt\"\n         \"../config.rkt\"\n         \"matcher.rkt\"\n         \"types.rkt\"\n         \"syntax.rkt\"\n         \"../syntax/float.rkt\"\n         \"generators.rkt\"\n         \"batch.rkt\")\n\n;;; Platforms describe a set of representations, operator, and constants\n;;; Herbie should use during its improvement loop. Platforms are just\n;;; a \"type signature\" - they provide no implementations of floating-point\n;;; operations (see plugins). During runtime, platforms will verify if\n;;; every listed feature is actually loaded by Herbie and will panic if\n;;; implemenations are missing. Unlike plugins, only one platform may be\n;;; active at any given time and platforms may be activated or deactivated.\n;;;\n;;; A small API is provided for platforms for querying the supported\n;;; operators, operator implementations, and representation conversions.\n(struct platform (representations implementations representation-costs)\n  #:name $platform\n  #:constructor-name create-platform\n  #:methods gen:custom-write\n  [(define (write-proc p port mode)\n     (fprintf port \"#<platform>\"))])\n\n(provide *active-platform*\n         get-representation\n         impl-exists?\n         impl-info\n         prog->spec\n         batch-to-spec!\n         get-fpcore-impl\n         (struct-out $platform)\n         ;; Platform API\n         ;; Operator sets\n         (contract-out [platform-reprs (-> platform? (listof representation?))]\n                       [platform-impls (-> platform? (listof symbol?))]\n                       [platform-repr-cost (-> platform? any/c any/c)]\n                       [platform-node-cost-proc (-> platform? procedure?)]\n                       [platform-cost-proc (-> platform? procedure?)])\n         ; Platform creation\n         make-empty-platform\n         display-platform\n         make-representation\n         (all-from-out \"generators.rkt\"))\n\n;; Active platform\n(define *active-platform* (make-parameter #f))\n\n(define (make-empty-platform)\n  (define reprs (make-hash))\n  (define repr-costs (make-hash))\n  (define impls (make-hash))\n  (create-platform reprs impls repr-costs))\n\n;; Returns the representation associated with `name`\n;; attempts to generate the repr if not initially found\n(define (get-representation name)\n  (define platform (*active-platform*))\n  (define reprs (platform-representations platform))\n  (or (hash-ref reprs name #f)\n      (raise-herbie-error \"Could not find support for ~a representation: ~a in a platform ~a\"\n                          name\n                          (string-join (map ~s (hash-keys reprs)) \", \")\n                          (*platform-name*))))\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; LImpl -> LSpec\n\n;; Translates an LImpl to a LSpec.\n(define (prog->spec expr)\n  (match expr\n    [(? literal?) (literal-value expr)]\n    [(? symbol?) expr]\n    [(approx spec _) spec]\n    [`(if ,cond ,ift ,iff)\n     `(if ,(prog->spec cond)\n          ,(prog->spec ift)\n          ,(prog->spec iff))]\n    [`(,impl ,args ...)\n     (define vars (impl-info impl 'vars))\n     (define spec (impl-info impl 'spec))\n     (define env (map cons vars (map prog->spec args)))\n     (pattern-substitute spec env)]))\n\n(define (batch-to-spec! batch brfs)\n  (define lower\n    (batch-recurse batch\n                   (lambda (brf recurse)\n                     (define node (deref brf))\n                     (match node\n                       [(? literal?) (batch-push! batch (literal-value node))]\n                       [(? number?) brf]\n                       [(? symbol?) brf]\n                       [(hole _ spec) (recurse spec)]\n                       [(approx spec _) (recurse spec)]\n                       [(list (? impl-exists? impl) args ...)\n                        (define vars (impl-info impl 'vars))\n                        (define spec (impl-info impl 'spec))\n                        (define env (map cons vars (map recurse args)))\n                        (batch-add! batch (pattern-substitute spec env))]\n                       [(list op args ...)\n                        (batch-push! batch (cons op (map (compose batchref-idx recurse) args)))]))))\n  (map lower brfs))\n\n;; Expression predicates ;;\n\n(define (impl-exists? op)\n  (define platform (*active-platform*))\n  (define impls (platform-implementations platform))\n  (hash-has-key? impls op))\n\n;; Looks up a property `field` of an real operator `op`.\n;; Panics if the operator is not found.\n(define/contract (impl-info impl-name field)\n  (-> symbol? (or/c 'vars 'itype 'otype 'spec 'fpcore 'fl 'cost 'aggregate) any/c)\n  (define impls (platform-implementations (*active-platform*)))\n  (define impl\n    (hash-ref impls\n              impl-name\n              (lambda ()\n                (error 'impl-info \"unknown impl '~a in platform ~a\" impl-name (*platform-name*)))))\n  (case field\n    [(vars) (context-vars (operator-impl-ctx impl))]\n    [(itype) (context-var-reprs (operator-impl-ctx impl))]\n    [(otype) (context-repr (operator-impl-ctx impl))]\n    [(spec) (operator-impl-spec impl)]\n    [(fpcore) (operator-impl-fpcore impl)]\n    [(fl) (operator-impl-fl impl)]\n    [(cost) (operator-impl-cost impl)]\n    [(aggregate) (operator-impl-aggregate impl)]))\n\n(define (platform-impls platform)\n  (hash-keys (platform-implementations platform)))\n\n(define (platform-reprs platform)\n  (hash-values (platform-representations platform)))\n\n; Representation (terminal) cost in a platform.\n(define (platform-repr-cost platform repr)\n  (define repr-costs (platform-representation-costs platform))\n  (hash-ref repr-costs (representation-name repr)))\n\n; Cost model of a single node by a platform.\n; Returns a procedure that must be called with the costs of the children.\n(define ((platform-node-cost-proc platform) expr repr)\n  (match expr\n    [(? literal?) (lambda () (platform-repr-cost platform repr))]\n    [(? symbol?) (lambda () (platform-repr-cost platform repr))]\n    [(list impl args ...)\n     (define impl-cost (impl-info impl 'cost))\n     (define impl-agg (impl-info impl 'aggregate))\n     (lambda itype-costs\n       (unless (= (length itype-costs) (length args))\n         (error 'platform-node-cost-proc \"arity mismatch, expected ~a arguments\" (length args)))\n       (+ impl-cost (apply impl-agg itype-costs)))]))\n\n; Cost model parameterized by a platform.\n(define (platform-cost-proc platform)\n  (define node-cost-proc (platform-node-cost-proc platform))\n  (λ (expr repr)\n    (let loop ([expr expr]\n               [repr repr])\n      (match expr\n        [(? literal?) ((node-cost-proc expr repr))]\n        [(? symbol?) ((node-cost-proc expr repr))]\n        [(approx _ impl) (loop impl repr)]\n        [(list impl args ...)\n         (define cost-proc (node-cost-proc expr repr))\n         (define itypes (impl-info impl 'itype))\n         (apply cost-proc (map loop args itypes))]))))\n\n;; Extracts the `fpcore` field of an operator implementation\n;; as a property dictionary and expression.\n(define (impl->fpcore impl)\n  (match (impl-info impl 'fpcore)\n    [(list '! props ... body) (values (props->dict props) body)]\n    [body (values '() body)]))\n\n(define/reset op-hash #f)\n\n;; For a given FPCore operator, rounding context, and input representations,\n;; finds the best operator implementation. Panics if none can be found.\n(define/contract (get-fpcore-impl op prop-dict ireprs)\n  (-> symbol? prop-dict/c (listof representation?) (or/c symbol? #f))\n  (unless (op-hash)\n    (define h (make-hash))\n    (for ([impl (in-list (platform-impls (*active-platform*)))])\n      (define-values (_ expr) (impl->fpcore impl))\n      (define expr*\n        (if (symbol? expr)\n            (list expr)\n            expr))\n      (when (list? expr*)\n        (hash-update! h (car expr*) (curry cons impl) '())))\n    (op-hash h))\n\n  ; gather all implementations that have the same spec, input representations,\n  ; and its FPCore translation has properties that are found in `prop-dict`\n  (define impls\n    (reap [sow]\n          (for ([impl (in-list (hash-ref (op-hash) op '()))]\n                #:when (equal? ireprs (impl-info impl 'itype)))\n            (define-values (prop-dict* expr) (impl->fpcore impl))\n            (define expr*\n              (if (symbol? expr)\n                  (list expr)\n                  expr)) ; Handle named constants\n            (define pattern (cons op (map (lambda (_) (gensym)) ireprs)))\n            (when (and (subset? prop-dict* prop-dict) (pattern-match pattern expr*))\n              (sow impl)))))\n  ; check that we have any matching impls\n  (cond\n    [(null? impls) #f]\n    [else\n     ; we rank implementations and select the highest scoring one\n     (define scores\n       (for/list ([impl (in-list impls)])\n         (define-values (prop-dict* _) (impl->fpcore impl))\n         (define num-matching (count (lambda (prop) (member prop prop-dict*)) prop-dict))\n         (cons num-matching (- (length prop-dict) num-matching))))\n     ; select the best implementation\n     ; sort first by the number of matched properties,\n     ; then tie break on the number of extraneous properties\n     (match-define (list (cons _ best) _ ...)\n       (sort (map cons scores impls)\n             (lambda (x y)\n               (cond\n                 [(> (car x) (car y)) #t]\n                 [(< (car x) (car y)) #f]\n                 [else (> (cdr x) (cdr y))]))\n             #:key car))\n     best]))\n\n(define (display-platform platform)\n  (define impls (platform-implementations platform))\n  (define reprs (platform-representations platform))\n  (define repr-costs (platform-representation-costs platform))\n\n  (displayln \"Representations:\")\n  (define reprs-data\n    (for/list ([repr (in-hash-values reprs)]\n               [n (in-naturals)])\n      (match-define (representation name type _ _ _ _ total-bits _) repr)\n      (define cost (hash-ref repr-costs name))\n      (list n name type total-bits cost)))\n  (write-table reprs-data (list \"idx\" \"name\" \"type\" \"#bits\" \"cost\"))\n\n  (displayln \"\\nImplementations\")\n  (define impls-data\n    (for/list ([impl (in-hash-values impls)]\n               [n (in-naturals)])\n      (define name (operator-impl-name impl))\n      (define itype (map representation-name (context-var-reprs (operator-impl-ctx impl))))\n      (define otype (representation-name (context-repr (operator-impl-ctx impl))))\n      (define spec (operator-impl-spec impl))\n      (define cost (operator-impl-cost impl))\n      (list n name itype otype spec cost)))\n  (write-table impls-data (list \"idx\" \"name\" \"itype\" \"otype\" \"spec\" \"cost\")))\n\n(define (write-table data headers #:buffer-space [buffer-space 2])\n  (define row-length (length (car data)))\n  (define cell-widths (make-vector row-length 0))\n\n  ; Measure cell-lengths\n  (for ([header (in-list headers)]\n        [i (in-naturals)])\n    (vector-set! cell-widths\n                 i\n                 (max (+ (string-length header) buffer-space) (vector-ref cell-widths i))))\n  (for ([row (in-list data)])\n    (for ([elem row]\n          [i (in-naturals)])\n      (vector-set! cell-widths\n                   i\n                   (max (+ (string-length (~a elem)) buffer-space) (vector-ref cell-widths i)))))\n\n  ; Header\n  (printf \"~a\" (~a (list-ref headers 0) #:width (vector-ref cell-widths 0)))\n  (for ([i (in-range 1 row-length)])\n    (printf \"|~a\" (~a (list-ref headers i) #:width (vector-ref cell-widths i))))\n  (newline)\n  (printf \"~a\" (~a \"\" #:width (vector-ref cell-widths 0) #:right-pad-string \"-\"))\n  (for ([i (in-range 1 row-length)])\n    (printf \"+~a\" (~a \"\" #:width (vector-ref cell-widths i) #:right-pad-string \"-\")))\n  (newline)\n\n  ; Content\n  (for ([row data])\n    (printf \"~a\" (~a (list-ref row 0) #:width (vector-ref cell-widths 0)))\n    (for ([i (in-range 1 row-length)])\n      (printf \"|~a\" (~a (list-ref row i) #:width (vector-ref cell-widths i))))\n    (newline)))\n"
  },
  {
    "path": "src/syntax/read.rkt",
    "content": "#lang racket\n\n(require \"../utils/common.rkt\"\n         \"../utils/errors.rkt\"\n         \"platform.rkt\"\n         \"sugar.rkt\"\n         \"syntax-check.rkt\"\n         \"syntax.rkt\"\n         \"type-check.rkt\"\n         \"types.rkt\")\n\n(provide (struct-out test)\n         test-context\n         test-output-repr\n         test-var-reprs\n         load-tests\n         parse-test)\n\n(define (free-variables prog)\n  (match prog\n    [(? literal?) '()]\n    [(? number?) '()]\n    [(? symbol?) (list prog)]\n    [(approx _ impl) (free-variables impl)]\n    [(list _ args ...) (remove-duplicates (append-map free-variables args))]))\n\n(struct test (name identifier vars input output expected spec pre output-repr-name var-repr-names)\n  #:prefab)\n\n(define (test-output-repr test)\n  (get-representation (test-output-repr-name test)))\n\n(define (test-var-reprs test)\n  (map get-representation (map cdr (test-var-repr-names test))))\n\n(define (test-context test)\n  (define output-repr (get-representation (test-output-repr-name test)))\n  (define vars (test-vars test))\n  (define var-reprs\n    (for/list ([var vars])\n      (get-representation (dict-ref (test-var-repr-names test) var))))\n  (context (test-vars test) output-repr var-reprs))\n\n;; Unfortunately copied from `src/syntax/sugar.rkt`\n(define (expand stx)\n  (match stx\n    ; expand let statements\n    [#`(let* ([#,vars #,vals] ...) #,body)\n     (datum->syntax #f\n                    (list 'let*\n                          (for/list ([var (in-list vars)]\n                                     [val (in-list vals)])\n                            (list var (expand val)))\n                          (expand body))\n                    stx)]\n    [#`(let ([#,vars #,vals] ...) #,body)\n     (datum->syntax #f\n                    (list 'let\n                          (for/list ([var (in-list vars)]\n                                     [val (in-list vals)])\n                            (list var (expand val)))\n                          (expand body))\n                    stx)]\n    ; special nullary operators\n    [#`(,(or 'and 'or)) (datum->syntax #f 'TRUE stx)]\n    [#`(+)\n     (warn 'nullary-operator \"+ is deprecated as a nullary operator\")\n     (datum->syntax #f 0 stx)]\n    [#`(*)\n     (warn 'nullary-operator \"* is deprecated as a nullary operator\")\n     (datum->syntax #f 1 stx)]\n    ; special unary operators\n    [#`(,(or 'and 'or) #,a) (expand a)]\n    ; deprecated unary operators\n    [#`(,(and (or '+ '*) op) #,a)\n     (warn 'unary-operator \"~a is deprecated as a unary operator\" op)\n     (expand a)]\n    [#`(/ #,a)\n     (warn 'unary-operator \"/ is deprecated as a unary operator\")\n     (datum->syntax #f (list '/ 1 (expand a)) stx)]\n    ; binary operators\n    [#`(,(and (or '+ '- '* '/ 'or) op) #,arg1 #,arg2)\n     (datum->syntax #f (list op (expand arg1) (expand arg2)) stx)]\n    ; variary operators\n    [#`(,(and (or '+ '- '* '/ 'or) op) #,arg1 #,arg2 #,rest ...)\n     (unless (null? rest)\n       (warn 'variary-operator \"~a is deprecated as a variary operator\" op))\n     (define prev (datum->syntax #f (list op (expand arg1) (expand arg2)) stx))\n     (let loop ([prev prev]\n                [rest rest])\n       (match rest\n         [(list) prev]\n         [(list next rest ...)\n          (define prev* (datum->syntax #f (list op prev (expand next)) next))\n          (loop prev* rest)]))]\n    [#`(,(and (or '< '<= '> '>= '=) op) #,args ...)\n     (define args* (map expand args))\n     (define out\n       (for/fold ([out #f])\n                 ([term args*]\n                  [next (cdr args*)])\n         (datum->syntax #f\n                        (if out\n                            (list 'and out (list op term next))\n                            (list op term next))\n                        term)))\n     (or out (datum->syntax #f 'TRUE stx))]\n    [#`(!= #,args ...)\n     (define args* (map expand args))\n     (define out\n       (for/fold ([out #f])\n                 ([term args*]\n                  [i (in-naturals)]\n                  #:when #t\n                  [term2 args*]\n                  [j (in-naturals)]\n                  #:when (< i j))\n         (datum->syntax #f\n                        (if out\n                            (list 'and out (list '!= term term2))\n                            (list '!= term term2))\n                        stx)))\n     (or out (datum->syntax #f 'TRUE stx))]\n    ; other operators\n    [#`(#,op #,args ...) (datum->syntax #f (cons op (map expand args)) stx)]\n    ; numbers, variables\n    [_ stx]))\n\n(define (expand-core stx)\n  (match stx\n    [#`(FPCore #,name (#,vars ...) #,props ... #,body)\n     (datum->syntax #f (append (list 'FPCore name vars) props (list (expand body))) stx)]\n    [#`(FPCore (#,vars ...) #,props ... #,body)\n     (datum->syntax #f (append (list 'FPCore vars) props (list (expand body))) stx)]))\n\n(define (parse-platform-name ann)\n  (match ann\n    [(list '! props ... body)\n     (define dict (props->dict props))\n     (dict-ref dict ':herbie-platform #f)]\n    [_ #f]))\n\n(define (parse-test stx)\n  (assert-program! stx)\n  (define stx* (expand-core stx))\n  (define-values (output-repr ctx) (assert-program-typed! stx*))\n  (define-values (func-name args props body)\n    (match (syntax->datum stx*)\n      [(list 'FPCore name (list args ...) props ... body) (values name args props body)]\n      [(list 'FPCore (list args ...) props ... body) (values #f args props body)]))\n\n  ;; NOTE: We intentionally do not use (define prop-dict (props->dict props)) here\n  ;; despite its apparent efficiency. props->dict could be considered, if :alt was a unique key\n  ;; in our property. When there are multiple entries with the same key, props->dict would collapse\n  ;; them, and prevent mutliple Developer Targets from being represented correctly.\n  ;; This less efficient implementation preserves all entries, and maintains dict-ref functionality.\n  (define prop-dict\n    (let loop ([props props])\n      (match props\n        ['() '()]\n        [(list prop val rest ...) (cons (cons prop val) (loop rest))])))\n\n  (define default-prec (dict-ref prop-dict ':precision (*default-precision*)))\n  (define var-names (context-vars ctx))\n  (define var-reprs (context-var-reprs ctx))\n\n  ;; Named fpcores need to be added to function table\n  (when func-name\n    (register-function! func-name args default-prec body))\n\n  ;; Try props first, then identifier, else the expression itself\n  (define name (or (dict-ref prop-dict ':name #f) func-name body))\n\n  ;; inline and desugar\n  (define body* (fpcore->prog body ctx))\n  (define pre* (fpcore->prog (dict-ref prop-dict ':pre 'TRUE) ctx))\n\n  (define targets\n    (for/list ([(key val) (in-dict prop-dict)]\n               #:when (eq? key ':alt))\n      (match (parse-platform-name val) ; plat-name is symbol or #f\n        ; If plat-name extracted, check if name matches\n        [(? symbol? plat-name) (cons val (equal? (~a plat-name) (*platform-name*)))]\n        ; try to lower\n        [#f\n         (with-handlers ([exn:fail:user:herbie:missing? (lambda (e) (cons val #f))])\n           ; Testing if error thrown\n           (fpcore->prog val ctx)\n           (cons val #t))])))\n\n  (define spec (fpcore->prog (dict-ref prop-dict ':spec body) ctx))\n  (check-unused-variables var-names body* pre*)\n  (check-weird-variables var-names)\n\n  (test (~a name)\n        func-name\n        var-names\n        body*\n        targets\n        (dict-ref prop-dict ':herbie-expected #t)\n        spec\n        pre*\n        (representation-name output-repr)\n        (for/list ([var (in-list var-names)]\n                   [repr (in-list var-reprs)])\n          (cons var (representation-name repr)))))\n\n(define (check-unused-variables vars precondition expr)\n  ;; Fun story: you might want variables in the precondition that\n  ;; don't appear in the `expr`, because that can allow you to do\n  ;; non-uniform sampling. For example, if you have the precondition\n  ;; `(< x y)`, where `y` is otherwise unused, then `x` is sampled\n  ;; non-uniformly (biased toward small values).\n  (define used (set-union (free-variables expr) (free-variables precondition)))\n  (unless (set=? vars used)\n    (define unused (set-subtract vars used))\n    (warn 'unused-variable\n          #:url \"faq.html#unused-variable\"\n          \"unused ~a ~a\"\n          (if (equal? (set-count unused) 1) \"variable\" \"variables\")\n          (string-join (map ~a unused) \", \"))))\n\n(define (check-weird-variables vars)\n  (for ([var (in-list vars)])\n    (define const-name (string->symbol (string-upcase (symbol->string var))))\n    (when (operator-exists? const-name)\n      (warn 'strange-variable\n            #:url \"faq.html#strange-variable\"\n            \"unusual variable ~a; did you mean ~a?\"\n            var\n            const-name))))\n\n(define (our-read-syntax port name)\n  (parameterize ([read-decimal-as-inexact false])\n    (read-syntax port name)))\n\n(define (load-port port)\n  (port-count-lines! port)\n  (for/list ([test (in-port (curry our-read-syntax \"stdin\") port)])\n    (parse-test test)))\n\n(define (load-file file)\n  (call-with-input-file file\n                        (λ (port)\n                          (port-count-lines! port)\n                          (for/list ([test (in-port (curry our-read-syntax file) port)])\n                            (parse-test test)))))\n\n(define (load-directory dir)\n  (apply append\n         (for/list ([fname (in-directory dir)]\n                    #:when (file-exists? fname)\n                    #:when (equal? (filename-extension fname) #\"fpcore\"))\n           (load-file fname))))\n\n(define (load-tests path)\n  (define path*\n    (if (string? path)\n        (string->path path)\n        path))\n  (define out\n    (cond\n      [(port? path) (load-port path)]\n      [(equal? path \"-\") (load-port (current-input-port))]\n      [(directory-exists? path*) (load-directory path*)]\n      [else (load-file path*)]))\n  (define duplicates (find-duplicates (map test-name out)))\n  (unless (null? duplicates)\n    (warn 'duplicate-names\n          \"Duplicate ~a ~a used for multiple cores\"\n          (if (equal? (length duplicates) 1) \"name\" \"names\")\n          (string-join (map (curry format \"\\\"~a\\\"\") duplicates) \", \")))\n  out)\n\n(module+ test\n  (require rackunit\n           \"../syntax/float.rkt\"\n           \"../syntax/load-platform.rkt\")\n\n  (activate-platform! (*platform-name*))\n  (define precision 'binary64)\n  (define ctx (context '(x y z a) <binary64> (make-list 4 <binary64>)))\n\n  ;; inlining\n\n  ;; Test classic quadp and quadm examples\n  (register-function! 'discr (list 'a 'b 'c) precision `(sqrt (- (* b b) (* a c))))\n  (define quadp `(/ (+ (- y) (discr x y z)) x))\n  (define quadm `(/ (- (- y) (discr x y z)) x))\n  (check-equal? (fpcore->prog quadp ctx)\n                '(/.f64 (+.f64 (neg.f64 y) (sqrt.f64 (-.f64 (*.f64 y y) (*.f64 x z)))) x))\n  (check-equal? (fpcore->prog quadm ctx)\n                '(/.f64 (-.f64 (neg.f64 y) (sqrt.f64 (-.f64 (*.f64 y y) (*.f64 x z)))) x))\n\n  ;; x^5 = x^3 * x^2\n  (register-function! 'sqr (list 'x) precision '(* x x))\n  (register-function! 'cube (list 'x) precision '(* x x x))\n  (define fifth '(* (cube a) (sqr a)))\n  (check-equal? (fpcore->prog fifth ctx) '(*.f64 (*.f64 (*.f64 a a) a) (*.f64 a a)))\n\n  ;; casting edge cases\n  (check-equal? (fpcore->prog `(cast x) ctx) 'x)\n  (check-equal? (fpcore->prog `(cast (! :precision binary64 x)) ctx) 'x))\n"
  },
  {
    "path": "src/syntax/rival.rkt",
    "content": ";; A narrow shim for Rival's \"machine\" abstraction.\n;; A Rival \"machine\" performs real evaluation for multiple expressions on a point.\n;;\n;; Ensure this file has minimal dependencies since `<herbie>/syntax/syntax.rkt`\n;; requires the file to synthesize floating-point implementations!\n;;\n\n#lang racket\n\n(require math/bigfloat\n         (prefix-in r2: rival)\n         (prefix-in r3: rival3))\n\n(require \"../config.rkt\"\n         \"../core/arrays.rkt\"\n         \"../utils/errors.rkt\"\n         \"../syntax/float.rkt\"\n         \"../utils/timeline.rkt\"\n         \"../syntax/types.rkt\"\n         \"../syntax/batch.rkt\")\n\n(define (use-rival3?)\n  (not (flag-set? 'setup 'rival2)))\n\n(define-syntax-rule (define/rival (name args ...) r2-impl r3-impl)\n  (define (name args ...)\n    (if (use-rival3?)\n        (r3-impl args ...)\n        (r2-impl args ...))))\n\n(define/rival (rival-compile exprs vars discs) r2:rival-compile r3:rival-compile)\n(define/rival (rival-apply machine pt hint) r2:rival-apply r3:rival-apply)\n(define/rival (rival-analyze-with-hints machine rect hint)\n              r2:rival-analyze-with-hints\n              r3:rival-analyze-with-hints)\n(define/rival (rival-profile machine param) r2:rival-profile r3:rival-profile)\n\n(define (repr->disc-type repr)\n  (cond\n    [(eq? repr <bool>) 'bool]\n    [(eq? repr <binary32>) 'f32]\n    [(eq? repr <binary64>) 'f64]\n    [else (error 'repr->disc-type \"unsupported repr ~a\" (representation-name repr))]))\n\n(define (repr->disc-convert repr)\n  (if (eq? repr <bool>)\n      (r3:discretization-convert r3:boolean-discretization)\n      (representation-bf->repr repr)))\n\n(define (make-discretizations reprs)\n  (if (use-rival3?)\n      ;; Rival 3 requires that all discretizations share the target precision for now\n      (let ([target (apply max (map representation-total-bits reprs))])\n        (cons (struct-copy r3:discretization r3:boolean-discretization [target target])\n              (for/list ([repr (in-list reprs)])\n                (r3:discretization (repr->disc-type repr) target (repr->disc-convert repr)))))\n      (cons r2:boolean-discretization\n            (for/list ([repr (in-list reprs)])\n              (define ulps (repr-ulps repr))\n              (r2:discretization (representation-total-bits repr)\n                                 (representation-bf->repr repr)\n                                 (lambda (x y) (- (ulps x y) 1)))))))\n\n(define (exn:rival:invalid? e)\n  (or (r2:exn:rival:invalid? e) (r3:exn:rival:invalid? e)))\n\n(define (exn:rival:unsamplable? e)\n  (or (r2:exn:rival:unsamplable? e) (r3:exn:rival:unsamplable? e)))\n\n(define *rival-max-precision*\n  (make-derived-parameter r2:*rival-max-precision*\n                          identity\n                          (lambda (v)\n                            (r3:*rival-max-precision* v)\n                            v)))\n\n(define *rival-max-iterations*\n  (make-derived-parameter r2:*rival-max-iterations*\n                          identity\n                          (lambda (v)\n                            (r3:*rival-max-iterations* v)\n                            v)))\n\n(define (*rival-profile-executions*)\n  (if (use-rival3?)\n      (r3:*rival-profile-executions*)\n      (r2:*rival-profile-executions*)))\n\n(define/rival (execution-name exec) r2:execution-name r3:execution-name)\n(define/rival (execution-precision exec) r2:execution-precision r3:execution-precision)\n(define/rival (execution-time exec) r2:execution-time r3:execution-time)\n(define/rival (execution-memory exec) r2:execution-memory r3:execution-memory)\n\n(struct herbie-ival (lo hi) #:transparent)\n\n(define (ival? x)\n  (or (herbie-ival? x) (r2:ival? x) (r3:ival? x)))\n\n(define (ival lo hi)\n  (herbie-ival lo hi))\n\n(define (ival-lo iv)\n  (cond\n    [(herbie-ival? iv) (herbie-ival-lo iv)]\n    [(r3:ival? iv) (r3:ival-lo iv)]\n    [else (r2:ival-lo iv)]))\n\n(define (ival-hi iv)\n  (cond\n    [(herbie-ival? iv) (herbie-ival-hi iv)]\n    [(r3:ival? iv) (r3:ival-hi iv)]\n    [else (r2:ival-hi iv)]))\n\n(provide (struct-out real-compiler)\n         ival\n         ival?\n         ival-lo\n         ival-hi\n         (contract-out\n          [make-real-compiler\n           (->i\n            ([batch batch?]\n             [brfs (listof batchref?)]\n             [ctxs (brfs) (and/c unified-contexts? (lambda (ctxs) (= (length brfs) (length ctxs))))])\n            (#:pre [pre any/c])\n            [c real-compiler?])]\n          [real-apply (->* (real-compiler? vector?) (any/c) (values symbol? any/c))]\n          [real-compiler-clear! (-> real-compiler? void?)]\n          [real-compiler-analyze (->* (real-compiler? (vectorof ival?)) (any/c) (listof any/c))]))\n\n(define (unified-contexts? ctxs)\n  (cond\n    [((non-empty-listof context?) ctxs)\n     (define ctx0 (car ctxs))\n     (for/and ([ctx (in-list (cdr ctxs))])\n       (and (equal? (context-vars ctx0) (context-vars ctx))\n            (for/and ([var (in-list (context-vars ctx0))])\n              (equal? (context-lookup ctx0 var) (context-lookup ctx var)))))]\n    [else #f]))\n\n(define (expr-size expr)\n  (if (list? expr)\n      (apply + 1 (map expr-size (cdr expr)))\n      1))\n\n;; Herbie's wrapper around the Rival machine abstraction.\n(struct real-compiler\n        (pre vars var-reprs exprs reprs machine dump-file assemble-point assemble-output))\n\n;; Creates a Rival machine.\n(define (make-real-compiler batch brfs ctxs #:pre [pre '(TRUE)])\n  (define specs (map (batch-exprs batch) brfs))\n  (define-values (specs* ctxs* pre* assemble-point assemble-output reprs)\n    (flatten-arrays-for-rival specs ctxs pre))\n  (define vars (context-vars (first ctxs*)))\n\n  ; create the machine\n  (define exprs (cons `(assert ,pre*) specs*))\n  (define discs (make-discretizations reprs))\n  (define machine (rival-compile exprs vars discs))\n  (timeline-push! 'compiler\n                  (apply + 1 (expr-size pre*) (map expr-size specs*))\n                  (+ (length vars) (rival-profile machine 'instructions)))\n\n  (define dump-file\n    (cond\n      [(flag-set? 'dump 'rival)\n       (define dump-dir \"dump-rival\")\n       (unless (directory-exists? dump-dir)\n         (make-directory dump-dir))\n       (define name\n         (for/first ([i (in-naturals)]\n                     #:unless (file-exists? (build-path dump-dir (format \"~a.rival\" i))))\n           (build-path dump-dir (format \"~a.rival\" i))))\n       (define dump-file (open-output-file name #:exists 'replace))\n       (pretty-print `(define (f ,@vars)\n                        ,@specs*)\n                     dump-file\n                     1)\n       (flush-output dump-file)\n       dump-file]\n      [else #f]))\n\n  ; wrap it with useful information for Herbie\n  (real-compiler pre\n                 (list->vector vars)\n                 (list->vector (context-var-reprs (first ctxs*)))\n                 specs*\n                 (list->vector reprs)\n                 machine\n                 dump-file\n                 assemble-point\n                 assemble-output))\n\n(define (bigfloat->readable-string x)\n  (define real (bigfloat->real x)) ; Exact rational unless inf/nan\n  (define float (real->double-flonum real))\n  (if (= real float)\n      (format \"#i~a\" float) ; The #i explicitly means nearest float\n      (number->string real))) ; Backup is print as rational\n\n;; Runs a Rival machine on an input point.\n(define (real-apply compiler pt [hint #f])\n  (match-define (real-compiler _ vars var-reprs _ _ machine dump-file _ _) compiler)\n  (define start (current-inexact-milliseconds))\n  (define pt*\n    (for/vector #:length (vector-length vars)\n                ([val (in-vector pt)]\n                 [repr (in-vector var-reprs)])\n      ((representation-repr->bf repr) val)))\n  (when dump-file\n    (define args (map bigfloat->readable-string (vector->list pt*)))\n    (fprintf dump-file \"(eval f ~a)\\n\" (string-join args \" \"))\n    (flush-output dump-file))\n  (define-values (status value)\n    (with-handlers ([exn:rival:invalid? (lambda (e) (values 'invalid #f))]\n                    [exn:rival:unsamplable? (lambda (e) (values 'exit #f))])\n      (parameterize ([*rival-max-precision* (*max-mpfr-prec*)]\n                     [*rival-max-iterations* 5])\n        (define value (rest (vector->list (rival-apply machine pt* hint)))) ; rest = drop precondition\n        (values 'valid value))))\n  (when (> (rival-profile machine 'bumps) 0)\n    (warn 'ground-truth\n          \"Could not converge on a ground truth\"\n          #:extra (for/list ([var (in-vector vars)]\n                             [val (in-vector pt)])\n                    (format \"~a = ~a\" var val))))\n  (define-values (iterations mixsample-data)\n    (if (use-rival3?)\n        (match-let ([(list summary _ iters) (rival-profile machine 'summary)])\n          (values iters\n                  (for/list ([entry (in-vector summary)])\n                    (match-define (list name prec-bucket total-time _) entry)\n                    (list total-time name prec-bucket 0))))\n        (let ()\n          (define executions (rival-profile machine 'executions))\n          (when (>= (vector-length executions) (r2:*rival-profile-executions*))\n            (warn 'profile \"Rival profile vector overflowed, profile may not be complete\"))\n          (define prec-threshold (exact-floor (/ (*max-mpfr-prec*) 25)))\n          (define mixsample-table (make-hash))\n          (for ([execution (in-vector executions)])\n            (define name (format \"~a\" (r2:execution-name execution)))\n            (define precision\n              (- (r2:execution-precision execution)\n                 (remainder (r2:execution-precision execution) prec-threshold)))\n            (define key (cons name precision))\n            ;; Uses vectors to avoid allocation; this is really allocation-heavy\n            (define data (hash-ref! mixsample-table key (lambda () (make-vector 2 0))))\n            (vector-set! data 0 (+ (vector-ref data 0) (r2:execution-time execution)))\n            (vector-set! data 1 (+ (vector-ref data 1) (r2:execution-memory execution))))\n          (values (rival-profile machine 'iterations)\n                  (for/list ([(key val) (in-hash mixsample-table)])\n                    (list (vector-ref val 0) (car key) (cdr key) (vector-ref val 1)))))))\n  (for ([entry (in-list mixsample-data)])\n    (match-define (list time name prec memory) entry)\n    (timeline-push!/unsafe 'mixsample time name prec memory))\n  (timeline-push!/unsafe 'outcomes\n                         (- (current-inexact-milliseconds) start)\n                         iterations\n                         (symbol->string status)\n                         1)\n  (values status value))\n\n;; Clears profiling data.\n(define (real-compiler-clear! compiler)\n  (unless (use-rival3?)\n    (r2:rival-profile (real-compiler-machine compiler) 'executions))\n  (void))\n\n;; Returns whether the machine is guaranteed to raise an exception\n;; for the given inputs range. The result is an interval representing\n;; how certain the result is: no, maybe, yes.\n(define (real-compiler-analyze compiler input-ranges [hint #f])\n  (define rect*\n    (for/vector #:length (vector-length input-ranges)\n                ([iv (in-vector input-ranges)])\n      (if (use-rival3?)\n          (r3:ival (ival-lo iv) (ival-hi iv))\n          (r2:ival (ival-lo iv) (ival-hi iv)))))\n  (rival-analyze-with-hints (real-compiler-machine compiler) rect* hint))\n\n(module+ test\n  (require rackunit)\n  (define <b64> <binary64>)\n  (define arr-repr (make-array-representation #:elem <b64> #:len 3))\n  (define arr-ctx (context '(v) arr-repr (list arr-repr)))\n  (define-values (specs* ctxs* pre* _assemble-pt _assemble-out reprs*)\n    (flatten-arrays-for-rival (list 'v) (list arr-ctx) 'TRUE))\n  (check-equal? specs* '(v_0 v_1 v_2))\n  (check-equal? (map context-vars ctxs*) '((v_0 v_1 v_2)))\n  (check-equal? (map context-var-reprs ctxs*) (list (list <b64> <b64> <b64>)))\n  (check-equal? reprs* (list <b64> <b64> <b64>))\n  (check-equal? (_assemble-out '(1 2 3)) '(#(1 2 3)))\n  (check-equal? pre* 'TRUE))\n"
  },
  {
    "path": "src/syntax/sugar.rkt",
    "content": ";; Expression conversions\n;;\n;; Herbie uses three expression languages.\n;; All formats are S-expressions with variables, numbers, and applications.\n;;\n;; FPCore: the input/output language\n;;\n;; - standardized interchange format with other tools\n;; - using a loopless subset with array literals\n;; - operators denote real computations while rounding contexts decide format\n;;\n;;  <FPCore> ::= (FPCore (<var> ...) <props> ... <expr>)\n;;             | (FPCore <id> (<var> ...) <props> ... <expr>)\n;;\n;;  <expr>   ::= (let ([<id> <expr>] ...) <expr>)\n;;             | (let* ([<id> <expr>] ...) <expr>)\n;;             | (if <expr> <expr> <expr>\n;;             | (cast <expr>)\n;;             | (! <props> ... <expr>)\n;;             | (<op> <expr> ...)\n;;             | <number>\n;;             | <id>\n;;\n;;  <var>    ::= <id>\n;;             | (! <props> ... <expr>)\n;;\n;; LImpl: the language of floating-point expressions\n;;\n;; - internal language, describes floating-point expressions\n;; - unary minus represented by `neg`\n;; - every operator is rounded\n;; - let expressions are inlined\n;; - numbers are rounded to a particular format\n;;\n;; <expr> ::= (<impl> <expr> ...)\n;;          | (literal <number> <repr>)\n;;          | <id>\n;;\n;; Every operator has a type signature where types are representations.\n;; In practice, most operator implemenetations have uniform representations but\n;; operations like casts are multi-format.\n;;\n;; LSpec: the language of mathematical formula\n;;\n;; - internal language, describes real-number formula\n;; - unary minus represented by `neg`\n;; - every operator is a real-number operation\n;; - every operator is supported by Rival\n;; - let expressions are inlined\n;; - casts are mapped to the identity operation\n;; - numbers are formatless\n;;\n;; <expr> ::= (<op> <expr> ...)\n;;          | <number>\n;;          | <id>\n;;\n\n#lang racket\n\n(require \"../utils/common.rkt\"\n         \"../utils/errors.rkt\"\n         \"platform.rkt\"\n         \"matcher.rkt\"\n         \"syntax.rkt\"\n         \"types.rkt\")\n\n(provide fpcore->prog\n         prog->fpcore)\n\n;; Local copies to avoid depending on core/programs.rkt.\n(define (repr-of expr ctx)\n  (match expr\n    [(literal _ precision) (get-representation precision)]\n    [(? symbol?) (context-lookup ctx expr)]\n    [(approx _ impl) (repr-of impl ctx)]\n    [(hole precision _) (get-representation precision)]\n    [(list op _ ...) (impl-info op 'otype)]))\n\n(define (replace-vars dict expr)\n  (let loop ([expr expr])\n    (match expr\n      [(? literal?) expr]\n      [(? number?) expr]\n      [(? symbol?) (dict-ref dict expr expr)]\n      [(approx impl spec) (approx (loop impl) (loop spec))]\n      [(list op args ...) (cons op (map loop args))])))\n\n;; Expression pre-processing for normalizing expressions.\n;; Used for conversion from FPCore to other IRs.\n(define (expand-expr expr)\n  (let loop ([expr expr]\n             [env '()])\n    (match expr\n      ; empty let/let* expression\n      [`(,(or 'let 'let*) () ,body) (loop body env)]\n      ; let* expression\n      [`(let* ([,var ,val]\n               ,rest ...)\n          ,body)\n       (loop `(let ([,var ,val]) (let* ,rest ,body)) env)]\n      ; let expression\n      [`(let ([,vars ,vals] ...) ,body)\n       (define env*\n         (for/fold ([env* env])\n                   ([var (in-list vars)]\n                    [val (in-list vals)])\n           (dict-set env* var (loop val env))))\n       (loop body env*)]\n      ; nullary expressions\n      ['(and) '(TRUE)]\n      ['(or) '(FALSE)]\n      [`(,(or '+ '-)) 0]\n      [`(,(or '* '/)) 1]\n      ; unary expressions\n      [`(,(or '+ '* 'and 'or) ,a) (loop a env)]\n      [`(- ,a) `(neg ,(loop a env))]\n      [`(/ ,a) `(/ 1 ,(loop a env))]\n      ; expand arithmetic associativity\n      [`(,(and (or '+ '- '* '/ 'and 'or) op) ,as ..2 ,b)\n       (list op (loop `(,op ,@as) env) (loop b env))]\n      ; expand comparison associativity\n      [`(,(and (or '< '<= '> '>= '=) op) ,as ...)\n       (define as* (map (curryr loop env) as))\n       (define out\n         (for/fold ([out #f])\n                   ([term as*]\n                    [next (cdr as*)])\n           (if out\n               (list 'and out (list op term next))\n               (list op term next))))\n       (or out '(TRUE))]\n      [`(!= ,as ...)\n       (define as* (map (curryr loop env) as))\n       (define out\n         (for/fold ([out #f])\n                   ([term as*]\n                    [i (in-naturals)]\n                    #:when true\n                    [term2 as*]\n                    [j (in-naturals)]\n                    #:when (< i j))\n           (if out\n               (list 'and out (list '!= term term2))\n               (list '!= term term2))))\n       (or out '(TRUE))]\n      ; function calls\n      [(list (? (curry hash-has-key? (*functions*)) fname) args ...)\n       (match-define (list vars _ body) (hash-ref (*functions*) fname))\n       (define env*\n         (for/fold ([env* '()])\n                   ([var (in-list vars)]\n                    [arg (in-list args)])\n           (dict-set env* var (loop arg env))))\n       (loop body env*)]\n      ; applications\n      [`(,op ,args ...) `(,op ,@(map (curryr loop env) args))]\n      ; constants\n      [(? operator-exists? op) (list expr)]\n      ; variables\n      [(? symbol?) (dict-ref env expr expr)]\n      ; other\n      [_ expr])))\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; FPCore -> LImpl\n\n(define (assert-fpcore-impl op prop-dict ireprs)\n  (or (get-fpcore-impl op prop-dict ireprs)\n      (raise-herbie-missing-error\n       \"No implementation for `~a` under rounding context `~a` with types `~a`\"\n       op\n       prop-dict\n       (string-join (map (λ (r) (format \"<~a>\" (representation-name r))) ireprs) \" \"))))\n\n;; Translates an FPCore operator application into\n;; an LImpl operator application.\n(define (fpcore->impl-app op prop-dict args ctx)\n  (define ireprs (map (lambda (arg) (repr-of arg ctx)) args))\n  (define impl (assert-fpcore-impl op prop-dict ireprs))\n  (define vars (impl-info impl 'vars))\n  (define pattern\n    (match (impl-info impl 'fpcore)\n      [(list '! _ ... body) body]\n      [body body]))\n  (define subst (pattern-match pattern (cons op args)))\n  (pattern-substitute (cons impl vars) subst))\n\n;; Translates from FPCore to an LImpl.\n(define (fpcore->prog prog ctx)\n  (let loop ([expr (expand-expr prog)]\n             [prop-dict (repr->prop (context-repr ctx))])\n    (match expr\n      [(? number? n)\n       (literal (match n\n                  [(or +inf.0 -inf.0 +nan.0) expr]\n                  [(? exact?) expr]\n                  [_ (inexact->exact expr)])\n                (dict-ref prop-dict ':precision))]\n      [(? symbol?) expr]\n      [(list '! props ... body)\n       (loop body\n             (if (not (null? props))\n                 (apply dict-set* prop-dict props)\n                 prop-dict))]\n      [(list 'neg arg) ; non-standard but useful [TODO: remove]\n       (define arg* (loop arg prop-dict))\n       (fpcore->impl-app '- prop-dict (list arg*) ctx)]\n      [(list 'cast arg) ; special case: unnecessary casts\n       (define arg* (loop arg prop-dict))\n       (define repr (get-representation (dict-ref prop-dict ':precision)))\n       (if (equal? (repr-of arg* ctx) repr)\n           arg*\n           (fpcore->impl-app 'cast prop-dict (list arg*) ctx))]\n      [(list 'ref arr idx)\n       (define arr* (loop arr prop-dict))\n       (define idx* (loop idx prop-dict))\n       (define arr-repr (repr-of arr* ctx))\n       (define idx-repr (repr-of idx* ctx))\n       (define impl (assert-fpcore-impl 'ref prop-dict (list arr-repr idx-repr)))\n       (define vars (impl-info impl 'vars))\n       (define pattern\n         (match (impl-info impl 'fpcore)\n           [(list '! _ ... body) body]\n           [body body]))\n       (define subst (pattern-match pattern (list 'ref arr* idx*)))\n       (pattern-substitute (cons impl vars) subst)]\n      [(list op args ...)\n       (define args* (map (lambda (arg) (loop arg prop-dict)) args))\n       (fpcore->impl-app op prop-dict args* ctx)])))\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; LImpl -> FPCore\n;; Translates from LImpl to an FPCore\n\n;; TODO: this process uses a batch-like data structure\n;; but _without_ deduplication since different use sites\n;; of a particular subexpression may have different\n;; parent rounding contexts. Would be nice to explore\n;; if the batch data structure can be used.\n\n;; Instruction vector index\n(struct index (v) #:prefab)\n\n;; Translates a literal (LImpl) to an FPCore expr\n(define (literal->fpcore x)\n  (match x\n    [(literal -inf.0 _) '(- INFINITY)]\n    [(literal +inf.0 _) 'INFINITY]\n    [(literal v (or 'binary64 'binary32)) (exact->inexact v)]\n    [(literal v _) v]))\n\n;; Step 1.\n;; Translates from LImpl to a series of let bindings such that each\n;; local variable is bound once and used at most once. The result is an\n;; instruction vector, representing the let bindings; the operator\n;; implementation for each instruction, and the final \"root\" operation/literal.\n;; Except for let-bound variables, the subexpressions are in FPCore.\n\n(define (prog->let-exprs expr)\n  (define instrs '())\n  (define (push! impl node)\n    (define id (length instrs))\n    (set! instrs (cons (cons node impl) instrs))\n    (index id))\n\n  (define (munge expr #:root? [root? #f])\n    (match expr\n      [(? literal?) (literal->fpcore expr)]\n      [(? number?) expr]\n      [(? symbol?) expr]\n      [(approx _ impl) (munge impl)]\n      [(hole _ spec) (munge spec)]\n      [(list (? impl-exists? impl) args ...)\n       (define args* (map munge args))\n       (define vars (impl-info impl 'vars))\n       (define node (replace-vars (map cons vars args*) (impl-info impl 'fpcore)))\n       (if root?\n           node\n           (push! impl node))]\n      [(list spec-op) spec-op]\n      [(list spec-op args ...) (list* spec-op (map munge args))]))\n\n  (define root (munge expr #:root? #t))\n  (cons (list->vector (reverse instrs)) root))\n\n;; Step 2.\n;; Inlines let bindings; let-inlining is generally unsound with\n;; rounding properties (the parent context may change),\n;; so we only inline those that result in the same operator\n;; implementation when converting back from FPCore to LImpl.\n\n(define (inline! root ivec ctx)\n  (define global-prop-dict (repr->prop (context-repr ctx)))\n  (let loop ([node root]\n             [prop-dict global-prop-dict])\n    (match node\n      [(? number?) node] ; number\n      [(? symbol?) node] ; variable\n      [(index idx) ; let-bound variable\n       ; we check what happens if we inline\n       (match-define (cons expr impl) (vector-ref ivec idx))\n       (define impl*\n         (match expr\n           [(list '! props ... (or (? symbol? op) (list op _ ...)))\n            ; rounding context updated parent context\n            (define prop-dict*\n              (if (not (null? props))\n                  (apply dict-set prop-dict props)\n                  prop-dict))\n            (assert-fpcore-impl op prop-dict* (impl-info impl 'itype))]\n           ; rounding context inherited from parent context\n           [(or (? symbol? op) (list op _ ...))\n            (assert-fpcore-impl op prop-dict (impl-info impl 'itype))]))\n       (cond\n         [(equal? impl impl*) ; inlining is safe\n          (define expr* (loop expr prop-dict))\n          (vector-set! ivec idx #f)\n          expr*]\n         [else ; inlining is not safe\n          (define expr* (loop expr global-prop-dict))\n          (vector-set! ivec idx expr*)\n          node])]\n      [(list '! props ... body) ; explicit rounding context\n       (define prop-dict* (props->dict props))\n       (define body* (loop body prop-dict*))\n       (define new-prop-dict\n         (for/list ([(k v) (in-dict prop-dict*)]\n                    #:unless (and (dict-has-key? prop-dict k) (equal? (dict-ref prop-dict k) v)))\n           (cons k v)))\n       (if (null? new-prop-dict)\n           body*\n           `(! ,@(append* (for/list ([(k v) (in-list new-prop-dict)])\n                            (list k v)))\n               ,body*))]\n      [(list op args ...) ; operator application\n       (define args* (map (lambda (e) (loop e prop-dict)) args))\n       `(,op ,@args*)])))\n\n;; Step 3.\n;; Construct the final FPCore expression using remaining let-bindings\n;; and the let-free body from the previous step.\n\n(define (reachable-indices ivec expr)\n  (define reachable (mutable-set))\n  (let loop ([expr expr])\n    (match expr\n      [(? number?) (void)]\n      [(? symbol?) (void)]\n      [(index idx)\n       (set-add! reachable idx)\n       (loop (vector-ref ivec idx))]\n      [(list _ args ...) (for-each loop args)]))\n  reachable)\n\n(define (remove-indices id->name expr)\n  (let loop ([expr expr])\n    (match expr\n      [(? number?) expr]\n      [(? symbol?) expr]\n      [(index idx) (hash-ref id->name idx)]\n      [(list '! props ... body) `(! ,@props ,(loop body))]\n      [(list op args ...) `(,op ,@(map loop args))])))\n\n(define (build-expr expr ivec ctx)\n  ; variable generation\n  (define vars (list->mutable-seteq (context-vars ctx)))\n  (define counter 0)\n  (define (gensym)\n    (set! counter (add1 counter))\n    (match (string->symbol (format \"t~a\" counter))\n      [(? (curry set-member? vars)) (gensym)]\n      [x\n       (set-add! vars x)\n       x]))\n\n  ; need fresh variables for reachable, non-inlined subexpressions\n  (define reachable (reachable-indices ivec expr))\n  (define id->name (make-hash))\n  (for ([expr (in-vector ivec)]\n        [idx (in-naturals)]\n        #:when (and expr (set-member? reachable idx)))\n    (hash-set! id->name idx (gensym)))\n\n  (for/fold ([body (remove-indices id->name expr)]) ([idx (in-list (sort (hash-keys id->name) >))])\n    (define var (hash-ref id->name idx))\n    (define val (remove-indices id->name (vector-ref ivec idx)))\n    `(let ([,var ,val]) ,body)))\n\n;; Translates from LImpl to an FPCore.\n;; The implementation of this procedure is complicated since\n;;  (1) every operator implementation requires certain (FPCore) rounding properties\n;;  (2) rounding contexts have lexical scoping\n(define (prog->fpcore prog ctx)\n  ; step 1: convert to an instruction vector where\n  ; each expression is evaluated under explicit rounding contexts\n  (match-define (cons ivec root) (prog->let-exprs prog))\n\n  ; step 2: inline nodes\n  (define body (inline! root ivec ctx))\n\n  ; step 3: construct the actual FPCore expression from\n  ; the remaining let-bindings and body\n  (build-expr body ivec ctx))\n"
  },
  {
    "path": "src/syntax/syntax-check.rkt",
    "content": "#lang racket\n\n(require syntax/id-set)\n(require \"../utils/common.rkt\"\n         \"../utils/errors.rkt\"\n         \"syntax.rkt\"\n         \"types.rkt\"\n         \"platform.rkt\")\n(provide assert-program!)\n\n(define (check-expression* stx vars error!)\n  (let loop ([stx stx]\n             [vars vars])\n    (match stx\n      [#`,(? number?) (void)]\n      [#`,(? operator-exists? stx) (void)]\n      [#`,(? symbol? var)\n       (unless (set-member? vars stx)\n         (error! stx \"Unknown variable ~a\" var))]\n      [#`(let* ([#,vars* #,vals] ...) #,body)\n       (define bindings\n         (for/fold ([vars vars])\n                   ([var vars*]\n                    [val vals])\n           (unless (identifier? var)\n             (error! var \"Invalid variable name ~a\" var))\n           (loop val vars)\n           (bound-id-set-union vars (immutable-bound-id-set (list var)))))\n       (loop body bindings)]\n      [#`(let ([#,vars* #,vals] ...) #,body)\n       ;; These are unfolded by desugaring\n       (for ([var vars*]\n             [val vals])\n         (unless (identifier? var)\n           (error! var \"Invalid variable name ~a\" var))\n         (loop val vars))\n       (loop body (bound-id-set-union vars (immutable-bound-id-set vars*)))]\n      [#`(let #,varlist #,body)\n       (error! stx \"Invalid `let` expression variable list ~a\" (syntax->datum varlist))\n       (loop body vars)]\n      [#`(let #,args ...)\n       (error! stx \"Invalid `let` expression with ~a arguments (expects 2)\" (length args))\n       (unless (null? args)\n         (loop (last args) vars))]\n      [#`(if #,cond #,ift #,iff)\n       (loop cond vars)\n       (loop ift vars)\n       (loop iff vars)]\n      [#`(if #,args ...)\n       (error! stx \"Invalid `if` expression with ~a arguments (expects 3)\" (length args))\n       (unless (null? args)\n         (loop (last args) vars))]\n      [#`(! #,props ... #,body)\n       (check-properties* props '() error!)\n       (loop body vars)]\n      [#`(array #,elems ...)\n       (when (null? elems)\n         (error! stx \"Array literal must have at least one element\"))\n       (for ([elem (in-list elems)])\n         (loop elem vars))]\n      [#`(ref #,arr ,idx)\n       (unless (integer? idx)\n         (error! idx \"Array index must be a literal integer, got ~a\" idx))\n       (loop arr vars)]\n      [#`(cast #,arg) (loop arg vars)]\n      [#`(cast #,args ...)\n       (error! stx \"Invalid `cast` expression with ~a arguments (expects 1)\" (length args))\n       (unless (null? args)\n         (loop (first args) vars))]\n      [#`(,(? (curry set-member? '(+ * and or))) #,args ...)\n       ;; Variary (minimum 0 arguments)\n       (for ([arg args])\n         (loop arg vars))]\n      [#`(,(? (curry set-member? '(- / = != < > <= >=))))\n       ;; Variary (minimum 1 arg)\n       (error! stx \"Variary operator expects at least one argument\")]\n      [#`(,(? (curry set-member? '(- / = != < > <= >=))) #,args ...)\n       ;; Variary (minimum 1 arg)\n       (for ([arg args])\n         (loop arg vars))]\n      [#`(,(? (curry set-member? '(+ - * / and or = != < > <= >=))) #,args ...)\n       ;; These expand by associativity so we don't check the number of arguments\n       (for ([arg args])\n         (loop arg vars))]\n      [#`(,(? (curry set-member? '(erfc expm1 log1p hypot fma)) op) #,args ...)\n       ; FPCore operators that are composite in Herbie\n       (define arity\n         (case op\n           [(erfc expm1 log1p) 1]\n           [(hypot) 2]\n           [(fma) 3]))\n       (unless (= arity (length args))\n         (error! stx \"Operator ~a given ~a arguments (expects ~a)\" op (length args) arity))\n       (for ([arg (in-list args)])\n         (loop arg vars))]\n      [#`(#,f-syntax #,args ...)\n       (define f (syntax->datum f-syntax))\n       (cond\n         [(operator-exists? f)\n          (define arity (length (operator-info f 'itype)))\n          (unless (= arity (length args))\n            (error! stx \"Operator ~a given ~a arguments (expects ~a)\" f (length args) arity))]\n         [(hash-has-key? (*functions*) f)\n          (match-define (list vars _ _) (hash-ref (*functions*) f))\n          (unless (= (length vars) (length args))\n            (error! stx \"Function ~a given ~a arguments (expects ~a)\" f (length args) (length vars)))]\n         [else (error! stx \"Unknown operator ~a\" f)])\n       (for ([arg args])\n         (loop arg vars))]\n      [_ (error! stx \"Unknown syntax ~a\" (syntax->datum stx))])))\n\n(define (check-property* prop error!)\n  (unless (identifier? prop)\n    (error! prop \"Invalid property name ~a\" prop))\n  (define name (~a (syntax-e prop)))\n  (unless (equal? (substring name 0 1) \":\")\n    (error! prop \"Invalid property name ~a\" prop)))\n\n(define (check-properties* props vars error!)\n  (define prop-dict\n    (let loop ([props props]\n               [out '()])\n      (match props\n        [(list (? identifier? prop-name) value rest ...)\n         (check-property* prop-name error!)\n         (loop rest (cons (cons (syntax-e prop-name) value) out))]\n        [(list head)\n         (check-property* head error!)\n         (error! head \"Property ~a has no value\" head)\n         out]\n        [(list) out])))\n\n  (when (dict-has-key? prop-dict ':name)\n    (define name (dict-ref prop-dict ':name))\n    (unless (string? (syntax-e name))\n      (error! name \"Invalid :name ~a; must be a string\" name)))\n\n  (when (dict-has-key? prop-dict ':herbie-platform)\n    (define name (dict-ref prop-dict ':herbie-platform))\n    (unless (identifier? name)\n      (error! name \"Invalid :herbie-platform ~a; must be a symbol\" name)))\n\n  (when (dict-has-key? prop-dict ':precision)\n    (define prec (dict-ref prop-dict ':precision))\n    (define repr (get-representation (syntax->datum prec)))\n    (unless repr\n      (error! prec \"Unknown :precision ~a\" prec))\n    (unless (or (not repr) (equal? (representation-type repr) 'real))\n      (error! prec \"Invalid :precision ~a; expected a real representation name\" prec)))\n\n  (when (dict-has-key? prop-dict ':cite)\n    (define cite (dict-ref prop-dict ':cite))\n    (if (list? (syntax-e cite))\n        (for ([citation (syntax-e cite)]\n              #:unless (identifier? citation))\n          (error! citation \"Invalid citation ~a; must be a variable name\" citation))\n        (error! cite \"Invalid :cite ~a; must be a list\" cite)))\n\n  (when (dict-has-key? prop-dict ':pre)\n    (check-expression* (dict-ref prop-dict ':pre) vars error!))\n\n  (when (dict-has-key? prop-dict ':alt)\n    (check-expression* (dict-ref prop-dict ':alt) vars error!))\n\n  (void))\n\n(define (check-argument name dims sow error!)\n  (unless (identifier? name)\n    (error! name \"Invalid argument name ~a\" name))\n  (for ([dim (in-list dims)])\n    (define dim* (syntax-e dim))\n    (unless (number? dim*)\n      (error! dim \"Invalid dimension ~a; must be a positive integer literal\" dim))\n    (when (number? dim*)\n      (unless (exact-positive-integer? dim*)\n        (error! dim \"Invalid dimension ~a; dimensions must be positive integers\" dim))))\n  (sow name))\n\n(define (check-program* stx vars props body error!)\n  (unless (list? vars)\n    (error! stx \"Invalid arguments list ~a; must be a list\" stx))\n  (define vars*\n    (reap [sow]\n          (when (list? vars)\n            (for ([var (in-list vars)])\n              (match var\n                [(? identifier? x) (check-argument x '() sow error!)]\n                [#`(! #,props ... #,name #,dims ...)\n                 (check-properties* props (immutable-bound-id-set '()) error!)\n                 (check-argument name dims sow error!)]\n                [#`(#,name #,dims ...) (check-argument name dims sow error!)]\n                [_ (error! var \"Invalid argument name ~a\" var)])))))\n  (when (check-duplicate-identifier vars*)\n    (error! stx \"Duplicate argument name ~a\" (check-duplicate-identifier vars*)))\n  (check-properties* props (immutable-bound-id-set vars*) error!)\n  (check-expression* body (immutable-bound-id-set vars*) error!))\n\n(define (check-fpcore* stx error!)\n  (match stx\n    [#`(FPCore #,name (#,vars ...) #,props ... #,body)\n     (unless (identifier? name)\n       (error! stx \"FPCore identifier must be a symbol: ~a\" name))\n     (check-program* stx vars props body error!)]\n    [#`(FPCore (#,vars ...) #,props ... #,body) (check-program* stx vars props body error!)]\n    [#`(FPCore #,something ...) (error! stx \"FPCore not in a valid format: ~s\" stx)]\n    [_ (error! stx \"Not an FPCore: ~a\" stx)]))\n\n(define (assert-program! stx)\n  (define errs\n    (reap [sow]\n          (define (error! stx fmt . args)\n            (define args*\n              (for/list ([x (in-list args)])\n                (if (syntax? x)\n                    (syntax->datum x)\n                    x)))\n            (sow (cons stx (apply format fmt args*))))\n          (check-fpcore* stx error!)))\n  (unless (null? errs)\n    (raise-herbie-syntax-error \"Invalid program\" #:locations errs)))\n\n;; testing FPCore format\n(module+ test\n  (require rackunit)\n  (require \"../syntax/load-platform.rkt\")\n  (activate-platform! (*platform-name*))\n\n  (define (get-errs stx)\n    (reap [sow]\n          (define (error! stx fmt . args)\n            (define args*\n              (for/list ([x (in-list args)])\n                (if (syntax? x)\n                    (syntax->datum x)\n                    x)))\n            (sow (cons stx (apply format fmt args*))))\n          (check-fpcore* stx error!)))\n\n  (check-pred (compose not null?) (get-errs #'a))\n  (check-pred (compose not null?) (get-errs #'(FPCore)))\n  (check-pred (compose not null?) (get-errs #'(FPCore foo 1)))\n  (check-pred (compose not null?) (get-errs #'(FPCore foo x 1)))\n  (check-pred (compose not null?) (get-errs #'(FPCore foo foo2 (x) x)))\n\n  (check-pred null? (get-errs #'(FPCore (x) x)))\n  (check-pred null? (get-errs #'(FPCore (x) :precision binary64 x)))\n  (check-pred null? (get-errs #'(FPCore foo (x) x)))\n  (check-pred null? (get-errs #'(FPCore foo (x) :precision binary64 x)))\n\n  (check-pred null? (get-errs #'(FPCore (x) (array 1 2))))\n  (check-pred null? (get-errs #'(FPCore (x) (ref (array 1 2) 0))))\n  (check-pred null? (get-errs #'(FPCore (x) (array 1 2 3))))\n  (check-pred null? (get-errs #'(FPCore (x) (ref (array 1 2) 2))))\n  (check-pred null? (get-errs #'(FPCore ((v 3)) v)))\n  (check-pred null? (get-errs #'(FPCore ((v 2 2)) v))))\n"
  },
  {
    "path": "src/syntax/syntax.rkt",
    "content": "#lang racket\n\n(require math/bigfloat\n         racket/hash\n         (only-in rival/eval/main rival-functions))\n\n(require \"../utils/common.rkt\"\n         \"../utils/errors.rkt\"\n         \"matcher.rkt\"\n         \"types.rkt\")\n\n(provide (struct-out literal)\n         (struct-out approx)\n         (struct-out hole)\n         operator-exists?\n         operator-info\n         all-operators ; return a list of operators names\n         *functions*\n         register-function!\n         (struct-out operator-impl)) ; required by platform.rkt\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; Real operators\n;; Pure mathematical operations\n\n;; TODO: specs should really be associated with impls\n;; unfortunately Herbie still mandates that every impl\n;; has an associated operator so the spec is here\n\n;; All real operators come from Rival\n\n;; Checks if an operator has been registered.\n(define (operator-exists? op)\n  (or (hash-has-key? rival-functions op) (equal? op 'ref) (equal? op 'array)))\n\n;; Returns all operators.\n(define (all-operators)\n  (sort (append (hash-keys rival-functions) (list 'array 'ref)) symbol<?))\n\n;; Looks up a property `field` of a real operator `op`.\n;; Panics if the operator is not found.\n(define/contract (operator-info op field)\n  (-> symbol? (or/c 'itype 'otype) any/c)\n  (define info\n    (cond\n      [(equal? op 'ref) '(real array real)]\n      [(equal? op 'array) '(array real real)]\n      [else\n       (hash-ref rival-functions\n                 op\n                 (lambda () (raise-arguments-error 'operator-info \"Unknown operator\" \"op\" op)))]))\n  (match-define (cons otype itypes) info)\n  (case field\n    [(itype) itypes]\n    [(otype) otype]))\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; Operator implementations\n;; Floating-point operations that approximate mathematical operations\n\n;; Operator implementations _approximate_ a program of\n;; mathematical operators with fixed input and output representations.\n;;\n;; An operator implementation requires\n;;  - a (unique) name\n;;  - input variables/representations\n;;  - output representation\n;;  - a specification it approximates\n;;  - its FPCore representation\n;;  - a floating-point implementation\n;;\n(struct operator-impl (name ctx spec fpcore fl cost aggregate))\n\n;; Floating-point expressions require that numbers\n;; be rounded to a particular precision.\n(struct literal (value precision) #:prefab)\n\n;; An approximation of a specification by\n;; a floating-point expression.\n(struct approx (spec impl) #:prefab)\n\n;; An unknown floating-point expression that implements a given spec\n(struct hole (precision spec) #:prefab)\n\n;; name -> (vars repr body)\t;; name -> (vars prec body)\n(define *functions* (make-parameter (make-hasheq)))\n\n(define (register-function! name args repr body) ;; Adds a function definition.\n  (hash-set! (*functions*) name (list args repr body)))\n"
  },
  {
    "path": "src/syntax/test-syntax.rkt",
    "content": "#lang racket\n\n(require \"syntax.rkt\"\n         \"platform.rkt\"\n         \"types.rkt\")\n\n(module+ test\n  (require rackunit\n           \"../config.rkt\"\n           \"../syntax/load-platform.rkt\")\n\n  (activate-platform! (*platform-name*))\n  (define f64 (get-representation 'binary64))\n\n  (define sin-proc (impl-info 'sin.f64 'fl))\n  (check-equal? (sin-proc 0.0) 0.0 \"sin(0) = 0\")\n\n  ; get-fpcore-impl\n  (define (get-impl op props itypes)\n    (get-fpcore-impl op props itypes))\n\n  (check-equal? (get-impl '+ '((:precision . binary64)) (list f64 f64)) '+.f64)\n  (check-equal? (get-impl '+ '((:precision . binary64) (:description . \"test\")) (list f64 f64))\n                '+.f64)\n  (check-equal? (get-impl 'sin '((:precision . binary64)) (list f64)) 'sin.f64)\n\n  (void))\n"
  },
  {
    "path": "src/syntax/type-check.rkt",
    "content": "#lang racket\n\n(require \"../utils/common.rkt\"\n         \"../utils/errors.rkt\"\n         \"types.rkt\"\n         \"platform.rkt\"\n         \"syntax.rkt\"\n         (except-in \"platform-language.rkt\" quasisyntax))\n(provide assert-program-typed!)\n\n(define (repr-description t)\n  (match t\n    [(? representation?) (representation-name t)]\n    [(? array-representation?)\n     `(array ,(repr-description (array-representation-elem t)) ,(array-representation-len t))]))\n\n(define (repr-compatible-with-precision? repr precision-repr)\n  (match repr\n    [(? array-representation?)\n     (repr-compatible-with-precision? (array-representation-elem repr) precision-repr)]\n    [(? representation?)\n     (or (equal? (representation-type repr) 'bool) (equal? repr precision-repr))]))\n\n(define (array-of elem dims)\n  (for/fold ([out elem]) ([d (in-list (reverse dims))])\n    (make-array-representation #:elem out #:len d)))\n\n(define (assert-program-typed! stx)\n  (define-values (vars props body)\n    (match (syntax-e stx)\n      [(list (app syntax-e 'FPCore) _ (app syntax-e (list vars ...)) props ... body)\n       (values vars props body)]\n      [(list (app syntax-e 'FPCore) (app syntax-e (list vars ...)) props ... body)\n       (values vars props body)]))\n\n  (define default-dict `((:precision . ,(*default-precision*))))\n  (define prop-dict (apply dict-set* default-dict (map syntax->datum props)))\n  (define prec (dict-ref prop-dict ':precision))\n  (define program-repr (get-representation prec))\n\n  (define-values (var-names var-types)\n    (for/lists (var-names var-types)\n               ([var (in-list vars)])\n               (match (syntax->datum var)\n                 [(list '! props ... name dims ...)\n                  (define prop-dict (props->dict props))\n                  (define arg-prec (dict-ref prop-dict ':precision prec))\n                  (define arg-repr (get-representation arg-prec))\n                  (values name (array-of arg-repr dims))]\n                 [(list (? symbol? name) dims ...) (values name (array-of program-repr dims))]\n                 [(? symbol? name) (values name program-repr)])))\n\n  (define ctx (context var-names program-repr var-types))\n  (values (assert-expression-type! body prop-dict ctx) ctx))\n\n(define (assert-expression-type! stx props ctx)\n  (define errs '())\n  (define (error! stx fmt . args)\n    (define args* (map repr-description args))\n    (set! errs (cons (cons stx (apply format fmt args*)) errs)))\n\n  (define repr (expression->type stx props ctx error!))\n  (define expected (context-repr ctx))\n  (when (not (repr-compatible-with-precision? repr expected))\n    (error! stx\n            \"Expected program of type ~a, got type ~a\"\n            (repr-description expected)\n            (repr-description repr)))\n\n  (unless (null? errs)\n    (raise-herbie-syntax-error \"Program has type errors\" #:locations errs))\n  repr)\n\n(define (application->string op types)\n  (format \"(~a ~a)\"\n          op\n          (string-join (for/list ([t types])\n                         (if t\n                             (format \"<~a>\" (repr-description t))\n                             \"<?>\"))\n                       \" \")))\n\n(define (expression->type stx prop-dict ctx error!)\n  (let loop ([stx stx]\n             [prop-dict prop-dict]\n             [ctx ctx])\n    (match stx\n      [#`,(? number?) (get-representation (dict-ref prop-dict ':precision))]\n      [#`,(? operator-exists? op)\n       (match (get-fpcore-impl op prop-dict '())\n         [#f ; no implementation found\n          (error! stx \"No implementation of `~a` in platform for context `~a`\" op prop-dict)\n          (get-representation (dict-ref prop-dict ':precision))]\n         [impl (impl-info impl 'otype)])]\n      [#`,(? symbol? x) (context-lookup ctx x)]\n      [#`(let ([,ids #,exprs] ...) #,body)\n       (define ctx*\n         (for/fold ([ctx* ctx])\n                   ([id (in-list ids)]\n                    [expr (in-list exprs)])\n           (context-extend ctx* id (loop expr prop-dict ctx))))\n       (loop body prop-dict ctx*)]\n      [#`(let* ([,ids #,exprs] ...) #,body)\n       (define ctx*\n         (for/fold ([ctx* ctx])\n                   ([id (in-list ids)]\n                    [expr (in-list exprs)])\n           (context-extend ctx* id (loop expr prop-dict ctx*))))\n       (loop body prop-dict ctx*)]\n      [#`(if #,branch #,ifstmt #,elsestmt)\n       (define cond-ctx (struct-copy context ctx [repr (get-representation 'bool)]))\n       (define cond-repr (loop branch prop-dict cond-ctx))\n       (unless (equal? (representation-type cond-repr) 'bool)\n         (error! stx \"If statement has non-boolean type ~a for branch\" (repr-description cond-repr)))\n       (define ift-repr (loop ifstmt prop-dict ctx))\n       (define iff-repr (loop elsestmt prop-dict ctx))\n       (unless (equal? ift-repr iff-repr)\n         (error! stx\n                 \"If statement has different types for if (~a) and else (~a)\"\n                 (repr-description ift-repr)\n                 (repr-description iff-repr)))\n       ift-repr]\n      [#`(! #,props ... #,body) (loop body (apply dict-set prop-dict (map syntax->datum props)) ctx)]\n      [#`(,(? (curry hash-has-key? (*functions*)) fname) #,args ...)\n       ; TODO: inline functions expect uniform types, this is clearly wrong\n       (match-define (list vars prec _) (hash-ref (*functions*) fname))\n       (define repr (get-representation prec))\n       (define ireprs (map (lambda (arg) (loop arg prop-dict ctx)) args))\n       (define expected (map (const repr) vars))\n       (unless (andmap equal? ireprs expected)\n         (error! stx\n                 \"Invalid arguments to ~a; expects ~a but got ~a\"\n                 fname\n                 fname\n                 (application->string fname expected)\n                 (application->string fname ireprs)))\n       repr]\n      [#`(array #,first-elem #,rest-elems ...)\n       (define first-type (loop first-elem prop-dict ctx))\n       (for ([elem (in-list rest-elems)])\n         (define t (loop elem prop-dict ctx))\n         (unless (equal? t first-type)\n           (error! stx\n                   \"Array elements have mismatched types: ~a vs ~a\"\n                   (repr-description first-type)\n                   (repr-description t))))\n       (array-of first-type (list (+ 1 (length rest-elems))))]\n      [#`(ref #,arr #,idx)\n       (define arr-type (loop arr prop-dict ctx))\n       (define raw (syntax-e idx))\n       (unless (integer? raw)\n         (error! idx \"Array index must be a literal integer, got ~a\" idx))\n       (match arr-type\n         [(? array-representation?)\n          (define len (array-representation-len arr-type))\n          (define elem (array-representation-elem arr-type))\n          (when (and (integer? raw) (or (< raw 0) (>= raw len)))\n            (error! idx \"Array index ~a out of bounds for length ~a\" raw len))\n          elem]\n         [_\n          (error! stx \"ref expects an array, got ~a\" (repr-description arr-type))\n          (get-representation (dict-ref prop-dict ':precision))])]\n      [#`(cast #,arg)\n       (define irepr (loop arg prop-dict ctx))\n       (define repr (get-representation (dict-ref prop-dict ':precision)))\n       (cond\n         [(equal? irepr repr) repr]\n         [else\n          (match (get-fpcore-impl 'cast prop-dict (list irepr))\n            [#f ; no implementation found\n             (error! stx\n                     \"No implementation of `~a` in platform for context `~a`\"\n                     (application->string 'cast (list irepr))\n                     prop-dict)\n             (get-representation (dict-ref prop-dict ':precision))]\n            [impl (impl-info impl 'otype)])])]\n      [#`(,(? symbol? op) #,args ...)\n       (define ireprs (map (lambda (arg) (loop arg prop-dict ctx)) args))\n       (match (get-fpcore-impl op prop-dict ireprs)\n         [#f ; no implementation found\n          (error! stx\n                  \"No implementation of `~a` in platform for context `~a`\"\n                  (application->string op ireprs)\n                  prop-dict)\n          (get-representation (dict-ref prop-dict ':precision))]\n         [impl (impl-info impl 'otype)])])))\n(module+ test\n  (require rackunit)\n  (require \"platform.rkt\"\n           \"../syntax/load-platform.rkt\")\n  (activate-platform! (*platform-name*))\n\n  ;; Dummy representation registration\n  (check-false (hash-has-key? (platform-representations (*active-platform*)) 'dummy))\n  (define pf\n    (struct-copy $platform\n                 (*active-platform*)\n                 [representations (hash-copy (platform-representations (*active-platform*)))]\n                 [implementations (hash-copy (platform-implementations (*active-platform*)))]\n                 [representation-costs\n                  (hash-copy (platform-representation-costs (*active-platform*)))]))\n  (parameterize ([*active-platform* pf])\n    (define dummy-repr\n      (make-representation #:name 'dummy\n                           #:bf->repr identity\n                           #:repr->bf identity\n                           #:ordinal->repr identity\n                           #:repr->ordinal identity\n                           #:total-bits 0\n                           #:special-value? (const #f)))\n    (hash-set! (platform-representations pf) 'dummy dummy-repr)\n    (hash-set! (platform-representation-costs pf) 'dummy 1)\n    (check-true (hash-has-key? (platform-representations pf) 'dummy))\n\n    (define dummy (get-representation 'dummy))\n    (check-equal? (representation-name dummy) 'dummy)\n    (check-equal? (get-representation 'dummy) dummy)\n\n    ;; Context operations\n    (define <b64> (get-representation 'binary64))\n    (define <bool> (get-representation 'bool))\n\n    (define ctx (context '() <b64> '()))\n    (define ctx1 (context-extend ctx 'x <b64>))\n    (check-equal? (context-vars ctx1) '(x))\n    (check-equal? (context-lookup ctx1 'x) <b64>)\n\n    (define ctx2 (context-extend ctx1 'y <bool>))\n    (check-equal? (context-vars ctx2) '(y x))\n    (check-equal? (context-lookup ctx2 'y) <bool>)\n    (check-equal? (context-lookup ctx2 'x) <b64>)\n\n    (define (fail! stx msg . args)\n      (error (apply format msg args) stx))\n\n    (define (check-types env-type rtype expr #:env [env '()])\n      (define ctx (context (map car env) env-type (map cdr env)))\n      (define repr (expression->type expr (repr->prop env-type) ctx fail!))\n      (cond\n        [(and (representation? repr) (representation? rtype))\n         (check-equal? (representation-name repr) (representation-name rtype))]\n        [else (check-equal? repr rtype)]))\n\n    (define (check-fails type expr #:env [env '()])\n      (define fail? #f)\n      (define ctx (context (map car env) type (map cdr env)))\n      (expression->type expr (repr->prop type) ctx (lambda _ (set! fail? #t)))\n      (check-true fail?))\n\n    (check-types <b64> <b64> #'4)\n    (check-types <b64> <b64> #'x #:env `((x . ,<b64>)))\n    (check-types <b64> <b64> #'(acos x) #:env `((x . ,<b64>)))\n    (check-fails <b64> #'(acos x) #:env `((x . ,<bool>)))\n    (check-types <b64> <bool> #'(and a b) #:env `((a . ,<bool>) (b . ,<bool>)))\n    (check-types <b64> <b64> #'(if (== a 1) 1 0) #:env `((a . ,<b64>)))\n    (check-fails <b64> #'(if (== a 1) 1 0) #:env `((a . ,<bool>)))\n    (check-types <b64> <bool> #'(let ([a 1]) TRUE))\n    (check-fails <b64> #'(if (== a 1) 1 TRUE) #:env `((a . ,<b64>)))\n    (check-types <b64> <b64> #'(let ([a 1]) a) #:env `((a . ,<bool>)))\n\n    ;; Array-aware typing\n    (define vec-type (array-of <b64> '(2)))\n    (define vec3-type (array-of <b64> '(3)))\n    (check-types <b64> vec-type #'(array 1 2))\n    (check-types <b64> vec3-type #'(array 1 2 3))\n    (check-fails <b64> #'(array (array 1) (array 1 2)))\n    (check-types <b64> <b64> #'(ref (array 5 6) 0))\n    (check-types <b64> <b64> #'(ref A 2) #:env `((A . ,vec3-type)))\n    (check-fails <b64> #'(ref A 3) #:env `((A . ,vec3-type)))\n    (check-fails <b64> #'(ref x 0) #:env `((x . ,<b64>))))\n\n  (check-exn exn:fail?\n             (lambda ()\n               (assert-program-typed! #'(FPCore () :precision (array binary64 2) (array 1.0 2.0)))))\n  (check-not-exn (lambda ()\n                   (assert-program-typed! #'(FPCore () :precision binary64 (array 1.0 2.0)))))\n  (check-not-exn (lambda () (assert-program-typed! #'(FPCore ((v 3)) :precision binary64 (ref v 2)))))\n  (check-not-exn (lambda ()\n                   (assert-program-typed! #'(FPCore ((a 3) (b 3))\n                                                    :precision\n                                                    binary64\n                                                    (+ (+ (ref a 0) (ref b 0))\n                                                       (+ (ref a 2) (ref b 2))))))))\n"
  },
  {
    "path": "src/syntax/types.rkt",
    "content": "#lang racket\n\n(require math/bigfloat\n         math/base\n         math/flonum\n         \"../utils/errors.rkt\")\n\n(provide (struct-out representation)\n         (struct-out array-representation)\n         repr->prop\n         array-representation-base\n         array-representation-shape\n         shift\n         unshift\n         <bool>\n         <binary32>\n         <binary64>\n         (struct-out context)\n         *context*\n         context-extend\n         context-lookup\n         make-representation\n         make-array-representation)\n\n;; Representations\n\n(struct representation\n        (name type bf->repr repr->bf ordinal->repr repr->ordinal total-bits special-value?)\n  #:transparent\n  #:methods gen:custom-write\n  [(define (write-proc repr port mode)\n     (fprintf port \"#<representation ~a>\" (representation-name repr)))])\n\n(struct array-representation representation (elem len) #:transparent)\n\n(define (array-representation-base repr)\n  (if (array-representation? repr)\n      (array-representation-base (array-representation-elem repr))\n      repr))\n\n(define (array-representation-shape repr)\n  (if (array-representation? repr)\n      (cons (array-representation-len repr)\n            (array-representation-shape (array-representation-elem repr)))\n      '()))\n\n;; Converts a representation into a rounding property\n(define (repr->prop repr)\n  (match repr\n    [(? array-representation?) (repr->prop (array-representation-elem repr))]\n    [(? representation?)\n     (match (representation-type repr)\n       ['bool '()]\n       ['real (list (cons ':precision (representation-name repr)))])]))\n\n(define (make-representation #:name name\n                             #:bf->repr bf->repr\n                             #:repr->bf repr->bf\n                             #:ordinal->repr ordinal->repr\n                             #:repr->ordinal repr->ordinal\n                             #:total-bits total-bits\n                             #:special-value? special-value?)\n  (representation name 'real bf->repr repr->bf ordinal->repr repr->ordinal total-bits special-value?))\n\n(define (make-array-representation #:elem elem-repr #:len len)\n  (unless (exact-positive-integer? len)\n    (raise-herbie-error \"Arrays require a positive length, got ~a\" len))\n  (define array-ty `(array ,(representation-type elem-repr) ,len))\n  (define name (string->symbol (format \"array~a-~a\" (representation-name elem-repr) len)))\n  ;; TODO: Array representations currently inherit scalar conversion slots.\n  ;; These should not be called for arrays; we'll clean up the hierarchy later.\n  (define total-bits (* len (representation-total-bits elem-repr)))\n  (array-representation name array-ty void void void void total-bits void elem-repr len))\n\n(module hairy racket/base\n  (require (only-in math/private/bigfloat/mpfr get-mpfr-fun _mpfr-pointer _rnd_t bf-rounding-mode))\n  (require ffi/unsafe)\n  (provide bigfloat->float32)\n  (define mpfr-get-flt (get-mpfr-fun 'mpfr_get_flt (_fun _mpfr-pointer _rnd_t -> _float)))\n  (define (bigfloat->float32 x)\n    (mpfr-get-flt x (bf-rounding-mode))))\n(require (submod \".\" hairy))\n\n(define (float32->bit-field x)\n  (integer-bytes->integer (real->floating-point-bytes x 4) #f #f))\n\n(define (float32->ordinal x)\n  (if (negative? x)\n      (- (float32->bit-field (- x)))\n      (float32->bit-field (abs x))))\n\n(define (bit-field->float32 x)\n  (floating-point-bytes->real (integer->integer-bytes x 4 #f #f) #f))\n\n(define (ordinal->float32 x)\n  (if (negative? x)\n      (- (bit-field->float32 (- x)))\n      (bit-field->float32 x)))\n\n(define (shift bits fn)\n  (define shift-val (expt 2 bits))\n  (λ (x) (fn (- x shift-val))))\n\n(define (unshift bits fn)\n  (define shift-val (expt 2 bits))\n  (λ (x) (+ (fn x) shift-val)))\n\n;; Does not use make-representation to define a repr of bool\n(define <bool>\n  (representation 'bool 'bool identity identity (curry = 0) (lambda (x) (if x 0 -1)) 1 (const #f)))\n\n(define <binary32>\n  (make-representation #:name 'binary32\n                       #:bf->repr bigfloat->float32\n                       #:repr->bf (lambda (x)\n                                    (parameterize ([bf-precision 24])\n                                      (bf x)))\n                       #:ordinal->repr ordinal->float32\n                       #:repr->ordinal float32->ordinal\n                       #:total-bits 32\n                       #:special-value? nan?))\n\n(define <binary64>\n  (make-representation #:name 'binary64\n                       #:bf->repr bigfloat->flonum\n                       #:repr->bf (lambda (x)\n                                    (parameterize ([bf-precision 53])\n                                      (bf x)))\n                       #:ordinal->repr ordinal->flonum\n                       #:repr->ordinal flonum->ordinal\n                       #:total-bits 64\n                       #:special-value? nan?))\n\n;; Contexts\n\n(struct context (vars repr var-reprs) #:transparent)\n\n;; Current context\n(define *context* (make-parameter #f))\n\n(define (context-extend ctx var repr)\n  (struct-copy context\n               ctx\n               [vars (cons var (context-vars ctx))]\n               [var-reprs (cons repr (context-var-reprs ctx))]))\n\n(define (context-lookup ctx var)\n  (dict-ref (map cons (context-vars ctx) (context-var-reprs ctx)) var))\n"
  },
  {
    "path": "src/utils/common.rkt",
    "content": "#lang racket\n\n(require math/base\n         \"../config.rkt\")\n\n(provide reap\n         drop-at\n         find-duplicates\n         partial-sums\n         get-seed\n         set-seed!\n         quasisyntax\n         sym-append\n         format-time\n         format-bits\n         prop-dict/c\n         props->dict\n         fpcore->string\n         (all-from-out \"../config.rkt\"))\n\n(module+ test\n  (require rackunit))\n\n;; Various syntactic forms of convenience used in Herbie\n\n(define-syntax-rule (reap [sows ...] body ...)\n  (let* ([sows (let ([store '()])\n                 (cons (λ () store)\n                       (match-lambda*\n                         [(list elt) (set! store (cons elt store))]\n                         [(list) store]\n                         [_ (error 'reap \"invalid sow\")])))] ...)\n    (let ([sows (cdr sows)] ...)\n      body ...)\n    (values (reverse ((car sows))) ...)))\n\n(define (drop-at ls index)\n  (define-values (front back) (split-at ls index))\n  (append front (rest back)))\n\n(define (partial-sums vec)\n  (define res (make-vector (vector-length vec)))\n  (for/fold ([cur-psum 0]) ([(el idx) (in-indexed (in-vector vec))])\n    (define new-psum (+ cur-psum el))\n    (vector-set! res idx new-psum)\n    new-psum)\n  res)\n\n(module+ test\n  (check-equal? (partial-sums #(1 4 6 3 8)) #(1 5 11 14 22)))\n\n(define (find-duplicates l)\n  (map car (filter (compose pair? rest) (group-by identity l))))\n\n;; Matching support for syntax objects.\n\n;; Begin the match with a #`\n;; Think of the #` as just like a ` match, same behavior\n;; In fact, matching x with #`pat should do the same\n;; as matching (syntax->datum x) with `pat\n;; Inside the #`, you can use #, to bind not a value but a syntax object.\n\n(define-match-expander quasisyntax\n  (λ (stx)\n    (syntax-case stx (unsyntax unquote)\n      [(_ (unsyntax pat)) #'pat]\n      [(_ (unquote pat)) #'(app syntax-e pat)]\n      [(_ (pats ...))\n       (let ([parts (for/list ([pat (syntax-e #'(pats ...))])\n                      (syntax-case pat (unsyntax unquote ...)\n                        [... pat]\n                        [(unsyntax a) #'a]\n                        [(unquote a) #'(app syntax-e a)]\n                        [a #'(quasisyntax a)]))])\n         #`(app syntax-e #,(datum->syntax stx (cons #'list parts))))]\n      [(_ a) #'(app syntax-e 'a)])))\n\n;; String formatting operations\n\n(define (format-time ms)\n  (cond\n    [(< ms 1000) (format \"~ams\" (round ms))]\n    [(< ms 60000) (format \"~as\" (/ (round (/ ms 100.0)) 10))]\n    [(< ms 3600000) (format \"~amin\" (/ (round (/ ms 6000.0)) 10))]\n    [else (format \"~ahr\" (/ (round (/ ms 360000.0)) 10))]))\n\n(module+ test\n  (check-equal? (format-time 60000) \"1.0min\")\n  (check-equal? (format-time 3600000) \"1.0hr\")\n  (check-equal? (format-time 500) \"500ms\")\n  (check-equal? (format-time 2000) \"2.0s\")\n  (check-equal? (format-time 0) \"0ms\")\n  (check-equal? (format-time 1800000) \"30.0min\")\n  (check-equal? (format-time 7200000) \"2.0hr\"))\n\n(define (format-bits r #:unit [unit? #f])\n  (define unit (if unit? \"b\" \"\"))\n  (cond\n    [(not r) \"\"]\n    [else (format \"~a~a\" (/ (round (* r 10)) 10) unit)]))\n\n;; Symbol generation\n\n(define (sym-append . args)\n  (string->symbol (apply string-append (map ~a args))))\n\n;; FPCore properties\n\n(define prop-dict/c (listof (cons/c symbol? any/c)))\n\n;; Prop list to dict\n(define (props->dict props)\n  (let loop ([props props]\n             [dict '()])\n    (match props\n      [(list key val rest ...) (loop rest (dict-set dict key val))]\n      [(list key) (error 'props->dict \"unmatched key\" key)]\n      [(list) dict])))\n\n(define (fpcore->string core)\n  (define-values (ident args props expr)\n    (match core\n      [(list 'FPCore name (list args ...) props ... expr) (values name args props expr)]\n      [(list 'FPCore (list args ...) props ... expr) (values #f args props expr)]))\n  (define props* ; make sure each property (name, value) gets put on the same line\n    (for/list ([(prop name) (in-dict (props->dict props))])\n      (format \"~a ~a\" prop (pretty-format name (- 69 (string-length (~a prop))) #:mode 'write))))\n  (define top\n    (if ident\n        (format \"FPCore ~a ~a\" ident args)\n        (format \"FPCore ~a\" args)))\n  (format \"(~a\\n  ~a\\n  ~a)\" top (string-join props* \"\\n  \") (pretty-format expr 70 #:mode 'write)))\n"
  },
  {
    "path": "src/utils/dvector.rkt",
    "content": "#lang racket\n\n(provide make-dvector\n         dvector-add!\n         dvector-set!\n         dvector-ref\n         in-dvector\n         dvector-length\n         dvector-capacity\n         create-dvector\n         dvector->vector)\n\n(define starting-capacity 128)\n\n(struct dvector ([vec #:mutable] [length #:mutable] filling-value)\n  #:property prop:equal+hash\n  (list (λ (a b eq?) ; equal? override\n          (and (dvector? b) (eq? (dvector-vec a) (dvector-vec b))))\n        (λ (a hc) ; hash-code\n          (+ (hc (dvector-vec a)) (dvector-length a)))\n        (λ (a hc) ; secondary-hash-code\n          (+ (hc (dvector-vec a)) (* 7 (+ 1 (dvector-length a)))))))\n\n(define (dvector->vector dvec)\n  (vector-copy (dvector-vec dvec) 0 (dvector-length dvec)))\n\n(define (make-dvector [size starting-capacity] [v #f])\n  (define size*\n    (cond\n      [(> size starting-capacity)\n       (let loop ([size* (* starting-capacity 2)])\n         (if (< size size*)\n             size*\n             (loop (* size* 2))))]\n      [(zero? size)\n       starting-capacity] ;; zero capacity is not allowed as it is going to break dvector-extend!\n      [else size])) ;; if user has a specific capacity in mind - do not go beyond that\n  (dvector (make-vector size* v) 0 v))\n\n(define (create-dvector . args)\n  (define dvec (make-dvector))\n  (for ([arg args])\n    (dvector-add! dvec arg))\n  dvec)\n\n(define (dvector-capacity dvec)\n  (vector-length (dvector-vec dvec)))\n\n(define (dvector-extend! dvec)\n  (match-define (dvector vec _ filling-val) dvec)\n  (define cap (dvector-capacity dvec))\n  (define vec* (make-vector (* 2 cap) filling-val))\n  (vector-copy! vec* 0 vec)\n  (set-dvector-vec! dvec vec*))\n\n(define (dvector-add! dvec elem)\n  (match-define (dvector vec len _) dvec)\n  (cond\n    [(equal? len (dvector-capacity dvec))\n     (dvector-extend! dvec)\n     (dvector-add! dvec elem)]\n    [else\n     (vector-set! vec len elem)\n     (set-dvector-length! dvec (add1 len))\n     len]))\n\n(define (dvector-set! dvec idx elem)\n  (match-define (dvector vec len _) dvec)\n  (cond\n    [(>= idx (dvector-capacity dvec))\n     (dvector-extend! dvec)\n     (dvector-set! dvec idx elem)]\n    [else\n     (vector-set! vec idx elem)\n     (set-dvector-length! dvec (max len (add1 idx)))]))\n\n(define (dvector-ref dvec idx)\n  (vector-ref (dvector-vec dvec) idx))\n\n(define (in-dvector dvec [start 0] [end (dvector-length dvec)] [step 1])\n  (when (or (< (dvector-length dvec) (or end (dvector-length dvec))) (> start (dvector-length dvec)))\n    (error \"in-dvector is out of index\"))\n  (in-vector (dvector-vec dvec) start (or end (dvector-length dvec)) step))\n\n(module+ test\n  (require rackunit)\n\n  ;; Test: Create a new dvector\n  (define dv (make-dvector))\n\n  (define dv1 (make-dvector)) ; default\n  (check-equal? (dvector-length dv1) 0)\n  (check-equal? (dvector-capacity dv1) starting-capacity)\n  (check-equal? (vector-length (dvector-vec dv1)) starting-capacity)\n\n  (define dv2 (make-dvector starting-capacity 5))\n  (check-equal? (dvector-length dv2) 0)\n  (check-equal? (dvector-capacity dv2) starting-capacity)\n  (check-equal? (vector-length (dvector-vec dv2)) starting-capacity)\n  (check-equal? (vector-ref (dvector-vec dv2) 0) 5)\n\n  ;; Large input triggers dynamic size growth\n  (define dv3 (make-dvector 300))\n  (check-true (> (dvector-capacity dv3) 300))\n\n  ;; Custom equal? behavior: only same vector => equal\n  (define dv4 dv2) ; same instance\n  (define dv5 (make-dvector 10 5)) ; same content, different vector\n  (check-true (equal? dv2 dv4))\n\n  (check-equal? (dvector-length dv) 0)\n  (check-equal? (vector-length (dvector-vec dv)) 128)\n\n  ;; Test: Adding one element\n  (dvector-add! dv 'a)\n  (check-equal? (dvector-length dv) 1)\n  (check-equal? (dvector-ref dv 0) 'a)\n\n  ;; Test: Adding multiple elements within capacity\n  (for ([i (in-range 1 128)])\n    (dvector-add! dv i))\n\n  (check-equal? (dvector-length dv) 128)\n  (check-equal? (dvector-ref dv 1) 1)\n  (check-equal? (dvector-ref dv 127) 127)\n\n  ;; Test: Adding element to trigger extension\n  (dvector-add! dv 'extended)\n  (check-equal? (dvector-length dv) 129)\n  (check-equal? (vector-length (dvector-vec dv)) 256) ; Should have doubled\n\n  (dvector-add! dv 'new)\n  (check-equal? (dvector-length dv) 130)\n  (check-equal? (dvector-ref dv 129) 'new)\n\n  ;; Test: in-dvector (implicit end)\n  (define values\n    (for/list ([x (in-dvector dv)])\n      x))\n  (check-equal? (length values) 130)\n  (check-equal? (first values) 'a)\n  (check-equal? (last values) 'new)\n\n  ;; Test: in-dvector with range and step\n  (define stepped\n    (for/list ([x (in-dvector dv 0 10 2)])\n      x))\n  (check-equal? stepped (list 'a 2 4 6 8))\n\n  ;; Test: Reference out of bounds\n  (check-exn exn:fail? (lambda () (dvector-ref dv 999)))\n\n  ;; Test: Length after many additions\n  (for ([i (in-range 200)])\n    (dvector-add! dv i))\n  (check-equal? (dvector-length dv) 330)\n  (check-equal? (vector-length (dvector-vec dv)) 512)) ; Should have extended again\n"
  },
  {
    "path": "src/utils/errors.rkt",
    "content": "#lang racket\n(require \"../config.rkt\")\n(provide raise-herbie-error\n         raise-herbie-syntax-error\n         raise-herbie-sampling-error\n         raise-herbie-missing-error\n         exception->datum\n         herbie-error->string\n         (struct-out exn:fail:user:herbie)\n         (struct-out exn:fail:user:herbie:sampling)\n         (struct-out exn:fail:user:herbie:missing)\n         warn\n         warning-log)\n\n(struct exn:fail:user:herbie exn:fail:user (url) #:extra-constructor-name make-exn:fail:user:herbie)\n\n(struct exn:fail:user:herbie:syntax exn:fail:user:herbie (locations)\n  #:extra-constructor-name make-exn:fail:user:herbie:syntax)\n\n(struct exn:fail:user:herbie:sampling exn:fail:user:herbie ()\n  #:extra-constructor-name make-exn:fail:user:herbie:sampling)\n\n(struct exn:fail:user:herbie:missing exn:fail:user:herbie ()\n  #:extra-constructor-name make-exn:fail:user:herbie:missing)\n\n(define (raise-herbie-error message #:url [url #f] . args)\n  (raise (make-exn:fail:user:herbie (apply format message args) (current-continuation-marks) url)))\n\n(define (raise-herbie-syntax-error message\n                                   #:url [url \"faq.html#invalid-syntax\"]\n                                   #:locations [locations '()]\n                                   . args)\n  (raise (make-exn:fail:user:herbie:syntax (apply format message args)\n                                           (current-continuation-marks)\n                                           url\n                                           locations)))\n\n(define (raise-herbie-sampling-error message #:url [url #f] . args)\n  (raise\n   (make-exn:fail:user:herbie:sampling (apply format message args) (current-continuation-marks) url)))\n\n(define (raise-herbie-missing-error message #:url [url #f] . args)\n  (raise\n   (make-exn:fail:user:herbie:missing (apply format message args) (current-continuation-marks) url)))\n\n(define (herbie-error-url exn)\n  (format \"https://herbie.uwplse.org/doc/~a/~a\" *herbie-version* (exn:fail:user:herbie-url exn)))\n\n(define (syntax->error-format-string stx)\n  (define file\n    (cond\n      [(path? (syntax-source stx))\n       (define-values (base name dir?) (split-path (syntax-source stx)))\n       (path->string name)]\n      [else (syntax-source stx)]))\n  (format \"~a:~a:~a: ~~a\"\n          file\n          (or (syntax-line stx) \"\")\n          (or (syntax-column stx) (syntax-position stx))))\n\n(define (traceback->datum exn)\n  (define ctx (continuation-mark-set->context (exn-continuation-marks exn)))\n  (for/list ([(name loc) (in-dict ctx)])\n    (define name* (or name \"(unnamed)\"))\n    (match loc\n      [(srcloc file line col _ _) (list name* file line col)]\n      [#f (cons name* #f)])))\n\n(define (syntax-locations->datum exn)\n  (for/list ([(stx msg) (in-dict (exn:fail:user:herbie:syntax-locations exn))])\n    (list msg (syntax-source stx) (syntax-line stx) (syntax-column stx) (syntax-position stx))))\n\n(define (exception->datum exn)\n  (match exn\n    [(? exn:fail:user:herbie:missing?)\n     (list 'exn 'missing (exn-message exn) (herbie-error-url exn) #f (traceback->datum exn))]\n    [(? exn:fail:user:herbie:sampling?)\n     (list 'exn 'sampling (exn-message exn) (herbie-error-url exn) #f (traceback->datum exn))]\n    [(? exn:fail:user:herbie:syntax?)\n     (list 'exn\n           'syntax\n           (exn-message exn)\n           (herbie-error-url exn)\n           (syntax-locations->datum exn)\n           (traceback->datum exn))]\n    [(? exn:fail:user:herbie?)\n     (list 'exn 'herbie (exn-message exn) (herbie-error-url exn) '() (traceback->datum exn))]\n    [(? exn?) (list 'exn #f (exn-message exn) #f '() (traceback->datum exn))]))\n\n(define (herbie-error->string err)\n  (call-with-output-string\n   (λ (p)\n     (match err\n       [(exn:fail:user:herbie:syntax message marks url locations)\n        (fprintf p \"~a\\n\" message)\n        (for ([(stx message) (in-dict locations)])\n          (fprintf p \"  ~a\\n\" (format (syntax->error-format-string stx) message)))\n        (when url\n          (fprintf p \"See <https://herbie.uwplse.org/doc/~a/~a> for more.\\n\" *herbie-version* url))]\n       [(exn:fail:user:herbie message marks url)\n        (fprintf p \"~a\\n\" message)\n        (when url\n          (fprintf p\n                   \"See <https://herbie.uwplse.org/doc/~a/~a> for more.\\n\"\n                   *herbie-version*\n                   url))]))))\n\n(define old-error-display-handler (error-display-handler))\n(error-display-handler\n (λ (message err)\n   (cond\n     [(exn:fail:user:herbie? err) (display (herbie-error->string err) (current-error-port))]\n     [(exn:fail:read? err)\n      (printf \"Invalid syntax\\n  ~a\\nSee <https://herbie.uwplse.org/doc/~a/input.html> for more.\\n\"\n              (exn-message err)\n              *herbie-version*)]\n     [else (old-error-display-handler message err)])))\n\n(define/reset warnings (mutable-set))\n(define/reset warning-log '())\n\n(define (warn type message #:url [url #f] #:extra [extra '()] . args)\n  (unless (set-member? (warnings) type)\n    (eprintf \"Warning: ~a\\n\" (apply format message args))\n    (for ([line extra])\n      (eprintf \"  ~a\\n\" line))\n    (define url* (and url (format \"https://herbie.uwplse.org/doc/~a/~a\" *herbie-version* url)))\n    (when url*\n      (eprintf \"See <~a> for more.\\n\" url*))\n    (define entry (list (~a type) (apply format message args) url* extra))\n    (set-add! (warnings) type)\n    (warning-log (cons entry (warning-log)))))\n"
  },
  {
    "path": "src/utils/multi-command-line.rkt",
    "content": "#lang racket\n(require (for-syntax syntax/parse))\n(provide multi-command-line)\n\n(define-syntax (multi-command-line stx)\n  (syntax-parse stx\n    [(_ #:program big-name\n        #:version version\n        args ...\n        #:subcommands [name:id help:str subargs ...]\n        ...\n        #:args else-subargs\n        body)\n     #`(let ([true-name big-name])\n         (command-line\n          #:program true-name\n          #:multi [(\"-v\" \"--version\") (\"Print the version and exit\") (printf \"~a\\n\" version) (exit)]\n          #:usage-help \"This command has subcommands:\"\n          #,@(for/list ([name (syntax->list #'(name ...))]\n                        [help (syntax->list #'(help ...))])\n               (datum->syntax name (format \"  ~a:\\t~a\" (syntax->datum name) (syntax->datum help))))\n          \"Learn more about a subcommand with <subcommand> --help\"\n          #:args cmdline-args\n          (match cmdline-args\n            [(cons (== (~a 'name)) rest)\n             (multi-command-line #:program (format \"~a ~a\" true-name 'name)\n                                 #:argv rest\n                                 args ...\n                                 subargs ...)] ...\n            [fallthrough (apply (λ else-subargs body) fallthrough)])))]\n    [(_ args ...) #'(command-line args ...)]))\n"
  },
  {
    "path": "src/utils/pareto.rkt",
    "content": "#lang racket\n\n(provide (struct-out pareto-point)\n         pareto-map\n         pareto-union\n         pareto-combine)\n\n(struct pareto-point (cost error data) #:prefab)\n\n(define (ppt->pt ppt)\n  (list (pareto-point-cost ppt) (pareto-point-error ppt)))\n\n(define (pt->ppt pt)\n  (pareto-point (first pt) (second pt) (list)))\n\n(define (pareto-shift ppt0 frontier)\n  (match-define (pareto-point cost0 err0 _) ppt0)\n  (for/list ([ppt (in-list frontier)])\n    (match-define (pareto-point cost err _) ppt)\n    (pareto-point (+ cost0 cost) (+ err0 err) (list))))\n\n(define (pareto-compare pt1 pt2)\n  (match-define (pareto-point cost1 err1 data1) pt1)\n  (match-define (pareto-point cost2 err2 data2) pt2)\n  (cond\n    [(and (= cost1 cost2) (= err1 err2)) '=]\n    [(and (<= cost1 cost2) (<= err1 err2)) '<]\n    [(and (>= cost1 cost2) (>= err1 err2)) '>]\n    [else '<>]))\n\n(define (pareto-map f curve)\n  (for/list ([ppt (in-list curve)])\n    (struct-copy pareto-point ppt [data (f (pareto-point-data ppt))])))\n\n;; Takes two lists of `pareto-point` structs that are Pareto-optimal\n;; and returns the Pareto-optimal subset of their union.\n;; The curves most be sorted using the same method.\n(define (pareto-union curve1 curve2 #:combine [combine (lambda (a b) (append a b))])\n  (let loop ([curve1 curve1]\n             [curve2 curve2])\n    ; The curve is sorted so that highest accuracy is first\n    (match* (curve1 curve2)\n      [('() _) curve2]\n      [(_ '()) curve1]\n      [((cons ppt1 rest1) (cons ppt2 rest2))\n       (match (pareto-compare ppt1 ppt2)\n         ['< (loop curve1 rest2)]\n         ['> (loop rest1 curve2)]\n         ['=\n          (define joint-data (combine (pareto-point-data ppt1) (pareto-point-data ppt2)))\n          (define joint (struct-copy pareto-point ppt1 [data joint-data]))\n          (cons joint (loop rest1 rest2))]\n         ['<>\n          (if (< (pareto-point-error ppt1) (pareto-point-error ppt2))\n              (cons ppt1 (loop rest1 curve2))\n              (cons ppt2 (loop curve1 rest2)))])])))\n\n;; Takes a Pareto frontier and returns the subset of\n;; points that are convex.\n(define (pareto-convex ppts)\n  (let loop ([ppts* '()]\n             [ppts ppts])\n    (match ppts\n      [(list p0 p1 p2 pns ...)\n       (match-define (pareto-point p0x p0y _) p0)\n       (match-define (pareto-point p1x p1y _) p1)\n       (match-define (pareto-point p2x p2y _) p2)\n       ; if { p0, p1, p2 } are not convex:\n       ;   discard p1\n       ;   try backtracking one point (if not continue)\n       ; else move forward one point\n       (define m01 (/ (- p1y p0y) (- p1x p0x)))\n       (define m12 (/ (- p2y p1y) (- p2x p1x)))\n       (match* ((> m12 m01) (null? ppts*))\n         [(#t #t) (loop ppts* (append (list p0 p2) pns))]\n         [(#t #f) (loop (rest ppts*) (append (list (first ppts*) p0 p2) pns))]\n         [(#f _) (loop (cons p0 ppts*) (append (list p1 p2) pns))])]\n      [_ (append (reverse ppts*) ppts)])))\n\n;; Takes a list of `pareto-point` structs\n;; and returns the Pareto-optimal subset.\n(define (pareto-minimize ppts)\n  (define ppts* (sort ppts < #:key pareto-point-cost))\n  (for/fold ([minimized '()]) ([ppt (in-list ppts*)])\n    (pareto-union (list ppt) minimized)))\n\n;; Creates a synthetic frontier from multiple frontiers\n;; as described in the ARITH '21 paper.\n(define (pareto-combine frontiers #:convex? [convex? #f])\n  (define (finalize f)\n    (if convex?\n        (pareto-convex f)\n        f))\n  (define frontiers* (map (λ (f) (pareto-minimize (map pt->ppt f))) frontiers))\n  (for/fold ([combined (list)]\n             #:result (map ppt->pt combined))\n            ([frontier (in-list frontiers*)])\n    (if (null? combined)\n        (finalize frontier)\n        (for/fold ([combined* (list)]\n                   #:result (finalize combined*))\n                  ([ppt (in-list combined)])\n          (define ppts (pareto-minimize (pareto-shift ppt frontier)))\n          (pareto-union ppts combined*)))))\n\n(module+ test\n  (require rackunit)\n\n  (define (make-pareto pts)\n    (sort (for/list ([pt (in-list pts)])\n            (match-define (list cost err altns ...) pt)\n            (pareto-point cost err altns))\n          <\n          #:key pareto-point-error))\n\n  (define (from-pareto pts)\n    (sort (for/list ([ppt (in-list pts)])\n            (match-define (pareto-point cost err altns) ppt)\n            (list* cost err altns))\n          <\n          #:key first))\n\n  (define (pareto-add curve d c e)\n    (pareto-union (list (pareto-point c e (list d))) curve))\n\n  (check-equal? (from-pareto (make-pareto '((1 5 a) (2 3 b) (5 1 a b)))) '((1 5 a) (2 3 b) (5 1 a b)))\n  (check-equal? (from-pareto (pareto-add (make-pareto '()) 'a 1 5)) '((1 5 a)))\n  (check-equal? (from-pareto (pareto-add (make-pareto '((1 5 a) (5 1 b))) 'c 3 3))\n                '((1 5 a) (3 3 c) (5 1 b)))\n  (check-equal? (from-pareto (pareto-add (make-pareto '((1 5 a) (3 3 b))) 'c 5 1))\n                '((1 5 a) (3 3 b) (5 1 c)))\n  (check-equal? (from-pareto (pareto-add (make-pareto '((3 3 b) (5 1 c))) 'a 1 5))\n                '((1 5 a) (3 3 b) (5 1 c)))\n  (check-equal? (from-pareto (pareto-add (make-pareto '((1 5 a) (3 3 b) (5 1 c))) 'd 1 5))\n                '((1 5 d a) (3 3 b) (5 1 c)))\n  (check-equal? (from-pareto (pareto-add (make-pareto '((1 5 a) (3 3 b) (5 1 c))) 'd 3 3))\n                '((1 5 a) (3 3 d b) (5 1 c)))\n  (check-equal? (from-pareto (pareto-add (make-pareto '((1 5 a) (3 3 b) (5 1 c))) 'd 2 2))\n                '((1 5 a) (2 2 d) (5 1 c)))\n  (check-equal? (from-pareto (pareto-add (make-pareto '((1 1 a))) 'b 1 3)) '((1 1 a))))\n"
  },
  {
    "path": "src/utils/pretty-print.rkt",
    "content": "#lang racket\n\n(require math/bigfloat)\n(provide bigfloat-interval-shortest\n         bigfloat-pick-point)\n\n(define (bigfloat->normal-string x)\n  (cond\n    [(bfzero? x)\n     (match (bigfloat-signbit x)\n       [0 '+zero]\n       [1 '-zero])]\n    [(bfinfinite? x)\n     (match (bigfloat-signbit x)\n       [0 '+inf]\n       [1 '-inf])]\n    [(bfnan? x) 'nan]\n    [else\n     (define s (bigfloat->string x))\n     (define-values (sign s-abs)\n       (if (string-prefix? s \"-\")\n           (values '- (substring s 1))\n           (values '+ s)))\n     (define-values (mantissa e)\n       (match (string-split s-abs \"e\" #:trim? #f)\n         [(list m e) (values m (string->number e))]\n         [(list m) (values m 0)]))\n     (define-values (pre-dot post-dot e*)\n       (match (string-split mantissa \".\" #:trim? #f)\n         [(list pre)\n          #:when (= (string-length pre) 1)\n          (values pre \"0\" e)]\n         [(list pre) (values (substring pre 0 1) (substring pre 1) (- (string-length pre) 1))]\n         [(list \"0\" s)\n          (let loop ([idx 0]\n                     [e e])\n            (if (eq? (string-ref s idx) #\\0)\n                (loop (+ idx 1) (- e 1))\n                (values (substring s idx (+ idx 1)) (substring s (+ idx 1)) (- e 1))))]\n         [(list pre post)\n          (if (= (string-length pre) 1)\n              (values pre post e)\n              (values (substring pre 0 1)\n                      (string-append (substring pre 1) post)\n                      (+ (string-length pre) -1 e)))]))\n     (list sign (string->number pre-dot) post-dot e*)]))\n\n(module+ test\n  (require rackunit)\n\n  (check-equal? (bigfloat->normal-string (bf -1e-100))\n                '(- 1 \"000000000000000019991899802602883619648\" -100))\n  (check-equal? (bigfloat->normal-string (bf \"-1\")) '(- 1 \"0\" 0))\n  (check-equal? (bigfloat->normal-string (bf \"-.1\"))\n                '(- 1 \"000000000000000000000000000000000000001\" -1))\n  (check-equal? (bigfloat->normal-string (bf \"-.000001\"))\n                '(- 1 \"000000000000000000000000000000000000001\" -6))\n  (check-equal? (bigfloat->normal-string (bf \"0\")) '+zero)\n  (check-equal? (bigfloat->normal-string (bf \"-1964363925810.15\"))\n                '(- 1 \"964363925810149999999999999999999999999\" 12))\n  (check-equal? (bigfloat->normal-string (bf \"-3.1014574914586375e-17\"))\n                '(- 3 \"101457491458637500000000000000000000006\" -17)))\n\n(define (digit-interval-shortest a b)\n  (define digits '(0 5 2 4 6 8 1 3 7 9))\n  (for/first ([d digits]\n              #:when (<= a d b))\n    d))\n\n(define (string-interval-shortest a b)\n  (let loop ([idx 0])\n    (cond\n      [(>= idx (string-length a)) a]\n      [(eq? (string-ref b idx) (string-ref a idx)) (loop (+ idx 1))]\n      [else\n       (format \"~a~a~a\"\n               (substring b 0 idx)\n               (let ([x-digit (string->number (substring a idx (+ idx 1)))]\n                     [y-digit (string->number (substring b idx (+ idx 1)))])\n                 (digit-interval-shortest (+ x-digit 1) y-digit))\n               (build-string (- (string-length b) idx 1) (const #\\0)))])))\n\n(define (string-pad s n c)\n  (define k (- n (string-length s)))\n  (if (positive? k)\n      (string-append (build-string k (const c)) s)\n      s))\n\n(module+ main\n  (require rackunit)\n  (check string=? (string-pad \"1\" 2 #\\0) \"01\"))\n\n(define (integer-interval-shortest a b)\n  (define sa (number->string a))\n  (define sb (number->string b))\n  (cond\n    [(<= a 0 b) 0]\n    [(negative? b) (- (integer-interval-shortest (- b) (- a)))]\n    [else\n     (define s1 (string-pad sa (max (string-length sa) (string-length sb)) #\\0))\n     (define s2 (string-pad sb (max (string-length sa) (string-length sb)) #\\0))\n     (string->number (string-interval-shortest s1 s2))]))\n\n(define/contract (bigfloat-interval-shortest x y)\n  (->i ([x bigfloat?] [y bigfloat?]) #:pre (x y) (or (bf<= x y) (bfnan? y)) [result bigfloat?])\n  (define x-parts (bigfloat->normal-string x))\n  (define y-parts (bigfloat->normal-string y))\n  (cond\n    [(bf= x y) y]\n    [(symbol? x-parts) x]\n    [(symbol? y-parts) y]\n    [(bfnegative? y) (bf- (bigfloat-interval-shortest (bf- y) (bf- x)))]\n    [(bfnegative? x) 0.bf]\n    [else\n     (match-define (list x-sign x-pre x-post x-e) x-parts)\n     (match-define (list y-sign y-pre y-post y-e) y-parts)\n     (cond\n       [(>= y-e (+ x-e 1)) (bf (format \"1.0e~a\" (integer-interval-shortest (+ x-e 1) y-e)))]\n       [(>= y-pre (+ x-pre 1))\n        (bf (format \"~a.0e~a\" (digit-interval-shortest (+ x-pre 1) y-pre) y-e))]\n       [else (bf (format \"~a.~ae~a\" y-pre (string-interval-shortest x-post y-post) y-e))])]))\n\n;; a little more rigorous than it sounds:\n;; finds the shortest number `x` near `p1` such that\n;; `x1` is in `[p1, p2]` and is no larger than\n;;  - if `p1` is negative, `p1 / 2`\n;;  - if `p1` is positive, `p1 * 2`\n(define/contract (bigfloat-pick-point left right)\n  (->i ([x bigfloat?] [y bigfloat?]) #:pre (x y) (or (bf<= x y) (bfnan? y)) [result bigfloat?])\n  (cond\n    [(and (bfnegative? left) (bfnegative? right)) (bf- (bigfloat-pick-point (bf- right) (bf- left)))]\n    [(and (bfpositive? left) (bfpositive? right))\n     (bigfloat-interval-shortest left (bfmin (bf* left 2.bf) right))]\n    [else (bigfloat-interval-shortest left right)]))\n\n(module+ test\n  (require math/base)\n\n  (define (sample-bigfloat)\n    (define exponent (random -1023 1023)) ; Pretend-double\n    (define significand (bf (random-bits (bf-precision)) (- (bf-precision))))\n    (define val (bfshift (bf+ 1.bf significand) exponent))\n    (if (= (random 0 2) 1)\n        (bf- val)\n        val))\n\n  (for ([i (in-range 10000)])\n    (define x (sample-bigfloat))\n    (define y (sample-bigfloat))\n    (define-values (x* y*)\n      (if (bf< x y)\n          (values x y)\n          (values y x)))\n    (define z (bigfloat-interval-shortest x* y*))\n    (with-check-info (['x x*] ['z z] ['y y*]) (check bf<= x* z) (check bf<= z y*))))\n"
  },
  {
    "path": "src/utils/profile.rkt",
    "content": "#lang racket\n(require profile/sampler\n         profile/analyzer\n         setup/dirs)\n(provide profile-merge\n         profile->json\n         json->profile\n         profile-thunk)\n\n;; One annoyance with profiling in Racket is that if function f calls\n;; (map g ...), we'll get profile edges (f, map) and (map, g). So if\n;; you want to know what \"f\" spends its time doing, you won't know for\n;; sure (imagine it calls map more than once), and if you want to know\n;; what \"g\" is called by, good luck.\n;;\n;; We thus apply some clever filtering to stacks: if the stack is (f\n;; map g), we'll create the edge (f, g), but if it's (f map) we'll\n;; still do the edge (f, map) to record the overhead of map.\n\n;; The specific test is whether or not it's part of the Racket\n;; standard library (called the \"collects\")\n(define collects-dir (let ([dir (find-collects-dir)]) (and dir (path->string dir))))\n\n(define (profile-focus? id src)\n  (define path (and src (srcloc-source src)))\n  (cond\n    [(not src) #t]\n    [(not collects-dir) #t]\n    [(path? path) (not (string-prefix? (path->string path) collects-dir))]\n    [(string? path) (not (string-prefix? path \"...\"))] ; abbreviated collects paths\n    [else #t]))\n\n;; Filter a stack for edge computation. Keep non-focused functions at the\n;; front (self position), then filter them out once we hit a focused function.\n(define (filter-stack focus? stack)\n  (let loop ([stack stack]\n             [filtering? #f])\n    (cond\n      [(null? stack) '()]\n      [else\n       (define entry (car stack))\n       (define focused? (focus? (car entry) (cdr entry)))\n       (cond\n         [focused? (cons entry (loop (cdr stack) #t))]\n         [filtering? (loop (cdr stack) #t)]\n         [else (cons entry (loop (cdr stack) #f))])])))\n\n;; Filter all stacks in samples using the focus predicate\n(define (filter-samples focus? cpu-time+samples)\n  (define cpu-time (car cpu-time+samples))\n  (define samples (cdr cpu-time+samples))\n  (cons cpu-time\n        (for/list ([sample (in-list samples)])\n          (define thread-id (car sample))\n          (define thread-time (cadr sample))\n          (define stack (cddr sample))\n          (list* thread-id thread-time (filter-stack focus? stack)))))\n\n(define (profile-thunk thunk renderer #:delay [delay-secs 0.05])\n  (define sampler (create-sampler (current-thread) delay-secs))\n  (define result\n    (with-handlers ([void (λ (e)\n                            (eprintf \"profiled thunk error: ~a\\n\"\n                                     (if (exn? e)\n                                         (exn-message e)\n                                         (format \"~e\" e))))])\n      (thunk)))\n  (sampler 'stop)\n  (define raw-samples (sampler 'get-snapshots))\n  (define filtered-samples (filter-samples profile-focus? raw-samples))\n  (renderer (analyze-samples filtered-samples))\n  result)\n\n(define (profile-merge . ps)\n  (define nodes (make-hash))\n  (define root-node (node #f #f '() 0 0 '() '()))\n  (hash-set! nodes (cons #f #f) root-node)\n  (for* ([p (in-list ps)]\n         [n (profile-nodes p)])\n    (hash-set! nodes (node-loc n) (node (node-id n) (node-src n) '() 0 0 '() '())))\n  (for* ([p ps]\n         [node (profile-nodes p)])\n    (profile-add nodes node))\n  (for ([p ps])\n    (profile-add nodes (profile-*-node p)))\n  (hash-remove! nodes (cons #f #f))\n  (profile (apply + (map profile-total-time ps))\n           (apply + (map profile-cpu-time ps))\n           (apply + (map profile-sample-number ps))\n           (apply merge-thread-times (map profile-thread-times ps))\n           (hash-values nodes)\n           root-node))\n\n(define (translate table node)\n  (hash-ref table (node-loc node)))\n\n(define (profile-add table node)\n  (define node* (translate table node))\n  (set-node-thread-ids! node* (set-union (node-thread-ids node*) (node-thread-ids node)))\n  (set-node-total! node* (+ (node-total node*) (node-total node)))\n  (set-node-self! node* (+ (node-self node*) (node-self node)))\n  (for ([e (node-callers node)])\n    (define caller* (translate table (edge-caller e)))\n    (match (findf (λ (e2) (eq? (edge-caller e2) caller*)) (node-callers node*))\n      [#f\n       (define e* (struct-copy edge e [caller caller*] [callee node*]))\n       (set-node-callers! node* (cons e* (node-callers node*)))]\n      [e*\n       (set-edge-total! e* (+ (edge-total e) (edge-total e*)))\n       (set-edge-caller-time! e* (+ (edge-caller-time e) (edge-caller-time e*)))\n       (set-edge-callee-time! e* (+ (edge-callee-time e) (edge-callee-time e*)))]))\n  (for ([e (node-callees node)])\n    (define callee* (translate table (edge-callee e)))\n    (match (findf (λ (e2) (eq? (edge-callee e2) callee*)) (node-callees node*))\n      [#f\n       (define e* (struct-copy edge e [callee callee*] [caller node*]))\n       (set-node-callees! node* (cons e* (node-callees node*)))]\n      [e*\n       (set-edge-total! e* (+ (edge-total e) (edge-total e*)))\n       (set-edge-caller-time! e* (+ (edge-caller-time e) (edge-caller-time e*)))\n       (set-edge-callee-time! e* (+ (edge-callee-time e) (edge-callee-time e*)))])))\n\n(define (node-loc node)\n  (cons (node-id node) (node-src node)))\n\n(define (merge-thread-times . ts)\n  (define h (make-hash))\n  (for* ([t (in-list ts)]\n         [(id time) (in-dict t)])\n    (hash-update! h id (curry + time) 0))\n  h)\n\n(define (profile->json p)\n  (define nodes (cons (profile-*-node p) (profile-nodes p)))\n  (define loc-hash\n    (for/hash ([node (in-list nodes)]\n               [n (in-naturals)])\n      (values (node-loc node) n)))\n  (define node-hash\n    (for/hash ([node (in-list nodes)])\n      (values (node-loc node) node)))\n\n  (hash 'total_time\n        (exact->inexact (profile-total-time p))\n        'cpu_time\n        (exact->inexact (profile-cpu-time p))\n        'sample_number\n        (profile-sample-number p)\n        'thread_times\n        (for/list ([(id time) (in-dict (profile-thread-times p))])\n          (hash 'id id 'time (exact->inexact time)))\n        'nodes\n        (for/list ([node nodes])\n          (hash 'id\n                (and (node-id node) (~a (node-id node)))\n                'src\n                (and (node-src node) (srcloc->string (node-src node)))\n                'thread_ids\n                (node-thread-ids node)\n                'total\n                (exact->inexact (node-total node))\n                'self\n                (exact->inexact (node-self node))\n                'callers\n                (map (curry edge->json loc-hash) (node-callers node))\n                'callees\n                (map (curry edge->json loc-hash) (node-callees node))))))\n\n(define (edge->json loc-hash edge)\n  (hash 'total\n        (exact->inexact (edge-total edge))\n        'caller\n        (hash-ref loc-hash (node-loc (edge-caller edge)))\n        'caller_time\n        (exact->inexact (edge-caller-time edge))\n        'callee\n        (hash-ref loc-hash (node-loc (edge-callee edge)))\n        'callee_time\n        (exact->inexact (edge-callee-time edge))))\n\n(define (string->srcloc s)\n  (match-define (list path-parts ... (app string->number line) (app string->number col))\n    (string-split s \":\" #:trim? #f))\n  (define path (string->path (string-join path-parts \":\")))\n  (srcloc path line (and line col) #f #f))\n\n(define (json->profile j)\n  (define nodes\n    (for/vector ([n (hash-ref j 'nodes)])\n      (node (hash-ref n 'id)\n            (and (hash-ref n 'src) (string->srcloc (hash-ref n 'src)))\n            (hash-ref n 'thread_ids)\n            (hash-ref n 'total)\n            (hash-ref n 'self)\n            '()\n            '())))\n  (for ([n (in-list (hash-ref j 'nodes))]\n        [n* (in-vector nodes)])\n    (set-node-callees! n*\n                       (for/list ([e (hash-ref n 'callees)])\n                         (edge (hash-ref e 'total)\n                               (vector-ref nodes (hash-ref e 'caller))\n                               (hash-ref e 'caller_time)\n                               (vector-ref nodes (hash-ref e 'callee))\n                               (hash-ref e 'callee_time))))\n    (set-node-callers! n*\n                       (for/list ([e (hash-ref n 'callers)])\n                         (edge (hash-ref e 'total)\n                               (vector-ref nodes (hash-ref e 'caller))\n                               (hash-ref e 'caller_time)\n                               (vector-ref nodes (hash-ref e 'callee))\n                               (hash-ref e 'callee_time)))))\n  (profile (hash-ref j 'total_time)\n           (hash-ref j 'cpu_time)\n           (hash-ref j 'sample_number)\n           (for/list ([t (hash-ref j 'thread_times)])\n             (cons (hash-ref t 'id) (hash-ref t 'time)))\n           (rest (vector->list nodes))\n           (vector-ref nodes 0)))\n\n(module+ main\n  (require profile/render-text\n           json)\n  (command-line #:args (file) (render (json->profile (call-with-input-file file read-json)) 'total)))\n"
  },
  {
    "path": "src/utils/timeline.rkt",
    "content": "#lang racket\n\n(require json\n         \"../config.rkt\"\n         racket/hash)\n\n(provide (rename-out [timeline-push! timeline-push!/unsafe] [timeline-start! timeline-start!/unsafe])\n         (contract-out (timeline-event! (symbol? . -> . void?))\n                       (timeline-push! (symbol? jsexpr? ... . -> . void?))\n                       (timeline-start! (symbol? jsexpr? ... . -> . (-> void?))))\n         timeline-load!\n         timeline-extract\n         timeline-merge\n         timeline-reattribute-gc\n         *timeline-disabled*)\n(module+ debug\n  (provide *timeline*))\n\n;; This is a box so we can get a reference outside the engine, and so\n;; access its value even in a timeout.\n;; Important: Use 'eq?' based hash tables, process may freeze otherwise\n(define/reset *timeline* (box '()) (lambda () (set-box! (*timeline*) '())))\n\n(define *timeline-active-key* #f)\n(define *timeline-active-value* #f)\n\n(define *timeline-disabled* (make-parameter true))\n\n(define always-compact '(mixsample outcomes))\n\n(define (timeline-event! type)\n  (when (and *timeline-active-key* (pair? (unbox (*timeline*))))\n    (hash-update! (car (unbox (*timeline*)))\n                  *timeline-active-key*\n                  (curry append *timeline-active-value*)\n                  '())\n    (set! *timeline-active-key* #f))\n\n  (unless (*timeline-disabled*)\n    (when (pair? (unbox (*timeline*)))\n      (for ([key (in-list always-compact)]\n            #:when (hash-has-key? (car (unbox (*timeline*))) key))\n        (timeline-compact! key)))\n    (define live-memory (current-memory-use #f))\n    (define alloc-memory (current-memory-use 'cumulative))\n    (define b\n      (make-hasheq (list (cons 'type (~a type))\n                         (cons 'time (current-inexact-milliseconds))\n                         (cons 'gc-time (current-gc-milliseconds))\n                         (list 'memory (list live-memory alloc-memory)))))\n    (set-box! (*timeline*) (cons b (unbox (*timeline*))))))\n\n(define (timeline-push! key . values)\n  (unless (*timeline-disabled*)\n    (define val\n      (if (null? (cdr values))\n          (car values)\n          values))\n    (cond\n      [(eq? *timeline-active-key* key)\n       (set! *timeline-active-value* (cons val *timeline-active-value*))]\n      [(not *timeline-active-key*)\n       (unless (pair? (unbox (*timeline*)))\n         (error 'timeline \"Cannot push '~a to an empty timeline.\" key))\n       (set! *timeline-active-key* key)\n       (set! *timeline-active-value* (list val))]\n      [else\n       (when *timeline-active-key*\n         (hash-update! (car (unbox (*timeline*)))\n                       *timeline-active-key*\n                       (curry append *timeline-active-value*)\n                       '()))\n       (set! *timeline-active-key* key)\n       (set! *timeline-active-value* (list val))])))\n\n(define *timeline-1st-timer* #f)\n(define *timeline-2nd-timer* #f)\n(define *timeline-timers* (mutable-set))\n\n(define (timeline-start! key . values)\n  (define tstart (current-inexact-milliseconds))\n  (cond\n    [(not *timeline-1st-timer*)\n     (define (end!)\n       (define tend (current-inexact-milliseconds))\n       (apply timeline-push! key (- tend tstart) values)\n       (set! *timeline-1st-timer* #f))\n     (set! *timeline-1st-timer* end!)\n     end!]\n    [(not *timeline-2nd-timer*)\n     (define (end!)\n       (define tend (current-inexact-milliseconds))\n       (apply timeline-push! key (- tend tstart) values)\n       (set! *timeline-2nd-timer* #f))\n     (set! *timeline-2nd-timer* end!)\n     end!]\n    [*timeline-1st-timer* ; Slow path, more than one timer at a time\n     (define (end!)\n       (define tend (current-inexact-milliseconds))\n       (apply timeline-push! key (- tend tstart) values)\n       (set-remove! *timeline-timers* end!))\n     (set-add! *timeline-timers* end!)\n     end!]))\n\n(define (timeline-load! value)\n  (*timeline* value))\n\n(define (diff-memory-records v1 v2)\n  (list (list (- (caar v1) (caar v2)) (- (cadar v1) (cadar v2)))))\n\n(define (timeline-extract)\n  (when *timeline-1st-timer*\n    (*timeline-1st-timer*))\n  (when *timeline-2nd-timer*\n    (*timeline-2nd-timer*))\n  (when *timeline-active-key*\n    (hash-update! (car (unbox (*timeline*)))\n                  *timeline-active-key*\n                  (curry append *timeline-active-value*)\n                  '())\n    (set! *timeline-active-key* #f))\n  (for ([end! (set->list *timeline-timers*)])\n    (end!))\n  (define end\n    (hasheq 'time\n            (current-inexact-milliseconds)\n            'gc-time\n            (current-gc-milliseconds)\n            'memory\n            (list (list (current-memory-use #f) (current-memory-use 'cumulative)))))\n  (timeline-reattribute-gc\n   (reverse (for/list ([evt (in-list (unbox (*timeline*)))]\n                       [next (in-list (cons end (unbox (*timeline*))))])\n              (define evt* (hash-copy evt))\n              (hash-update! evt* 'time (λ (v) (- (hash-ref next 'time) v)))\n              (hash-update! evt* 'gc-time (λ (v) (- (hash-ref next 'gc-time) v)))\n              (hash-update! evt* 'memory (λ (v) (diff-memory-records (hash-ref next 'memory) v)))\n              evt*))))\n\n(define timeline-types (make-hasheq))\n\n(define-syntax define-timeline\n  (syntax-rules ()\n    [(_ name [field] ...) (hash-set! timeline-types 'name append)]\n    [(_ name (field type) ...)\n     (hash-set! timeline-types 'name (procedure-rename (make-merger type ...) 'name))]\n    [(_ name #:custom fn) (hash-set! timeline-types 'name fn)]\n    [(_ name #:unmergable) (hash-set! timeline-types 'name #f)]))\n\n(define ((make-merger . fields) . tables)\n  (define rows (apply append tables))\n  (define groups (make-hash))\n  (for ([row rows])\n    (define-values (values key*) (partition cdr (map cons row fields)))\n    (define key (map car key*))\n    (if (hash-has-key? groups key)\n        (hash-update! groups\n                      key\n                      (λ (old)\n                        (for/list ([value2 old]\n                                   [(value1 fn) (in-dict values)])\n                          (fn value2 value1))))\n        (hash-set! groups key (map car values))))\n  (for/list ([(k v) (in-hash groups)])\n    (let loop ([fields fields]\n               [k k]\n               [v v])\n      (match* (fields k v)\n        [((cons #f f*) (cons k k*) v) (cons k (loop f* k* v))]\n        [((cons _ f*) k (cons v v*)) (cons v (loop f* k v*))]\n        [('() '() '()) '()]))))\n\n(define (merge-sampling-tables l1 l2)\n  (let loop ([l1 (sort l1 < #:key first)]\n             [l2 (sort l2 < #:key first)])\n    (match-define (list n1 t1) (car l1))\n    (match-define (list n2 t2) (car l2))\n    (define rec (list n1 (hash-union t1 t2 #:combine +)))\n    (match* ((cdr l1) (cdr l2))\n      [('() '()) (list rec)]\n      [('() l2*) (cons rec (loop (list (list (+ n1 1) t1)) l2*))]\n      [(l1* '()) (cons rec (loop l1* (list (list (+ n2 1) t2))))]\n      [(l1* l2*) (cons rec (loop l1* l2*))])))\n\n;; Generic & universal\n(define-timeline type #:custom (λ (a b) a))\n(define-timeline time #:custom +)\n\n;; Handled with separate GC phase\n(define-timeline gc-time #:custom +)\n(define-timeline memory [live +] [alloc +])\n(define-timeline allocations [phase false] [memory +])\n\n(define-timeline method [method])\n(define-timeline mixsample [time +] [function false] [precision false] [memory +])\n(define-timeline times [time +] [input false])\n(define-timeline series [time +] [var false] [transform false])\n(define-timeline compiler [before +] [after +])\n(define-timeline outcomes [time +] [prec false] [category false] [count +])\n(define-timeline accuracy [accuracy])\n(define-timeline oracle [oracle])\n(define-timeline baseline [baseline])\n(define-timeline count [input +] [output +])\n(define-timeline alts #:unmergable)\n(define-timeline batch #:unmergable)\n(define-timeline inputs #:unmergable)\n(define-timeline outputs #:unmergable)\n(define-timeline sampling #:custom merge-sampling-tables)\n(define-timeline bogosity #:custom (λ (x y) (list (hash-union (car x) (car y) #:combine +))))\n(define-timeline symmetry #:unmergable)\n(define-timeline bstep #:unmergable)\n(define-timeline kept #:unmergable)\n(define-timeline min-error #:unmergable)\n(define-timeline egraph #:unmergable)\n(define-timeline stop [reason false] [count +])\n(define-timeline branch #:unmergable)\n\n(define (timeline-merge . timelines)\n  ;; The timelines in this case are JSON objects, as above\n  (define types (make-hash))\n  (for* ([tl (in-list timelines)]\n         [event tl])\n    (define data (hash-ref! types (hash-ref event 'type) (make-hash)))\n    (for ([(k v) (in-dict event)]\n          #:when (hash-ref timeline-types k #f))\n      (if (hash-has-key? data k)\n          (hash-update! data k (λ (old) ((hash-ref timeline-types k) v old)))\n          (hash-set! data k v))))\n\n  (sort (timeline-reattribute-gc (hash-values types)) > #:key (curryr hash-ref 'time)))\n\n(define (timeline-compact! key)\n  (unless (*timeline-disabled*)\n    (define fn (hash-ref timeline-types key #f))\n    (when fn\n      (hash-update! (car (unbox (*timeline*))) key (curryr fn '()) '()))))\n\n(define (timeline-reattribute-gc timeline)\n  (define total-gc-time (for/sum ([phase (in-list timeline)]) (hash-ref phase 'gc-time 0)))\n  (define allocations-by-phase (make-hash))\n  (for ([phase (in-list timeline)])\n    (define type (hash-ref phase 'type \"unknown\"))\n    (define alloc (second (first (hash-ref phase 'memory '((0 0))))))\n    (hash-update! allocations-by-phase type (curry + alloc) 0))\n  (define allocation-table\n    (for/list ([(type alloc) (in-hash allocations-by-phase)])\n      (list type alloc)))\n  (define adjusted-phases\n    (for/list ([phase (in-list timeline)])\n      (define gc-time (hash-ref phase 'gc-time 0))\n      (define new-time (- (hash-ref phase 'time 0) gc-time))\n      (define phase* (hash-copy phase))\n      (hash-set! phase* 'time new-time)\n      (hash-remove! phase* 'gc-time)\n      (hash-remove! phase* 'memory)\n      phase*))\n  (define gc-phase\n    (make-hasheq\n     (list (cons 'type \"gc\") (cons 'time total-gc-time) (cons 'allocations allocation-table))))\n  (if (zero? total-gc-time)\n      adjusted-phases\n      (append adjusted-phases (list gc-phase))))\n"
  },
  {
    "path": "www/aec.html",
    "content": "<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie AEC Instructions</title>\n  <style>\n    html {font-family: sans-serif;}\n    body {min-width: 400px; max-width: 650px; margin: 3em auto;}\n    h1, h2, h3 {letter-spacing: .125em; font-weight: 600;}\n    h1 {font-size: 18px; line-height: 1; margin: 1.5em 0 .5em 0;}\n    h2 {font-size: 16px; line-height: 1.125; margin: 2.5em 0 .25em;}\n    h3 {font-size: 14px; line-height: 1.286; margin: 1.5em 0 .114em;}\n    .hide-text {background-color: #f1f1f1; cursor: pointer; padding: .5em; margin: 1em;}\n    p, li, dd, blockquote, figcaption {\n      font-size: 15px; line-height: 1.2; margin: .5em;\n      text-align: justify; -moz-hyphens: auto; -webkit-hyphens: auto; hyphens: auto;}\n    figcaption {font-size: 14px; line-height: 1.1;}\n    header h1 {margin: .5em 0 0 0; font-size: 16pt;}\n    header p {font-size: 14pt; margin: .5em 0 0 0;}\n    header img {position: relative; top: -1em; float: left; width: 133px; margin: 0 2em 0 0;}\n    header {margin: 2em 0 1em 0;}\n    header + * {clear: both;}\n    pre, dt {padding-left: 1.5em; font-size: 16px; font-family: monospace; background-color: #f1f1f1;}\n  </style>\n</head>\n<body>\n  <header>\n    <img alt=\"Herbie\" src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAABICAMAAAAKwMFNAAAAkFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDIYgjAAAAL3RSTlMACxwCEwcXX2IEM0JSaCciawFMb2U+DzkuVkda7vqCldL0iuXdyL97rZB2tKabodAnO0sAAAanSURBVGje7FXtdqIwEA0SUJAifgBiE0wIQTDovP/brdRSJ9vt6bZ1/+zx/tEzkNzJnXsJeeCBBx544H8DjcN0F02fQ88qe2HsOy75h0gUk5wDsPMElydC1U3bbbZ3JHcWDiaGET0uh+xaVBW9B+eSbqddU69QaQrAa6E1A5mi8o7DKzrvp6xenpw0gwtKVI04qJA62UrBDJVnALwrTw0DtkXlOMy+TjwRcAXvA+to4kXNE0zRywcA4RPi5AKwPhXT3eqrEngGBlmbqoiRY3IJZtjJ7a2j7QH27guVzG/VoAWAxiFfRAmgnkdnIRedL8N3puoQIAYDcjf88bVBCzINAAn5HK6lSjSqihEr0NX+3OiNRywG2T1F88KYGJUXNUC9+Dw389PBtTlq/93ka+grCbD5vWrW1cnUfB0QPJdhAqi/NPuTmVpmt+c0F2LXT5MS0fu1DJdPDIw1gi3jq4tgTmwknkDBQc6xhqx5mtgab1dB1gPAGqe4A3YR1XQFIqFCLUiwlnxKEOZcXJvLGfbc0baWN3hNVOFba0G6V4KSWABoan0s5KnYOvY8tMguK45S4NafoVqOKhWW1xOsPIMBql9lt06GRiMGPLIEVPG7kDUmGH5KXrroaKOijuY7HEg8O7cD4BIukOPaGX9hDCqA1kOy6lE3tNrsrwyVytHRRvvvsBJUDNbCHuflvKsB+DP6SJXDmw2wHJGc5Tvi5flIXpkPy7cXT+JUJlG+jYSKcCwsa60BTEaW8VE3dNytBGhdkq0agAr1mLDwleWmw27sJaC3biZ5cUlT2+g+XWLLYWtRDfV1rR/fpqlAhIlmuuV4KqkKiUvDWdXP/+YucygNcGEGCbGyJVKP2AjOwBVrI0oNTpQvymTfn8so/tZdV6qFlaW2bPqCEgs7CW0+7B7WKFFB1R93i29fsF3n4iyJmPjT1sys/ZxmvHU3LEJtuuQHmFBk1L0srt/lmUMwNmC8aws9StT9sKg774Nrf7wQ4iYkd8fyoP0PnpRs5AsX9ycOzjq1JUaJ+tV+tTanDgJRIAQIj0B45AEzZsYvqZnb/v+fd0Ftta3tbWr77Z4ZNSrh7Nk9uCv9hpC6JwQhRDBswKcg6elpwjdj+rPfKAINkinlGaWUeaWo5KT6tN0fHtb2xgo7b7EwsspbjmBTHZVXdY94/miAnw044/Lg3memJt2XaXtpAq5uJEEa0X8aL7/rgHInPjpy2LrQgF9Ca0hW1xOUoVGd2TTqX9gwXRD4FUCHwEh3J1tRY0G/UqZUEhqe4lqM+BXRUlSWCXf+OSUeIFaaZCtyELhINmjy5Od5takDbUb5nFnfIfp8LY5aA4PcjT/NW6sWux7E8EymKkQvdp9kBTrhe+xt/QNVRS0fghAh8NbKbhoASO1NYlCZku3BcTGz/j7WPjBFJxtFRrQpwY760K6kuhD7ugBmkGCODkPSksHc425sjX07CjQ60p0ppk4pKQtqatQZ3uKrY/f9QleDExDcQgMJQlrrVjd5Wd/DgvrN4ECM6L5X25TwfeagtgLb0dD44W0oyvCFoGoavsFrp+6j/aSLg1xD929rOrK5vjLBEwuEb9zVyVRjsVrHbwVFtL6ar4dpa5lHdswzSrvDvPe8uTaNq7MSMSJXv6tqXA6Pj/P6MrrXZqPkjrblWczzmiZzeDRXFQ0SkD+2BtW7k4rWeZEhTLvHlxSLuDHTqjDFB4eKcCznJb+/7IVYzJq8Bq9AdofT8YN2fm6ORG1sVVOoAH9gz3cN82WDkUKHAa5qh1/bUc38pba785eVR9uI8YLxflcD4RMtPUdeNoVueIrD0InUvbbFPOUvR87HHnRJnf+s2GETb0mR3HNQURXSLt+Ld+ZFcruyqcXxjeDK7wkAfF2EyK+aSXsKR24jjoEYg0E1TVpQW7a9GmkQNcpN/ZtQ1xIal/LcP7Hnx7Ws29h3ffAwEye2HHQpuhLHFllASDtq8go14Ip2hXiREZZAMTZDdma/zV3towlQHYn9filHKw0GAuLYCWWMvwL1tEmCVYWYIdQUp/UAUxba0W0iRhyCjiFQpdQKyuqcgj5SRC3GWR4qranNGLOV+DCEEGfPeoUvqSa+9C0dJxq3t6hgsztXBNUOgZZ2TWCL8xlHwSmlaZqktNbGGCeZI7WimIuCjHL9fUCjQQ2r8iiXGVVB133YEhCAHJ1mQgjugHb6vCX7koDWtecj7fS9w6zUfY+EG7qvrVeUa82pR+BOwIEqxSL+chcfJaWybcAPoKk78B/34y94b44pY3l6PgAAAABJRU5ErkJggg==\" />\n    <h1>Herbie (#61)</h1>\n    <p>AEC Evaluation</p>\n  </header>\n\n  <p>\n    These are instructions for evaluating Herbie,\n    the artifact for PLDI 2015 paper #61.\n    The main downloads for this artifact are the\n    <a href=\"paper.pdf\">Submitted paper</a> and the <a href=\"image.ova\">VirtualBox Image</a>,\n    along with these instructions.\n  </p>\n\n  <h2>Installing Herbie</h2>\n\n  <p>\n    There are three ways to try out Herbie.\n    The simplest is to use a VirtualBox image to run Herbie;\n    for users familiar with Docker,\n    Herbie provides a Docker image which may be more convenient;\n    and Herbie can also be built and run from source.\n  </p>\n\n  <h3>Virtual machine</h3>\n\n  <p>\n    To run Herbie in a virtual machine,\n    <a href=\"vm.vmx\">download</a> the virtual machine image,\n    start VirtualBox, and start the image in VirtualBox.\n    (VMs other than VirtualBox should also work; however, this has not been tested.)\n  </p>\n\n  <p>\n    The virtual machine will start into a graphical desktop\n    with two icons on the desktop:\n  </p>\n\n  <ul>\n    <li><code>Results</code>, which holds Herbie's output. It contains a recent run's results.</li>\n    <li><code>README.html</code>, which are a copy of these instructions.</li>\n  </ul>\n\n  <p>\n    In the virtual machine, Herbie can be run with the <code>herbie</code> command.\n    In case you want to install additional software in the VM,\n    the machine is a standard Ubuntu 14.04 Desktop installation,\n    with username <kbd>aec</kdb> and password <kbd>password</kbd>.\n  </p>\n\n  <div id=\"hidable\" data-hidetext=\"Instructions for using Docker or source are hidden; click here to show them.\">\n  <h3>Docker image</h3>\n\n  <p>\n    To run Herbie through Docker,\n    <a href=\"https://docs.docker.com/installation/\">install Docker</a>\n    and download the Herbie image to your computer with:\n  </p>\n\n  <pre>docker pull pldi15num61/herbie</pre>\n\n  <p>\n    Create a folder for Herbie to place its results into:\n  </p>\n\n  <pre>mkdir Results</pre>\n\n  <p>\n    You can now run Herbie with the incantation\n  </p>\n\n  <pre>docker run -it -v $PWD/Results/:/herbie/graphs pldi15num61/herbie</pre>\n\n  <p>\n    For convenience create an alias for this command in your shell.\n    In Bash, you would do this by executing:\n  </p>\n\n  <pre>alias herbie=docker run -it -v $PWD/Results/:/herbie/graphs pldi15num61/herbie</pre>\n\n  <h3>Installing from source</h3>\n\n  <p>\n    Herbie is developed on <a href=\"https://github.com/uwplse/herbie\">Github</a>\n    in <a href=\"https://racket-lang.org\">Racket</a>.\n    To run Herbie, you'll need to <a href=\"http://download.racket-lang.org/\">install Racket</a>.\n    Take care to use the official installer,\n    instead of using your distribution's package manager or a tool like OS X Homebrew.\n    These repositories often have out-of-date Racket version (Herbie requires 6.1)\n    or buggy versions of Racket's bundled mathematics libraries.\n    Note that Herbie's <code>git</code> history contains the names of Herbie's authors,\n    so this method may sacrifice double-blind evaluation.\n  </p>\n\n  <p>\n    Herbie's source can be downloaded with:\n  </p>\n\n  <pre>git clone https://github.com/uwplse/herbie.git herbie</pre>\n\n  <p>\n    Build Herbie by running:\n  </p>\n\n  <pre>cd herbie && raco make herbie/reports/make-report.rkt</pre>\n\n  <p>\n    Herbie can now be run with:\n  </p>\n\n  <pre>racket herbie/reports/make-report.rkt</pre>\n\n  <p>\n    For convenience create an alias for this command in your shell.\n    In Bash, you would do this by executing:\n  </p>\n\n  <pre>alias herbie=racket herbie/reports/make-report.rkt</pre>\n\n  <p>\n    Unlike for the virtual machine or the Docker image,\n    results will appear in <code>graphs/</code>\n    inside the Herbie source directory.\n  </p>\n  </div>\n  <script>\n    var h = document.getElementById(\"hidable\");\n    var t = document.createElement(\"div\");\n    t.className = \"hide-text\";\n    t.innerHTML = h.dataset.hidetext;\n    h.parentNode.replaceChild(t, h);\n    t.addEventListener(\"click\", function(){t.parentNode.replaceChild(h, t)});\n  </script>\n\n  <h2>Evaluating Herbie</h2>\n\n  <p>\n    Now that Herbie is installed and can be run,\n    there are several experiments you can perform\n    to reproduce the results in the paper.\n    These instructions assume the <code>herbie</code> alias\n    has been defined as in the instructions above.\n  </p>\n\n  <h3>Reproducing the main evaluation</h3>\n  <p>\n    To reproduce the results from the main evaluation, run:\n  </p>\n\n  <pre>herbie bench/hamming</pre>\n\n  <p>\n    This command will take a while to run\n    and demands at least two gigabytes of memory to complete.\n    (Runtime can be anywhere from five minutes to an hour,\n    depending on the number of CPUs available,\n    the available memory,\n    and the speed of the machine.\n    In a virtual machine, this may take longer yet).\n  </p>\n\n  <p>\n    Once complete, open <code>report.html</code>,\n    from the results folder, in a browser.\n    (The page has been mostly tested in Firefox,\n    but should work in all modern browsers.)\n    Note that each invocation of <code>herbie</code>\n    will overwrite this report page.\n    The top of the page should contain a graphic\n    similar to the double precision results in Figure 7 from the paper.\n  </p>\n\n  <p>\n    The results in the figure may not be exactly identical to that in the paper,\n    due to the following reasons:\n  </p>\n\n  <ul>\n    <li>\n      Herbie has improved somewhat since the submitted paper,\n      so may produce somewhat better results on a few tests.\n    </li>\n    <li>\n      The plot drawn on the results page is generated by sampling 8196 points,\n      instead of the 100 000 used in the paper.\n    </li>\n    <li>\n      The random seed used by Herbie is different on every evaluation,\n      which changes the sample points used by Herbie and thus its results.\n    </li>\n  </ul>\n\n  <p>\n    We do not expect any of these sources of error to lead to significant difference in the results.\n  </p>\n\n  <p>\n    The rest of the report contains various details of how Herbie achieved its results\n    and several metrics for evaluating them.\n    We did not discuss these metrics in the paper, but invite the artifact evaluator to explore them.\n    For each benchmark, the <code>Target bits</code> column represents\n    the average bits correct for Hamming's answer, when known.\n  </p>\n\n  <h3>Reproducing the extended test suite evaluation</h3>\n\n  <p>\n    To reproduce Herbie's results on the extended evaluation, execute:\n  </p>\n\n  <pre>herbie bench</pre>\n\n  <p>\n    This command may take several hours to execute,\n    and is expected to require as much as four gigabytes of memory.\n    The results will again be summarized in <code>report.html</code>.\n    Note that for the numeric results reported in the paper,\n    only some of the test cases were considered.\n    (Herbie's complete benchmarks contain several trivial or duplicate benchmarks,\n    since the same formula sometimes shows up in multiple places;\n    these were ignored in the reported results.)\n  </p>\n\n  <h2>More things to do with Herbie</h2>\n\n  <p>\n    Herbie supports several additional options,\n    which can be used to explore the effect of other parameters.\n    These options are summarized by <code>herbie --help</code>:\n  </p>\n\n  <dl>\n    <dt>-r <var>R</var></dt>\n    <dd>A random seed to use; a fixed seed is stored in the <code>SEED</code> environment variable. Omitting this argument asks Herbie to choose a new seed.</dd>\n    <dt>-n <var>N</var></dt>\n    <dd>Number of iterations of the main loop to use.</dd>\n    <dt>-s <var>N</var></dt>\n    <dd>Number of sample points to use during the internal search.</dd>\n    <dt>-f <var>category</var>:<var>flag</var></dt>\n    <dd>\n      Toggle flags that govern Herbie's search. This option can be repeated.\n      If both <code>sample:double</code> and <code>precision:double</code> are toggled,\n      Herbie will search for improvements in single-precision mode.\n      The other flags turn off various parts of Herbie's search, and are not recommended.\n    </dd>\n  </dl>\n\n  <h3>Writing new tests</h3>\n\n  <p>\n    New benchmarks can also be written and passed to Herbie.\n    To do this, create a new file in <code>bench/</code> named <code><var>something</var>.rkt</code>.\n    This file should be in a standard format; see <code>bench/basic.rkt</code> for an example.\n    Herbie should now be run so:\n  </p>\n\n  <pre>herbie bench/<var>something</var>.rkt</pre>\n\n  <p>\n    A report is produced as usual.\n  </p>\n  \n</body>\n"
  },
  {
    "path": "www/demo.js",
    "content": "CONSTANTS = [\"PI\", \"E\"]\nFUNCTIONS = {\n    \"+\": [2], \"-\": [1, 2], \"*\": [2], \"/\": [2], \"fabs\": [1],\n    \"sqrt\": [1], \"sqr\": [1], \"exp\": [1], \"log\": [1], \"pow\": [2],\n    \"sin\": [1], \"cos\": [1], \"tan\": [1], \"cot\": [1],\n    \"asin\": [1], \"acos\": [1], \"atan\": [1],\n    \"sinh\": [1], \"cosh\": [1], \"tanh\": [1]\n}\n\nSECRETFUNCTIONS = {\"^\": \"pow\", \"**\": \"pow\", \"abs\": \"fabs\"}\n\nfunction tree_errors(tree) /* tree -> list */ {\n    var messages = [];\n    var names = [];\n\n    bottom_up(tree, function(node, path, parent) {\n        switch(node.type) {\n        case \"ConstantNode\":\n            if (node.valueType !== \"number\")\n                messages.push(\"Constants that are \" + node.valueType + \"s not supported.\");\n            break;\n        case \"FunctionNode\":\n            node.name = SECRETFUNCTIONS[node.name] || node.name;\n            if (!FUNCTIONS[node.name]) {\n                messages.push(\"Function <code>\" + node.name + \"</code> unsupported.\");\n            } else if (FUNCTIONS[node.name].indexOf(node.args.length) === -1) {\n                messages.push(\"Function <code>\" + node.name + \"</code> expects \" +\n                              FUNCTIONS[node.name].join(\" or \") + \" arguments\");\n            }\n            break;\n        case \"OperatorNode\":\n            node.op = SECRETFUNCTIONS[node.op] || node.op;\n            if (!FUNCTIONS[node.op]) {\n                messages.push(\"Operator <code>\" + node.op + \"</code> unsupported.\");\n            } else if (FUNCTIONS[node.op].indexOf(node.args.length) === -1) {\n                messages.push(\"Operator <code>\" + node.op + \"</code> expects \" +\n                              FUNCTIONS[node.op].join(\" or \") + \" arguments\");\n            }\n            break;\n        case \"SymbolNode\":\n            if (CONSTANTS.indexOf(node.name) === -1)\n                names.push(node.name);\n            break;\n        default:\n            messages.push(\"Unsupported syntax; found unexpected <code>\" + node.type + \"</code>.\")\n            break;\n        }\n    });\n\n    if (names.length == 0) {\n        messages.push(\"No variables mentioned.\");\n    }\n\n    return messages;\n}\n\nfunction bottom_up(tree, cb) {\n    if (tree.args) {\n        tree.args = tree.args.map(function(node) {return bottom_up(node, cb)});\n        tree.res = cb(tree);\n    } else {\n        tree.res = cb(tree);\n    }\n    return tree;\n}\n\nfunction dump_tree(tree, txt) /* tree string -> string */ {\n    function extract(args) {return args.map(function(n) {return n.res});}\n    var names = [];\n    var body = bottom_up(tree, function(node) {\n        switch(node.type) {\n        case \"ConstantNode\":\n            return \"\" + node.value;\n        case \"FunctionNode\":\n            node.name = SECRETFUNCTIONS[node.name] || node.name;\n            return \"(\" + node.name + \" \" + extract(node.args).join(\" \") + \")\";\n        case \"OperatorNode\":\n            node.op = SECRETFUNCTIONS[node.op] || node.op;\n            return \"(\" + node.op + \" \" + extract(node.args).join(\" \") + \")\";\n        case \"SymbolNode\":\n            if (CONSTANTS.indexOf(node.name) === -1)\n                names.push(node.name);\n            return node.name;\n        default:\n            throw SyntaxError(\"Invalid tree!\");\n        }\n    });\n\n    var dnames = [];\n    for (var i = 0; i < names.length; i++) {\n        if (dnames.indexOf(names[i]) === -1) dnames.push(names[i]);\n    }\n\n    var name = txt.replace(\"\\\\\", \"\\\\\\\\\").replace(\"\\\"\", \"\\\\\\\"\");\n    return \"(FPCore (\" + dnames.join(\" \") + \") :name \\\"\" + name + \"\\\" \"  + body.res + \")\";\n}\n\nfunction onload() /* null -> null */ {\n    var form = document.getElementById(\"formula\");\n    var input = document.querySelector(\"#formula input\");\n    input.setAttribute(\"name\", \"formula-math\");\n    input.setAttribute(\"placeholder\", \"sqrt(x + 1) - sqrt(x)\");\n    input.removeAttribute(\"disabled\");\n    var hidden = document.createElement(\"input\");\n    hidden.type = \"hidden\";\n    hidden.setAttribute(\"name\", \"formula\");\n    form.appendChild(hidden);\n\n    document.getElementById(\"mathjs-instructions\").style.display = \"block\";\n    document.getElementById(\"lisp-instructions\").style.display = \"none\";\n\n    input.addEventListener(\"keyup\", function(evt) {\n        var txt = input.value;\n        var tree, errors = [];\n        try {\n            tree = math.parse(txt);\n            errors = tree_errors(tree);\n        } catch (e) {\n            errors = [\"\" + e];\n        }\n\n        if (txt && errors.length > 0) {\n            document.getElementById(\"errors\").innerHTML = \"<li>\" + errors.join(\"</li><li>\") + \"</li>\";\n        } else {\n            document.getElementById(\"errors\").innerHTML = \"\";\n        }\n    });\n\n    form.addEventListener(\"submit\", function(evt) {\n        var txt = input.value;\n        var tree, errors;\n        try {\n            tree = math.parse(txt);\n            errors = tree_errors(tree);\n        } catch (e) {\n            errors = [\"\" + e];\n        }\n\n        if (errors.length > 0) {\n            document.getElementById(\"errors\").innerHTML = \"<li>\" + errors.join(\"</li><li>\") + \"</li>\";\n            evt.preventDefault();\n            return false;\n        } else {\n            document.getElementById(\"errors\").innerHTML = \"\";\n        }\n\n        var lisp = dump_tree(tree, txt);\n        hidden.setAttribute(\"value\", lisp);\n\n        var url = document.getElementById(\"formula\").getAttribute(\"data-progress\");\n        if (url) {\n            input.disabled = \"true\";\n            ajax_submit(url, txt, lisp);\n            evt.preventDefault();\n            return false;\n        } else {\n            return true;\n        }\n    });\n}\n\nfunction clean_progress(str) {\n    var lines = str.split(\"\\n\");\n    var outlines = [];\n    for (var i = 0; i < lines.length; i++) {\n        var line = lines[i];\n        var words = line.split(\"  \");\n        var word0 = words.shift();\n        outlines.push(htmlescape((word0.substring(0, 6) === \"* * * \" ? \"* \" : \"\") + words.join(\"  \")));\n    }\n    return outlines.join(\"\\n\");\n}\n\nfunction htmlescape(str) {\n    return (\"\" + str).replace(\"&\", \"&amp;\").replace(\"<\", \"&lt;\").replace(\">\", \"&gt;\");\n}\n\nfunction get_progress(loc) {\n    var req2 = new XMLHttpRequest();\n    req2.open(\"GET\", loc);\n    req2.onreadystatechange = function() {\n        if (req2.readyState == 4) {\n            if (req2.status == 202) {\n                document.getElementById(\"progress\").innerHTML = clean_progress(req2.responseText);\n                setTimeout(function() {get_progress(loc)}, 100);\n            } else if (req2.status == 201) {\n                var loc2 = req2.getResponseHeader(\"Location\");\n                window.location.href = loc2;\n            } else {\n                document.getElementById(\"errors\").innerHTML = req2.responseText;\n            }\n        }\n    }\n    req2.send();\n}\n\nfunction ajax_submit(url, text, lisp) {\n    document.getElementById(\"progress\").style.display = \"block\";\n    var req = new XMLHttpRequest();\n    req.open(\"POST\", url);\n    req.setRequestHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\n    req.onreadystatechange = function() {\n        if (req.readyState == 4) {\n            if (req.status == 201) {\n                var jobcount = req.getResponseHeader(\"X-Job-Count\");\n                var jobelt = document.getElementById(\"num-jobs\")\n                if (jobelt) jobelt.innerHTML = jobcount - 1;\n                var loc = req.getResponseHeader(\"Location\");\n                get_progress(loc);\n            } else {\n                document.getElementById(\"errors\").innerHTML = req.responseText;\n            }\n        }\n    }\n    var content = \"formula=\" + encodeURIComponent(lisp) + \"&formula-math=\" + encodeURIComponent(text);\n    req.send(content);\n}\n\nwindow.addEventListener(\"load\", onload);\n"
  },
  {
    "path": "www/doc/0.9/docker.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie on Docker</title>\n  <base href=\"../../\" />\n  <link rel='stylesheet' type='text/css' href='main.css'>\n</head>\n<body>\n  <header>\n    <h1>Installing with Docker</h1>\n    <a href=\".\"><img class=\"logo\" src=\"logo-car.png\" /></a>\n  </header>\n\n  <p>\n    <a href=\".\">Herbie</a>'s is available\n    through <a href=\"https://www.docker.com/\">Docker</a>, which is a\n    sort of like an easily-scriptable virtual machine. This page\n    describes how to install\n    the <a href=\"https://hub.docker.com/uwplse/herbie\">official Docker\n    image</a> for Herbie.\n  </p>\n  \n  <p>\n    Herbie can also be <a href=\"doc/0.9/installing.html\">installed\n    normally</a>.\n  </p>\n  \n  <h2>Installing the Herbie image</h2>\n\n  <p>\n    First, <a href=\"https://docs.docker.com/installation/\">install\n    Docker</a>. Docker supports Windows, OS X, and Linux. Depending on\n    how you install Docker, you may need to prefix\n    all <code>docker</code> commands on this page\n    with <code>sudo</code> or run them as the root or administrative\n    user.\n  </p>\n  \n  <p>\n    With Docker installed, you should be able to download the Herbie image with:\n  </p>\n \n\n  <pre>docker pull uwplse/herbie</pre>\n  \n  <p>\n    You can now run Herbie:\n  </p>\n\n  <pre>docker run uwplse/herbie -it</pre>\n  \n  <p>\n    This will run Herbie, reading input from the standard input. To\n    read from a file, you will need to mount the file in the Docker\n    container. Do that with:\n  </p>\n  \n  <pre><strong>$</strong> docker run -it \\\n    -v <var>dir</var>:/herbie/bench \\\n    uwplse/herbie bench/<var>file</var></pre>\n\n  <p>\n    In this command, <var>file</var> is a file you want to run Herbie\n    on, located in <var>dir</var>.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/0.9/input.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Input Format</title>\n  <base href=\"../..\"/>\n  <link rel='stylesheet' type='text/css' href='main.css'>\n</head>\n<body>\n  <header>\n    <h1>The Input Format</h1>\n    <a href=\".\"><img class=\"logo\" src=\"logo-car.png\" /></a>\n  </header>\n\n  <p>\n    <a href=\".\">Herbie</a>'s input format is designed for\n    expressing mathematical functions, which Herbie can then search\n    for accurate implementations of. It also allows specifying the\n    distribution that Herbie draws inputs from when evaluating the\n    accuracy of an expression.\n  </p>\n  \n  <h2 id=\"sec1\">General format</h2>\n\n  <p>The general format of an input expression is:</p>\n\n  <pre>(herbie-test (<var>inputs ...</var>) \"<var>title</var>\" <var>expression</var>)</pre>\n\n  <p>\n    Each input is a variable, like <code>x</code>, or a variable and a\n    distribution, written <code>[x <var>distribution</var>]</code>.\n    The title is any text that describes the expression and the input\n    is the expression to improve the accuracy of.\n  </p>\n\n  <p>\n    The expression is written in prefix form, with every function call\n    parenthesized, as in Lisp. For example, the formula for the\n    hypotenuse of a triangle with legs <i>a</i> and <i>b</i> is\n  </p>\n\n  <pre>(herbie-test (a b) \"hypotenuse\" (sqrt (+ (sqr a) (sqr b))))</pre>\n  \n  <h2>Supported functions</h2>\n  \n  <p>\n    The full list of supported functions and is as follows:\n  </p>\n\n  <dl class=\"function-list\">\n    <dt><code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>, <code>abs</code></dt>\n    <dd>The usual arithmetic functions<br/><code>-</code> is both negation and subtraction</dd>\n    <dt><code>sqr</code>, <code>sqrt</code></dt>\n    <dd>Squares and square roots</dd>\n    <dt><code>exp</code>, <code>log</code></dt>\n    <dd>Natural exponent and natural log</dd>\n    <dt><code>pow</code></dt>\n    <dd>Exponentiation; raising a value to a power</dd>\n    <dt><code>sin</code>, <code>cos</code>, <code>tan</code>, <code>cotan</code></dt>\n    <dd>The trigonometric functions</dd>\n    <dt><code>asin</code>, <code>acos</code>, <code>atan</code>, <code>atan2</code></dt>\n    <dd>The inverse trigonometric functions<br/><code>atan2</code> is the\n    two-argument inverse tangent</dd>\n    <dt><code>sinh</code>, <code>cosh</code>, <code>tanh</code></dt>\n    <dd>The hyperbolic trigonometric functions</dd>\n    <dt><code>expm1</code>, <code>log1p</code>, <code>hypot</code></dt>\n    <dd>Specialized numeric functions, as in <a href=\"http://pubs.opengroup.org/onlinepubs/7908799/xsh/math.h.html\">math.h</a></dd>\n  </dl>\n\n  <p>\n    Herbie allows the <code>+</code>, <code>-</code>, <code>*</code>,\n    and <code>/</code> functions to be passed more than two arguments,\n    and all of these functions are taken as left-associative.\n  </p>\n  \n  <p>\n    Herbie allows conditional expressions\n    using <code>if</code>: <code>(if cond a b)</code> evaluates the\n    conditional <code>cond</code> and returns either <code>a</code> if\n    it is true or <code>b</code> if it is not. Conditionals may use:\n  </p>\n  \n  <dl class=\"function-list\">\n    <dt><code>=</code>, <code>&lt;</code>, <code>&gt;</code>, <code>&lt;=</code>, <code>&gt;=</code></dt>\n    <dd>The usual comparison operators</dd>\n    <dt><code>and</code>, <code>or</code>, <code>not</code></dt>\n    <dd>The usual logical operators</dd>\n  </dl>\n  \n  <p>Intermediate variables can be defined using <code>let*</code>:</p>\n\n  <pre>(let* ([<var>variable</var> <var>value</var>] <var>...</var>) <var>body</var>)</pre>\n\n  <p>\n    Each variable is bound to the associated value, in order, with\n    later values allowed to reference prior values. All the defined\n    values are bound in the body. Note that Herbie treats these\n    intermediate values only as a notational convenience, and inlines\n    their values before improving the formula's accuracy.\n  </p>\n\n  <p>Herbie also supports the constants <code>PI</code> and <code>E</code>.</p>\n  \n  <h2>Distributions</h2>\n\n  <p>\n    Herbie allows each variable to <a href=\"#sec1\">specify the\n    distribution it is drawn from</a>. These distributions can be:\n  </p>\n  \n  <dl class=\"function-list\">\n    <dt><code>default</code></dt>\n    <dd>Interpret a random bit pattern as a float</dd>\n    <dt><code>(uniform <var>a</var> <var>b</var>)</code></dt>\n    <dd>A uniform real value between <var>a</var> and <var>b</var><br/>Both bounds must be numeric constants</dd>\n    <dt><code>int</code></dt>\n    <dd>Samples a random 32-bit signed integer</dd>\n    <dt><code><var>n</var></code></dt>\n    <dd>Always bind the variable to a constant</dd>\n  </dl>\n  \n  <p>Each of these distributions can also be modified:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>(&lt; <var>a</var> <var>dist</var> <var>b</var>)</code></dt>\n    <dd>Only values between <var>a</var> and <var>b</var> from <var>dist</var><br/>\n      Both bounds are optional numeric constants.</dd>\n  </dl>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/0.9/installing-herbgrind.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Installing HerbGrind</title>\n  <base href=\"../..\"/>\n  <link rel='stylesheet' type='text/css' href='main.css'>\n</head>\n<body>\n  <header>\n    <h1>Installing HerbGrind</h1>\n    <a href=\".\"><img class=\"logo\" src=\"logo-car.png\" /></a>\n  </header>\n\n  <p>\n    <a href=\".\">HerbGrind</a> depends\n    on <a href=\"http://valgrind.org\">Valgrind</a>, a binary\n    instrumentation and memory analysis framework. To install\n    HerbGrind, you must first install a C compiler and\n    GNU <code>awk</code> and <code>sed</code>.\n  </p>\n  \n  <p class=\"note\">\n    HerbGrind is <strong>α</strong> software. It is currently known to\n    work only on 64-bit GNU Linux platforms. Support for 32-bit\n    architectures, for OS X, for Clang, and for BSD core tools is\n    still in progress. Please <a href=\"https://github.com/uwplse/herbgrind/issues\">file a bug</a>\n    if HerbGrind does not work on your system.\n  </p>\n\n  <h2>Installing GNU AWK and Sed</h2>\n\n  <p>\n    HerbGrind currently supports 64-bit GNU Linux with GCC; OS X has\n    known bugs, and other configurations are untested. On Linux,\n    install GCC, AWK, and Sed using distro-provided packages; on\n    Debian-derivatives, use the <code>build-essentials</code> pacakge:\n  </p>\n  \n  <pre>sudo apt-get install build-essentials</pre>\n\n  <p>\n    On OS X, the same tools can be installed using <a href=\"https://brew.sh\">Homebrew</a>:\n  </p>\n\n  <pre>brew install gawk\nbrew install gnu-sed --with-default-names\nbrew install gcc</pre>\n  \n  <p>You will also want the XCode Command-line Tools on OSX, which you can install with:</p>\n\n  <pre>xcode-select --install</pre>\n  \n  <h2>Installing HerbGrind</h2>\n\n  <p>\n    Once the GNU tools are installed, download the HerbGrind source\n    <a href=\"https://github.com/uwplse/herbgrind\">from GitHub</a> with:\n  </p>\n\n  <pre>git clone https://github.com/uwplse/herbgrind</pre>\n\n  <p>\n    If you go to the <code>herbgrind</code> directory,\n    you should see a <code>README.md</code> file, a directory named <code>herbgrind</code>,\n    a directory named <code>bench/</code>, and a variety of other directories.\n    You should also see a <code>Makefile</code>. Make the binary with:\n  </p>\n\n  <pre>make compile</pre>\n\n  <p>\n    This command will take approximately ten minutes to run for the first time,\n      since it will download and build a custom Valgrind fork.\n    You may want to set the following Make variables;\n  </p>\n  \n  <dl>\n    <dt><code>TARGET_PLAT</code></dt>\n    <dd>The platform you want to run HerbGrind on; the default\n    is <code>amd64-darwin</code> on OS X and <code>amd64-linux</code>\n    otherwise.</dd>\n    <dt><code>ARCH_PRIM</code> and <code>ARCH_SEC</code></dt>\n    <dd>The primary and secondary architecture versions, which you\n    will want to set for some 64+32-bit configurations. The default\n    is <code>amd64</code> primary and no secondary.</dd>\n  </p>\n\n  <p>You can also configure without compiling using <code>make setup</code>.</p>\n\n  <p>\n    Once HerbGrind is installed and working correctly,\n    check out the <a href=\"doc/0.9/using-herbgrind.html\">usage instructions</a>.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/0.9/installing-herbie.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Installing Herbie</title>\n  <base href=\"../..\"/>\n  <link rel='stylesheet' type='text/css' href='main.css'>\n</head>\n<body>\n  <header>\n    <h1>Installing Herbie</h1>\n    <a href=\".\"><img class=\"logo\" src=\"logo-car.png\" /></a>\n  </header>\n\n  <p>\n    <a href=\".\">Herbie</a> depends\n    on <a href=\"https://racket-lang.org\">Racket</a>, a dynamic\n    language developed by Northeastern University. To install Herbie,\n    one must first install Racket. Once Racket is installed, Herbie\n    should run without problems.\n  </p>\n\n  <h2>Installing Racket</h2>\n\n  <p>\n    Herbie currently supports Linux and OS X. Windows has known bugs\n    we are working to resolve, due to the lack of a\n    full <code>math.h</code> library. Use\n    the <a href=\"http://download.racket-lang.org/racket-v6.5.html\">official\n    installer</a> to install Racket, or use distro-provided packages\n    provided they are version 6.4 or later of Racket (earlier versions\n    are not supported).\n  </p>\n\n  <p>\n    Test that Racket is installed correctly and has a correct version:\n  </p>\n\n  <pre><strong>$</strong> racket\nWelcome to Racket v6.4.\n> (exit)</pre>\n  \n  <h2>Installing Herbie</h2>\n\n  <p>\n    Once Racket is installed, download the Herbie source\n    <a href=\"https://github.com/uwplse/herbie\">from GitHub</a> with:\n  </p>\n\n  <pre>git clone https://github.com/uwplse/herbie</pre>\n\n  <p>\n    If you go to the <code>herbie</code> directory,\n    you should see a <code>README.md</code> file, a directory named <code>herbie</code>,\n    a directory named <code>bench/</code>, and a variety of other directories.\n    Do a trial run of Herbie to make sure everything is installed and working correctly:\n  </p>\n\n  <pre>racket src/reports/run.rkt bench/hamming/</pre>\n\n  <p>\n    This command will take approximately fifteen minutes to run;\n      it runs Herbie on problems from Richard Hamming's\n      <i>Numerical Methods for Scientists and Engineers</i>, Chapter 3.\n    After the command completes,\n      a directory named <code>graphs</code> should have appeared.\n    Open up the <code>report.html</code> file inside with your browser;\n      you should see a listing of the expressions Herbie was run on,\n      most of which should be green.\n    A score of 24/28 or greater suggests that everything is working correctly.\n  </p>\n\n  <p>\n    If any of the test results are crashes (there will be a “crashes” count at the top),\n      installation issues are to blame.\n    Check that your Racket installation is at least version 6.1\n      and that you installed Racket from the official installation packages.\n    If you're confident the installation is correct\n      please <a href=\"mailto:herbie@cs.washington.edu\">report the error</a> to the Herbie developers,\n      attaching an archive of the complete <code>graphs/</code> directory.\n  </p>\n\n  <p>If this all works correctly, you can make Herbie start up faster by byte-compiling it:</p>\n\n  <pre>raco make src/reports/run.rkt</pre>\n\n  <p>\n    Once Herbie is installed and working correctly,\n    check out the <a href=\"using-herbie.html\">tutorial</a>.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/0.9/options.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Command-line Options</title>\n  <base href=\"../..\"/>\n  <link rel='stylesheet' type='text/css' href='main.css'>\n</head>\n<body>\n  <header>\n    <h1>Command-line Options</h1>\n    <a href=\".\"><img class=\"logo\" src=\"logo-car.png\" /></a>\n  </header>\n\n  <p>\n    The <a href=\".\">Herbie</a> command takes several options\n    that influence its search procedure and the types of solutions it finds.\n    These options apply both to the report generator and the one-off command-line tool.\n  </p>\n\n  <h2>General Options</h2>\n\n  These options can be set on both the report generator and the one-off tool,\n  and influence the coarse properties of Herbie's search.\n\n  <dl>\n    <dt><code>-r</code> or <code>--seed</code></dt>\n    <dd>This sets the random seed, which changes the randomly-selected\n      points that Herbie evaluates candidate expressions on. The\n      format of the seed is that used by the\n      Racket <code>vector->pseudo-random-generator!</code> function;\n      in practice, just use a seed produced by an earlier run. This\n      option can be used to make Herbie's results reproducible or to\n      compare two different runs.</dd>\n\n    <dt><code>--fuel</code></dt>\n    <dd>The number of improvements Herbie attempts to make to the\n      program. The default, 2, suffices for most programs and helps\n      keep Herbie fast. If this is set very high, Herbie may run out\n      of things to do and terminate before the given number of\n      iterations, but in practice iterations beyond the first few\n      rarely lead to lower error. This option can be increased to 3 or\n      4 to check that there aren't further improvements that Herbie\n      could seek out.</dd>\n\n    <dt><code>--num-points</code></dt>\n    <dd>The number of randomly-selected points used to evaluate\n      candidate expressions. The default, 256, gives good behavior for\n      most programs. The more points sampled, the slower Herbie is.\n      This option can be increased to 512 or 1024 if Herbie gives very\n      inconsistent results between runs with different seeds.</dd>\n\n    <dt><code>--threads</code>, for the report generator only</dt>\n    <dd>Enables multi-threaded operation. By default, no threads are\n      used, a number can be passed to this option to use that many\n      threads, or <code>yes</code> can be passed to tell Herbie to use\n      all but one of the hardware threads. This option is not\n      supported on OS X or in Racket 6.2, and will warn if used in\n      those cases.</dd>\n  </dl>\n\n  <h2>Search Options</h2>\n\n  These options influence the fine properties of Herbie's search, most\n  importantly the types of transformations that Herbie uses to find\n  candidate programs. These options offer very fine-grained control\n  over Herbie's output, and are only recommended for advanced uses of\n  Herbie.\n\n  Each option can be toggled with the <code>-o</code>\n  or <code>--option</code> command-line flags. The recommended set of\n  options is the default set; turning a default-on option off\n  typically results in less-accurate results, while turning a\n  default-off option on typically results in more-complex and\n  more-surprising output expressions.\n\n  <dl>\n    <dt><code>precision:double</code></dt>\n    <dd>This option, on by default, runs Herbie in double-precision\n      mode. If turned off, Herbie runs in single-precision mode.</dd>\n\n    <dt><code>setup:simplify</code></dt>\n    <dd>This option, on by default, simplifies the expression before\n      passing it to Herbie. If turned off, Herbie will not simplify\n      input programs before improving them. You will want to turn off\n      this option if simplifying the program will create a lot of\n      error, say if the association of operations is cleverly\n      chosen.</dd>\n\n    <dt><code>generate:rr</code></dt>\n    <dd>This option, on by default, uses Herbie's recursive rewriting\n      algorithm to generate candidate programs. If turned off, Herbie\n      will use a non-recursive rewriting algorithm, which will\n      substantially limit the candidates Herbie finds. You will rarely\n      want to turn this option off.</dd>\n\n    <dt><code>generate:taylor</code></dt>\n    <dd>This option, on by default, uses series expansion to produce\n      new candidates during the main improvement loop. If turned off,\n      Herbie will not use series expansion in the main improvement loop.\n      You will want to turn this option off if you want to avoid\n      series-expansion-based rewrites, such as if you need to preserve\n      the equivalence of the input and output expressions as real-number\n      formulas.</dd>\n\n    <dt><code>generate:simplify</code></dt>\n    <dd>This option, on by default, simplifies candidates during the\n      main improvement loop. If turned off, candidates will not be\n      simplified, which typically results in much less accurate\n      expressions, since simplification is often necessary for\n      cancelling terms. You will rarely want to turn this option off.</dd>\n\n    <dt><code>reduce:regimes</code></dt>\n    <dd>This option, on by default, uses Herbie's regime inference\n      algorithm to branch between several program candidates. If\n      turned off, brances will be inferred and the output program will\n      be straight-line code (if the input was). You will want to turn\n      this option off if your programming environment makes branches\n      too expensive, such as in some cases of GPU programming.</dd>\n\n    <dt><code>reduce:taylor</code></dt>\n    <dd>This option, on by default, uses a final set of series\n      expansions after all improvements have been made. This sometimes\n      improves accuracy further. If turned off, this final series\n      expansion pass will not be done. You will want to turn this\n      option off if you want to avoid series-expansion-based rewrites,\n      such as if you need to preserve the equivalence of the input and\n      output expressions as real-number formulas.</dd>\n\n    <dt><code>reduce:simplify</code></dt>\n    <dd>This option, on by default, uses a final simplification pass\n      after all improvements have been made. This sometimes improves\n      accuracy further. If turned off, this final simplification pass\n      will not be done. You will rarely want to turn this option\n      off.</dd>\n\n    <dt><code>reduce:avg-error</code></dt>\n    <dd>This option, on by default, causes Herbie to output the\n      candidate with the best average error over the chosen inputs. If\n      turned off, Herbie will choose the candidate with the least\n      maximum error instead. This usually produces programs with worse\n      overall accuracy. You may want to turn this option off if\n      worst-case accuracy is more important to you than overall\n      accuracy.</dd>\n\n    <dt><code>rules:arithmetic</code></dt>\n    <dd>This option, on by default, allows Herbie to use basic\n      arithmetic facts during its search. If turned off, Herbie will\n      not be able to use those facts. You will rarely want to turn\n      this option off.</dd>\n\n    <dt><code>rules:polynomials</code></dt>\n    <dd>This option, on by default, allows Herbie to use facts\n      about polynomials during its search. If turned off, Herbie will\n      not be able to use those facts. You will rarely want to turn\n      this option off.</dd>\n\n    <dt><code>rules:fractions</code></dt>\n    <dd>This option, on by default, allows Herbie to use facts about\n      fractions during its search. If turned off, Herbie will not be\n      able to use those facts. You will rarely want to turn this\n      option off.</dd>\n\n    <dt><code>rules:exponents</code></dt>\n    <dd>This option, on by default, allows Herbie to use facts about\n      exponents during its search. If turned off, Herbie will not be\n      able to use those facts. You rarely want to turn this option off\n      if you do not want to use exponents or logarithms in the output\n      expressions, which might be the case when code runtime is more\n      important than accuracy.</dd>\n\n    <dt><code>rules:trigonometry</code></dt>\n    <dd>This option, on by default, allows Herbie to use basic\n      trigonometry facts during its search. If turned off, Herbie will\n      not be able to use those facts. Herbie's trigonometry knowledge\n      is extremely basic. You will rarely want to turn this option off.</dd>\n\n    <dt><code>rules:numerics</code></dt>\n    <dd>This option, off by default, allows Herbie to use special\n      numerical functions. If turned off, Herbie will not be able to\n      use these functions. You will want to turn this option on if\n      these functions (currently <code>expm1</code>, <code>log1p</code>,\n      and <code>hypot</code>) are available in your language.</dd>\n  </dl>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/0.9/using-herbgrind.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using HerbGrind</title>\n  <base href=\"../..\"/>\n  <link rel='stylesheet' type='text/css' href='main.css'>\n</head>\n<body>\n  <header>\n    <h1>Using HerbGrind</h1>\n    <a href=\".\"><img class=\"logo\" src=\"logo-car.png\" /></a>\n  </header>\n\n  <p>\n    <a href=\".\">HerbGrind</a> analyzes binaries to find inaccurate\n    floating point expressions. The binaries can come from anywhere—C\n    source, Fortran source, even unknown origins. This tutorial\n    runs HerbGrind on the benchmark programs that HerbGrind ships with.\n  </p>\n  \n  <h2>Compiling the benchmark program</h2>\n\n  <p>\n    HerbGrind ships test binaries in its <code>bench/</code>\n    directory. You can build them with:\n  </p>\n  \n  <pre>make -C bench all</pre>\n\n  <p>\n    Let's analyze the <code>diff-roots-simple.out</code> binary that\n    you just compiled. Run HerbGrind on that binary with:\n  </p>\n\n  <pre>valgrind/herbgrind-install/bin/valgrind --tool=herbgrind bench/diff-roots-simple.out</pre>\n\n  <p>\n    This should produce output that looks like this:\n  </p>\n  \n  <pre>==16725== HerbGrind, a valgrind tool for Herbie\n==16725== \n==16725== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info\n==16725== Command: bench/diff-roots-simple.out\n==16725== \n1.578592e-07\n==16725== \nWriting report out to bench/diff-roots-simple.out-errors.gh</pre>\n\n  <p>The printed value, <code>1.578592e-07</code>, is printed by\n  the <code>diff-roots-simple.out</code> binary. HerbGrind writes its\n  results to the named\n  file, <code>bench/diff-roots-simple.out-errors.gh</code>. This file\n  contains one record for each operation; the only operation found\n  in <code>diff-roots-simple.c</code> is:</p>\n  \n  <pre>(- (sqrt (+ 1.000000 10000000000000.000000)) (sqrt 10000000000000.000000))\nsubtraction in main at diff-roots-simple.c:12 (address 400A00)\n43.129555 bits average error\n43.129555 bits max error\nAggregated over 1 instances</pre>\n\n  <p>\n    The first line gives the expression inaccurately evaluated, and\n    the second line gives its location. That line\n    in <code>diff-roots-simple.c</code> is actually:\n  </p>\n\n  <pre>y = sqrt(x + 1) - sqrt(x);</pre>\n  \n  <p>\n    Since this line of code is run only once, HerbGrind doesn't know\n    that <code>x</code> is intended to be a variable, and instead\n    inlines its value.\n  </p>\n  \n  <p>\n    The next three lines of the output give the error incurred by the\n    inaccurate computation: 43.1 bits of error over 1 instance of computing that expression.\n  </p>\n  \n  <h2>Turning HerbGrind on and off</h2>\n\n  <p>\n    While running on <code>diff-roots-simple.out</code>, HerbGrind\n    found inaccurate computations not only\n    in <code>diff-roots-simple.out</code> but also in several GNU\n    library calls. HerbGrind has a feature to avoid tracking floating\n    point operations in libraries and other code not within your\n    control by adding instrumentation to your source code.\n  </p>\n  \n  <p>\n    Simply surround the numerically-interesting parts of your\n    computation in the <code>HERBGRIND_BEGIN()</code>\n    and <code>HERBGRIND_END()</code> macros:\n  </p>\n  \n  <pre>// initialization code ...\nHERBGRIND_BEGIN();\n// numerical code ...\nHERBGRIND_END();\n// cleanup code ...</pre>\n\n  <p>The <code>diff-roots-simple.c</code> example does this on lines\n    11 and 13. You can then run HerbGrind with\n    the <code>--start-off</code> flag, which tells HerbGrind not to\n    begin analyzing floating point operations until it sees\n    a <code>HERBGRIND_BEGIN()</code> region:\n  </p>\n\n  <pre>valgrind/herbgrind-install/bin/valgrind --tool=herbgrind \\\n      <b>--start-off</b> bench/diff-roots-simple.out</pre>\n\n  <p>\n    The report file now contains only the inaccurate expression\n    described before, and no library computations.\n  </p>\n  \n  <p>\n    The <code>HERBGRIND_BEGIN()</code>/<code>HERBGRIND_END()</code>\n    regions can be sprinkled anywhere in your source code; it's common\n    to use them to start HerbGrind only after initializing your\n    program and before cleaning up and outputting results. HerbGrind\n    can be turned on and off multiple times.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/0.9/using-herbie.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie</title>\n  <base href=\"../..\"/>\n  <link rel='stylesheet' type='text/css' href='main.css'>\n</head>\n<body>\n  <header>\n    <h1>Using Herbie</h1>\n    <a href=\".\"><img class=\"logo\" src=\"logo-car.png\" /></a>\n  </header>\n\n  <p>\n    <a href=\".\">Herbie</a> rewrites floating point expressions to\n    make them more accurate. The expressions could come from\n    anywhere—your source code, mathematical papers, or even the output\n    of <a href=\"doc/0.9/using-herbgrind.html\">HerbGrind</a>, our tool for\n    finding inaccurate expressions in binaries. This tutorial run\n    Herbie on the benchmark programs that Herbie ships with.\n  </p>\n  \n  <h2>The benchmark programs</h2>\n\n  <p>\n    Herbie ships a collection of binaries in its <code>bench/</code>\n    directory. For example, <code>bench/tutorial.rkt</code> contains the following code:\n  </p>\n  \n  <pre>(herbie-test (x)\n  \"Cancel like terms\"\n  (- (+ 1 x) x))\n\n(herbie-test (x)\n  \"Expanding a square\"\n  (- (sqr (+ x 1)) 1))\n\n(herbie-test (x y z)\n  \"Commute and associate\"\n  (- (+ (+ x y) z) (+ x (+ y z))))</pre>\n  \n  <p>\n    This code defines three floating point expressions that we want to\n    run Herbie on: the expression <code>(1 + x) - x</code>, the\n    expression <code>(x + 1)² - 1</code>, and finally the\n    expression <code>((x + y) + z) - (x + (y + z))</code>. You can\n    check out our <a href=\"doc/0.9/input.html\">input format documentation</a>\n    for more information about how to format Herbie inputs.\n  </p>\n\n  <h2>Running Herbie</h2>\n\n  <p>\n    Let's analyze these three examples using Herbie. Run Herbie:\n  </p>\n\n  <pre>racket src/herbie.rkt</pre>\n\n  <p>\n    After a few seconds, Herbie will start up and wait for input:\n  </p>\n  \n  <pre><strong>$</strong> racket src/herbie.rkt \nSeed: #(4084085515 1217806925 3915723770 1268025332 545417352 1092579889) </pre>\n\n  \n  <p>\n    You can now paste inputs directly into your terminal for Herbie to improve:\n  </p>\n\n  <pre>(herbie-test (x)\n  \"Cancel like terms\"\n  (- (+ 1 x) x))\n[ 1586.644ms]\tCancel like terms\t(29→ 0)\n(λ (x) 1)</pre>\n\n  <p>\n    Alternatively, you can run Herbie on a file with expressions with:\n  </p>\n  \n  <pre><strong>$</strong> racket src/herbie.rkt bench/tutorial.rkt > out.rkt\nSeed: #(1637424072 4209802118 1686524629 1009825284 4285017075 2209820745)\n[ 1563.552ms]\tCancel like terms\t(29→ 0)\n[ 4839.121ms]\tExpanding a square\t(38→ 0)\n[ 3083.238ms]\tCommute and associate\t( 0→ 0)</pre>\n  \n  <p>\n    The output file <code>out.rkt</code> contains more accurate\n    versions of each program:\n  </p>\n  \n  <pre>(λ (x) 1)\n(λ (x) (+ (* x 2) (* x x)))\n(λ (x y z) (- (+ (+ x y) z) (+ x (+ y z))))</pre>\n  \n  <p>\n    Note that the final expression was not simplified to <code>0</code> by Herbie,\n    since the difference in accuracy is negligible.\n  </p>\n  \n  <p>\n    For more control over Herbie, see the documentation of\n    Herbie's <a href=\"doc/0.9/options.html\">command-line options</a>.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.0/docker.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie on Docker</title>\n  <base href=\"../../\" />\n  <link rel='stylesheet' type='text/css' href='main.css'>\n</head>\n<body>\n  <header>\n    <h1>Installing with Docker</h1>\n    <a href=\".\"><img class=\"logo\" src=\"logo-car.png\" /></a>\n  </header>\n\n  <p>\n    <a href=\".\">Herbie</a>'s is available\n    through <a href=\"https://www.docker.com/\">Docker</a>, which is a\n    sort of like an easily-scriptable virtual machine. This page\n    describes how to install\n    the <a href=\"https://hub.docker.com/uwplse/herbie\">official Docker\n    image</a> for Herbie.\n  </p>\n  \n  <p>\n    Herbie can also be <a href=\"doc/1.0/installing.html\">installed\n    normally</a>.\n  </p>\n  \n  <h2>Installing the Herbie image</h2>\n\n  <p>\n    First, <a href=\"https://docs.docker.com/installation/\">install\n    Docker</a>. Docker supports Windows, OS X, and Linux. Depending on\n    how you install Docker, you may need to prefix\n    all <code>docker</code> commands on this page\n    with <code>sudo</code> or run them as the root or administrative\n    user.\n  </p>\n  \n  <p>\n    With Docker installed, you should be able to download the Herbie image with:\n  </p>\n \n\n  <pre>docker pull uwplse/herbie</pre>\n  \n  <p>\n    You can now run Herbie:\n  </p>\n\n  <pre>docker run uwplse/herbie -it</pre>\n  \n  <p>\n    This will run Herbie, reading input from the standard input. To\n    read from a file, you will need to mount the file in the Docker\n    container. Do that with:\n  </p>\n  \n  <pre><strong>$</strong> docker run -it \\\n    -v <var>dir</var>:/herbie/bench \\\n    uwplse/herbie bench/<var>file</var></pre>\n\n  <p>\n    In this command, <var>file</var> is a file you want to run Herbie\n    on, located in <var>dir</var>.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.0/faq.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie FAQ</title>\n  <base href=\"../..\"/>\n  <link rel='stylesheet' type='text/css' href='main.css'>\n</head>\n<body>\n  <header>\n    <h1>Frequently Asked Questions</h1>\n    <a href=\".\"><img class=\"logo\" src=\"logo-car.png\" /></a>\n  </header>\n\n  <p>\n    <a href=\".\">Herbie</a> automatically transforms floating point\n    expressions into more accurate forms. This page catalogs questions\n    frequently asked questions about Herbie.\n  </p>\n  \n  <h2>Troubleshooting common errors</h2>\n  \n  <p>\n    Several Herbie error messages refer to this page for additional\n    information and debugging tips.\n  </p>\n  \n  <h3 id=\"invalid-program\">“Invalid program” error</h3>\n\n  <p>\n    This error is most likely due to an error in preparing the input\n    to Herbie. Common errors include misspelling function names and\n    parenthesizing expressions that must not be parenthesized. The\n    stack trace will contain additional information. For example, in\n    the expression <code>(- (exp (x)) 1)</code>, the use\n    of <code>x</code> as invalid because <code>x</code> is a variable,\n    so cannot be parenthesized. <code>(- (exp x) 1)</code> would\n    be the correct way of describing that expression.\n  </p>\n  \n  <h3 id=\"sample-valid-points\">“Cannot sample enough valid points” error</h3>\n  \n  <p>\n    Herbie uses random sampling to select the points which it will use\n    to evaluate the error of an expression. This error occurs when it\n    is not able to find enough valid points. For example, consider the\n    expression <code>(acos (+ 1000 x))</code>. This expression yields\n    a valid result only when <code>x</code> is between -1001 and -999,\n    a rather narrow range.\n  </p>\n  \n  <p>\n    The solution is to give a <a href=\"input.html\">distribution</a>\n    which specifies the bounds on <code>x</code> by adding the line\n    <code>:herbie-samplers ([x (uniform -1001 -999)])</code> after the\n    parameter list.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.0/input.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Input Format</title>\n  <base href=\"../..\"/>\n  <link rel='stylesheet' type='text/css' href='main.css'>\n</head>\n<body>\n  <header>\n    <h1>The Input Format</h1>\n    <a href=\".\"><img class=\"logo\" src=\"logo-car.png\" /></a>\n  </header>\n\n  <p>\n    <a href=\".\">Herbie</a>'s input format is designed for\n    expressing mathematical functions, which Herbie can then search\n    for accurate implementations of. It also allows specifying the\n    distribution that Herbie draws inputs from when evaluating the\n    accuracy of an expression.\n  </p>\n  \n  <h2 id=\"sec1\">General format</h2>\n\n  <p>Herbie uses the <a href=\"http://fpbench.org\">FPCore</a> format\n  for its input expression, which looks like this:</p>\n\n  <pre>(FPCore (<var>inputs ...</var>) <var>properties ...</var> <var>expression</var>)</pre>\n\n  <p>\n    Each input is a variable, like <code>x</code>, which can be used\n    in the expression, whose accuracy Herbie will try to improve.\n    Properties are <a href=\"#properties\">described below</a>.\n  </p>\n\n  <p>\n    The expression is written in prefix form, with every function call\n    parenthesized, as in Lisp. For example, the formula for the\n    hypotenuse of a triangle with legs <i>a</i> and <i>b</i> is\n  </p>\n\n  <pre>(FPCore (a b) (sqrt (+ (sqr a) (sqr b))))</pre>\n\n  <p>\n    We recommend the <code>.fpcore</code> file extension for Herbie input files.\n  </p>\n\n  <h2>Converting from Herbie 0.9</h2>\n\n  <p>\n    Herbie 0.9 used a <a href=\"../0.9/input.html\">different input\n    format</a>, which is no longer supported in Herbie 1.0. To\n    simplify the transition, the <code>infra/convert.rkt</code> script\n    converts from the old to the new format.\n  </p>\n  \n  <p>To use the conversion tool, run:</p>\n\n  <pre>racket infra/convert.rkt <var>file.rkt</var> > <var>file.fpcore</var></pre>\n  \n  <h2>Supported functions</h2>\n  \n  <p>\n    The full list of supported functions and is as follows:\n  </p>\n\n  <dl class=\"function-list\">\n    <dt><code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>, <code>abs</code></dt>\n    <dd>The usual arithmetic functions<br/><code>-</code> is both negation and subtraction</dd>\n    <dt><code>sqr</code>, <code>sqrt</code></dt>\n    <dd>Squares and square roots</dd>\n    <dt><code>exp</code>, <code>log</code></dt>\n    <dd>Natural exponent and natural log</dd>\n    <dt><code>pow</code></dt>\n    <dd>Exponentiation; raising a value to a power</dd>\n    <dt><code>sin</code>, <code>cos</code>, <code>tan</code>, <code>cotan</code></dt>\n    <dd>The trigonometric functions</dd>\n    <dt><code>asin</code>, <code>acos</code>, <code>atan</code>, <code>atan2</code></dt>\n    <dd>The inverse trigonometric functions<br/><code>atan2</code> is the\n    two-argument inverse tangent</dd>\n    <dt><code>sinh</code>, <code>cosh</code>, <code>tanh</code></dt>\n    <dd>The hyperbolic trigonometric functions</dd>\n    <dt><code>expm1</code>, <code>log1p</code>, <code>hypot</code></dt>\n    <dd>Specialized numeric functions, as in <a href=\"http://pubs.opengroup.org/onlinepubs/7908799/xsh/math.h.html\">math.h</a></dd>\n  </dl>\n  \n  <p>FPCore writes conditional expressions using <code>if</code>:</p>\n\n  <pre>(if <var>cond</var> <var>if-true</var> <var>if-false</var>)</pre>\n\n  <p>\n    An <code>if</code> epxression evaluates the\n    conditional <code>cond</code> and returns either <code>if-true</code> if\n    it is true or <code>if-false</code> if it is not. Conditionals may use:\n  </p>\n  \n  <dl class=\"function-list\">\n    <dt><code>==</code>, <code>!=</code>, <code>&lt;</code>, <code>&gt;</code>, <code>&lt;=</code>, <code>&gt;=</code></dt>\n    <dd>The usual comparison operators</dd>\n    <dt><code>and</code>, <code>or</code>, <code>not</code></dt>\n    <dd>The usual logical operators</dd>\n  </dl>\n  \n  <p>Intermediate variables can be defined using <code>let</code>:</p>\n\n  <pre>(let ([<var>variable</var> <var>value</var>] <var>...</var>) <var>body</var>)</pre>\n\n  <p>\n    In a <code>let</code> expression, all the values are evaluated first,\n    and then are bound to their variables in the body.\n    This means that you can't use one variable in the value of another;\n    nest <code>let</code> constructs if you want to do that.\n    Note that Herbie treats these intermediate values only as a\n    notational convenience, and inlines their values before improving\n    the formula's accuracy.\n  </p>\n\n  <p>Herbie also supports the constants <code>PI</code> and <code>E</code>.</p>\n  \n  <h2 id=\"properties\">Properties</h2>\n\n  <p>Herbie also uses several FPCore properties for additional meta-data:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>:name <var>string</var></code></dt>\n    <dd>Herbie prints this name in its output when a name is required.</dd>\n    <dt><code>:pre <var>condition</var></code></dt>\n    <dd>Only points where the condition is true are sampled by Herbie.</dd>\n    <dt><code>:herbie-samplers <var>samplers</var></code></dt>\n    <dd>Change the distribution with which variables are sampled (see below).</dd>\n    <dt>\n  </dl>\n  \n  <h2>Distributions</h2>\n\n  <p>\n    Herbie allows you to specify what distribution is used to randomly\n    sample values for each variable with\n    the <code>:herbie-samplers</code> property. For example:\n  </p>\n  \n  <pre>:herbie-samplers ([x (uniform 0 1)] [y (uniform -1 1)])</pre>\n\n  <p>\n    This property tells Herbie to use a uniform distribution to sample\n    a value between 0 and 1 for <code>x</code>, and between -1 and 1\n    for <code>y</code>. Not all variables need to be given distributions;\n    if a variable isn't given a distribution, the <code>default</code>\n    distribution will be used.\n  </p>\n  \n  <dl class=\"function-list\">\n    <dt><code>default</code></dt>\n    <dd>Interpret a random bit pattern as a float</dd>\n    <dt><code>(uniform <var>a</var> <var>b</var>)</code></dt>\n    <dd>A uniform real value between <var>a</var> and <var>b</var><br/>Both bounds must be numeric constants</dd>\n  </dl>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.0/installing-herbgrind.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Installing Herbgrind</title>\n  <base href=\"../..\"/>\n  <link rel='stylesheet' type='text/css' href='main.css'>\n</head>\n<body>\n  <header>\n    <h1>Installing Herbgrind</h1>\n    <a href=\".\"><img class=\"logo\" src=\"logo-car.png\" /></a>\n  </header>\n\n  <p>\n    <a href=\".\">Herbgrind</a> depends\n    on <a href=\"http://valgrind.org\">Valgrind</a>, a binary\n    instrumentation and memory analysis framework. To install\n    Herbgrind, you must first install a C compiler and\n    GNU <code>awk</code> and <code>sed</code>.\n  </p>\n  \n  <p class=\"note\">\n    Herbgrind is <strong>α</strong> software. It is currently known to\n    work only on 64-bit GNU Linux platforms. Support for 32-bit\n    architectures, for OS X, for Clang, and for BSD core tools is\n    still in progress. Please <a href=\"https://github.com/uwplse/herbgrind/issues\">file a bug</a>\n    if Herbgrind does not work on your system.\n  </p>\n\n  <h2>Installing GNU AWK and Sed</h2>\n\n  <p>\n    Herbgrind currently supports 64-bit GNU Linux with GCC; OS X has\n    known bugs, and other configurations are untested. On Linux,\n    install GCC, AWK, and Sed using distro-provided packages; on\n    Debian-derivatives, use the <code>build-essentials</code> pacakge:\n  </p>\n  \n  <pre>sudo apt-get install build-essentials</pre>\n\n  <p>\n    On OS X, the same tools can be installed using <a href=\"https://brew.sh\">Homebrew</a>:\n  </p>\n\n  <pre>brew install gawk\nbrew install gnu-sed --with-default-names\nbrew install gcc</pre>\n  \n  <p>You will also want the XCode Command-line Tools on OSX, which you can install with:</p>\n\n  <pre>xcode-select --install</pre>\n  \n  <h2>Installing Herbgrind</h2>\n\n  <p>\n    Once the GNU tools are installed, download the Herbgrind source\n    <a href=\"https://github.com/uwplse/herbgrind\">from GitHub</a> with:\n  </p>\n\n  <pre>git clone https://github.com/uwplse/herbgrind</pre>\n\n  <p>\n    If you go to the <code>herbgrind</code> directory,\n    you should see a <code>README.md</code> file, a directory named <code>herbgrind</code>,\n    a directory named <code>bench/</code>, and a variety of other directories.\n    You should also see a <code>Makefile</code>. Make the binary with:\n  </p>\n\n  <pre>make compile</pre>\n\n  <p>\n    This command will take approximately ten minutes to run for the first time,\n      since it will download and build a custom Valgrind fork.\n    You may want to set the following Make variables;\n  </p>\n  \n  <dl>\n    <dt><code>TARGET_PLAT</code></dt>\n    <dd>The platform you want to run Herbgrind on; the default\n    is <code>amd64-darwin</code> on OS X and <code>amd64-linux</code>\n    otherwise.</dd>\n    <dt><code>ARCH_PRIM</code> and <code>ARCH_SEC</code></dt>\n    <dd>The primary and secondary architecture versions, which you\n    will want to set for some 64+32-bit configurations. The default\n    is <code>amd64</code> primary and no secondary.</dd>\n  </p>\n\n  <p>You can also configure without compiling using <code>make setup</code>.</p>\n\n  <p>\n    Once Herbgrind is installed and working correctly,\n    check out the <a href=\"doc/1.0/using-herbgrind.html\">usage instructions</a>.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.0/installing-herbie.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Installing Herbie</title>\n  <base href=\"../..\"/>\n  <link rel='stylesheet' type='text/css' href='main.css'>\n</head>\n<body>\n  <header>\n    <h1>Installing Herbie</h1>\n    <a href=\".\"><img class=\"logo\" src=\"logo-car.png\" /></a>\n  </header>\n\n  <p>\n    <a href=\".\">Herbie</a> depends\n    on <a href=\"https://racket-lang.org\">Racket</a>, a dynamic\n    language developed by Northeastern University. To install Herbie,\n    one must first install Racket. Once Racket is installed, Herbie\n    should run without problems.\n  </p>\n\n  <h2>Installing Racket</h2>\n\n  <p>\n    Herbie currently supports Linux and OS X. Windows has known bugs\n    we are working to resolve, due to the lack of a\n    full <code>math.h</code> library. Use\n    the <a href=\"http://download.racket-lang.org/racket-v6.5.html\">official\n    installer</a> to install Racket, or use distro-provided packages\n    provided they are version 6.4 or later of Racket (earlier versions\n    are not supported).\n  </p>\n\n  <p>\n    Test that Racket is installed correctly and has a correct version:\n  </p>\n\n  <pre><strong>$</strong> racket\nWelcome to Racket v6.4.\n> (exit)</pre>\n  \n  <h2>Installing Herbie</h2>\n\n  <p>\n    Once Racket is installed, download the Herbie source\n    <a href=\"https://github.com/uwplse/herbie\">from GitHub</a> with:\n  </p>\n\n  <pre>git clone https://github.com/uwplse/herbie</pre>\n\n  <p>\n    If you go to the <code>herbie</code> directory,\n    you should see a <code>README.md</code> file, a directory named <code>herbie</code>,\n    a directory named <code>bench/</code>, and a variety of other directories.\n    Do a trial run of Herbie to make sure everything is installed and working correctly:\n  </p>\n\n  <pre>racket src/reports/run.rkt bench/hamming/</pre>\n\n  <p>\n    This command will take approximately fifteen minutes to run;\n      it runs Herbie on problems from Richard Hamming's\n      <i>Numerical Methods for Scientists and Engineers</i>, Chapter 3.\n    After the command completes,\n      a directory named <code>graphs</code> should have appeared.\n    Open up the <code>report.html</code> file inside with your browser;\n      you should see a listing of the expressions Herbie was run on,\n      most of which should be green.\n    A score of 24/28 or greater suggests that everything is working correctly.\n  </p>\n\n  <p>\n    If any of the test results are crashes (there will be a “crashes” count at the top),\n      installation issues are to blame.\n    Check that your Racket installation is at least version 6.1\n      and that you installed Racket from the official installation packages.\n    If you're confident the installation is correct\n      please <a href=\"mailto:herbie@cs.washington.edu\">report the error</a> to the Herbie developers,\n      attaching an archive of the complete <code>graphs/</code> directory.\n  </p>\n\n  <p>If this all works correctly, you can make Herbie start up faster by byte-compiling it:</p>\n\n  <pre>raco make src/reports/run.rkt</pre>\n\n  <p>\n    Once Herbie is installed and working correctly,\n    check out the <a href=\"tutorial.html\">tutorial</a>.\n  </p>\n  \n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.0/options.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Command-line Options</title>\n  <base href=\"../..\"/>\n  <link rel='stylesheet' type='text/css' href='main.css'>\n</head>\n<body>\n  <header>\n    <h1>Command-line Options</h1>\n    <a href=\".\"><img class=\"logo\" src=\"logo-car.png\" /></a>\n  </header>\n\n  <p>\n    The <a href=\".\">Herbie</a> command takes several options\n    that influence its search procedure and the types of solutions it finds.\n    These options apply both to the report generator and the one-off command-line tool.\n  </p>\n\n  <h2>General Options</h2>\n\n  These options can be set on both the report generator and the one-off tool,\n  and influence the coarse properties of Herbie's search.\n\n  <dl>\n    <dt><code>--seed</code></dt>\n    <dd>This sets the random seed, which changes the randomly-selected\n      points that Herbie evaluates candidate expressions on. The\n      format of the seed is that used by the\n      Racket <code>vector->pseudo-random-generator!</code> function;\n      in practice, just use a seed produced by an earlier run. This\n      option can be used to make Herbie's results reproducible or to\n      compare two different runs.</dd>\n\n    <dt><code>--num-iters</code></dt>\n    <dd>The number of improvements Herbie attempts to make to the\n      program. The default, 2, suffices for most programs and helps\n      keep Herbie fast. If this is set very high, Herbie may run out\n      of things to do and terminate before the given number of\n      iterations, but in practice iterations beyond the first few\n      rarely lead to lower error. This option can be increased to 3 or\n      4 to check that there aren't further improvements that Herbie\n      could seek out.</dd>\n\n    <dt><code>--num-points</code></dt>\n    <dd>The number of randomly-selected points used to evaluate\n      candidate expressions. The default, 256, gives good behavior for\n      most programs. The more points sampled, the slower Herbie is.\n      This option can be increased to 512 or 1024 if Herbie gives very\n      inconsistent results between runs with different seeds.</dd>\n    \n    <dt><code>--timeout</code></dt>\n    <dd>The timeout to use per-example, in seconds. A fractional\n    number of seconds can be given.</dd>\n\n    <!--\n    <dt><code>--threads</code>, for the report generator only</dt>\n    <dd>Enables multi-threaded operation. By default, no threads are\n      used, a number can be passed to this option to use that many\n      threads, or <code>yes</code> can be passed to tell Herbie to use\n      all but one of the hardware threads. This option is not\n      supported on OS X or in Racket 6.2, and will warn if used in\n      those cases.</dd>\n    -->\n  </dl>\n\n  <h2>Search Options</h2>\n\n  These options influence the fine properties of Herbie's search, most\n  importantly the types of transformations that Herbie uses to find\n  candidate programs. These options offer very fine-grained control\n  over Herbie's output, and are only recommended for advanced uses of\n  Herbie.\n\n  Each option can be toggled with the <code>-o</code>\n  or <code>--option</code> command-line flags. The recommended set of\n  options is the default set; turning a default-on option off\n  typically results in less-accurate results, while turning a\n  default-off option on typically results in more-complex and\n  more-surprising output expressions.\n\n  <dl>\n    <dt><code>precision:double</code></dt>\n    <dd>This option, on by default, runs Herbie in double-precision\n      mode. If turned off, Herbie runs in single-precision mode.</dd>\n\n    <dt><code>setup:simplify</code></dt>\n    <dd>This option, on by default, simplifies the expression before\n      passing it to Herbie. If turned off, Herbie will not simplify\n      input programs before improving them. You will want to turn off\n      this option if simplifying the program will create a lot of\n      error, say if the association of operations is cleverly\n      chosen.</dd>\n\n    <dt><code>setup:early-exit</code></dt>\n    <dd>This option, off by default, causes Herbie to exit without\n      modifying the input program if it determines that the input\n      program has less than 0.1 bits of error. You will want to turn\n      this option on if you are running Herbie on a large corpus of\n      programs that you do not believe to be inaccurate.</dd>\n\n    <dt><code>generate:rr</code></dt>\n    <dd>This option, on by default, uses Herbie's recursive rewriting\n      algorithm to generate candidate programs. If turned off, Herbie\n      will use a non-recursive rewriting algorithm, which will\n      substantially limit the candidates Herbie finds. You will rarely\n      want to turn this option off.</dd>\n\n    <dt><code>generate:taylor</code></dt>\n    <dd>This option, on by default, uses series expansion to produce\n      new candidates during the main improvement loop. If turned off,\n      Herbie will not use series expansion in the main improvement loop.\n      You will want to turn this option off if you want to avoid\n      series-expansion-based rewrites, such as if you need to preserve\n      the equivalence of the input and output expressions as real-number\n      formulas.</dd>\n\n    <dt><code>generate:simplify</code></dt>\n    <dd>This option, on by default, simplifies candidates during the\n      main improvement loop. If turned off, candidates will not be\n      simplified, which typically results in much less accurate\n      expressions, since simplification is often necessary for\n      cancelling terms. You will rarely want to turn this option off.</dd>\n\n    <dt><code>reduce:regimes</code></dt>\n    <dd>This option, on by default, uses Herbie's regime inference\n      algorithm to branch between several program candidates. If\n      turned off, brances will be inferred and the output program will\n      be straight-line code (if the input was). You will want to turn\n      this option off if your programming environment makes branches\n      too expensive, such as in some cases of GPU programming.</dd>\n\n    <dt><code>reduce:taylor</code></dt>\n    <dd>This option, on by default, uses a final set of series\n      expansions after all improvements have been made. This sometimes\n      improves accuracy further. If turned off, this final series\n      expansion pass will not be done. You will want to turn this\n      option off if you want to avoid series-expansion-based rewrites,\n      such as if you need to preserve the equivalence of the input and\n      output expressions as real-number formulas.</dd>\n\n    <dt><code>reduce:simplify</code></dt>\n    <dd>This option, on by default, uses a final simplification pass\n      after all improvements have been made. This sometimes improves\n      accuracy further. If turned off, this final simplification pass\n      will not be done. You will rarely want to turn this option\n      off.</dd>\n\n    <dt><code>reduce:avg-error</code></dt>\n    <dd>This option, on by default, causes Herbie to output the\n      candidate with the best average error over the chosen inputs. If\n      turned off, Herbie will choose the candidate with the least\n      maximum error instead. This usually produces programs with worse\n      overall accuracy. You may want to turn this option off if\n      worst-case accuracy is more important to you than overall\n      accuracy.</dd>\n\n    <dt><code>rules:arithmetic</code></dt>\n    <dd>This option, on by default, allows Herbie to use basic\n      arithmetic facts during its search. If turned off, Herbie will\n      not be able to use those facts. You will rarely want to turn\n      this option off.</dd>\n\n    <dt><code>rules:polynomials</code></dt>\n    <dd>This option, on by default, allows Herbie to use facts\n      about polynomials during its search. If turned off, Herbie will\n      not be able to use those facts. You will rarely want to turn\n      this option off.</dd>\n\n    <dt><code>rules:fractions</code></dt>\n    <dd>This option, on by default, allows Herbie to use facts about\n      fractions during its search. If turned off, Herbie will not be\n      able to use those facts. You will rarely want to turn this\n      option off.</dd>\n\n    <dt><code>rules:exponents</code></dt>\n    <dd>This option, on by default, allows Herbie to use facts about\n      exponents during its search. If turned off, Herbie will not be\n      able to use those facts. You rarely want to turn this option off\n      if you do not want to use exponents or logarithms in the output\n      expressions, which might be the case when code runtime is more\n      important than accuracy.</dd>\n\n    <dt><code>rules:trigonometry</code></dt>\n    <dd>This option, on by default, allows Herbie to use basic\n      trigonometry facts during its search. If turned off, Herbie will\n      not be able to use those facts. Herbie's trigonometry knowledge\n      is extremely basic. You will rarely want to turn this option off.</dd>\n\n    <dt><code>rules:numerics</code></dt>\n    <dd>This option, off by default, allows Herbie to use special\n      numerical functions. If turned off, Herbie will not be able to\n      use these functions. You will want to turn this option on if\n      these functions (currently <code>expm1</code>, <code>log1p</code>,\n      and <code>hypot</code>) are available in your language.</dd>\n  </dl>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.0/release-notes.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie 1.0 Release Notes</title>\n  <base href=\"../../\" />\n  <link rel='stylesheet' type='text/css' href='main.css'>\n</head>\n<body>\n  <header>\n    <h1>Herbie 1.0 Release Notes</h1>\n    <a href=\".\"><img class=\"logo\" src=\"logo-car.png\" /></a>\n  </header>\n\n  <p>\n    After two years of work, the <a href=\".\">Herbie</a> developers are\n    excited to announce Herbie 1.0! This is the first release of\n    Herbie, marking its transition from research software to a tool\n    for scientists and engineers to improve the accuracy of their\n    floating point software.\n  </p>\n\n  <p>\n    Herbie automatically improves the accuracy of floating point\n    expressions. This avoids the bugs, errors, and surprises that so\n    often occur when working with floating point. Since\n    our <a href=\"papers.html\">PLDI'15 paper</a>, we've been hard at\n    work making Herbie more versatile and easier to use.\n  </p>\n\n  <h2>Usability improvements</h2>\n\n  <ul>\n    <li>A switch to the standard FPCore <a href=\"doc/1.0/input.html\">input\n    format</a>. This makes it easy to use Herbie together with other\n    floating point tools,\n    like <a href=\"doc/1.0/using-herbgrind.html\">Herbgrind</a>.</li>\n    <li>A <a href=\"/demo/\">web demo</a>, which makes it easy to try\n    out Herbie and also gives us a sense of what problems people are\n    trying to solve using Herbie.</li>\n    <li>Easier <a href=\"doc/1.0/installing-herbie.html\">installation</a>.\n    We've removed dependencies on several external libraries, upgraded\n    to the latest versions of Racket, and eliminated a confusing\n    linking step.</li>\n    <li>OS X support. We've tracked down several bugs that prevented\n    Herbie from working on OS X.</li>\n    <li>Support for more functions. Every function available\n    in <a href=\"http://pubs.opengroup.org/onlinepubs/7908799/xsh/math.h.html\">math.h</a>\n    is supported, and some additional functions from GNU libc are as\n    well.</li>\n    <li><a href=\"doc/1.0/docker.html\">Docker support</a> for Herbie. You can\n    now use the popular container tool to make installation even\n    easier.</li>\n    <li>More informative report pages, visible in the web demo, which\n    makes them more useful both for users and for debugging. In\n    particular, the new graph gives a quick overview of how Herbie did\n    on a collection of inputs.</li>\n    <li>Make it possible to <a href=\"doc/1.0/options.html\">toggle rulesets</a>\n    in Herbie.</li>\n    <li>A new entry point into Herbie, cleaning up a haphazard\n    collection of different scripts.</li>\n    <li>New website!</li>\n  </ul>\n\n  <h2>Improvement to core algorithm</h2>\n\n  <ul>\n    <li>Herbie is now faster! A new measurement infrastructure helped\n    us track down some time sinks.</li>\n    <li>Bounds on variables. You can now specifiy bounds within which\n    to sample variables.</li>\n    <li>Branch on expressions. Herbie can now sometimes infer\n    conditionals that use expressions, not variables, to determine\n    which expression to use.</li>\n    <li>Support expansions around ±∞ in Taylor expansions. The\n    framework behind this should eventually make it possible to\n    support Puiseux series as well.</li>\n    <li>Simplify expressions such as <code>(exp 1)</code>\n    or <code>(cos PI)</code>, by supporting symbolic constants in the\n    simplification algorithm.</li>\n    <li>Faster Taylor series routine. Several large tweaks have helped\n    make Taylor series orders of magnitude faster, which has sped up\n    Herbie.</li>\n  </ul>\n\n  <h2>Code Cleanup</h2>\n\n  <ul>\n    <li>Use a proper parser for input files. We used to use a bizarre\n    system of <code>eval</code>ing input files and poking around\n    global storage for the results.</li>\n    <li>Many crashes fixed. Herbie is stabler than ever!</li>\n    <li>A new debugging and logging system, which makes Herbie\n    debugging from the REPL significantly easier</li>\n    <li>A new measurement system that lets us see where Herbie spend\n    its time. This has helped speed up Herbie.</li>\n    <li>A new implementation of the Herbie main loop, which is much\n    easier to work with in the debugger.</li>\n    <li>Unit tests and more integration with the Racket toolchain.</li>\n    <li>A fuzzer for Herbie, which has allowed us to track down many bugs.</li>\n  </ul>\n  \n  <h2>Try it out!</h2>\n\n  <p>\n    We're excited to continue to improve Herbie and make it more\n    useful to scientists, engineers, and programmers around the world.\n    We've got a lot of features we're excited to work on in the coming\n    months. Please\n    <a href=\"https://github.com/uwplse/herbie/issues\">report bugs</a>,\n    join\n    <a href=\"https://mailman.cs.washington.edu/mailman/listinfo/herbie\">the\n    mailing list</a>,\n    or <a href=\"https://github.com/uw-plse/herbie\">contribute</a>.\n  </p>\n  \n  <p><em style=\"font-weight: bold; font-style: roman;\">If you find Herbie useful, <a href=\"mailto:herbie@cs.washington.edu\">let us know!</em></p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.0/using-herbgrind.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbgrind</title>\n  <base href=\"../..\"/>\n  <link rel='stylesheet' type='text/css' href='main.css'>\n</head>\n<body>\n  <header>\n    <h1>Using Herbgrind</h1>\n    <a href=\".\"><img class=\"logo\" src=\"logo-car.png\" /></a>\n  </header>\n\n  <p>\n    <a href=\".\">Herbgrind</a> analyzes binaries to find inaccurate\n    floating point expressions. The binaries can come from anywhere—C\n    source, Fortran source, even unknown origins. This tutorial\n    runs Herbgrind on the benchmark programs that Herbgrind ships with.\n  </p>\n  \n  <h2>Compiling the benchmark program</h2>\n\n  <p>\n    Herbgrind ships test binaries in its <code>bench/</code>\n    directory. You can build them with:\n  </p>\n  \n  <pre>make -C bench all</pre>\n\n  <p>\n    Let's analyze the <code>diff-roots-simple.out</code> binary that\n    you just compiled. Run Herbgrind on that binary with:\n  </p>\n\n  <pre>valgrind/herbgrind-install/bin/valgrind --tool=herbgrind bench/diff-roots-simple.out</pre>\n\n  <p>\n    This should produce output that looks like this:\n  </p>\n  \n  <pre>==16725== Herbgrind, a valgrind tool for Herbie\n==16725== \n==16725== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info\n==16725== Command: bench/diff-roots-simple.out\n==16725== \n1.578592e-07\n==16725== \nWriting report out to bench/diff-roots-simple.out-errors.gh</pre>\n\n  <p>The printed value, <code>1.578592e-07</code>, is printed by\n  the <code>diff-roots-simple.out</code> binary. Herbgrind writes its\n  results to the named\n  file, <code>bench/diff-roots-simple.out-errors.gh</code>. This file\n  contains one record for each operation; the only operation found\n  in <code>diff-roots-simple.c</code> is:</p>\n  \n  <pre>(FPCore ()\n  :type binary64\n  (- (sqrt (+ 1.000000 10000000000000.000000)) (sqrt 10000000000000.000000)))\nsubtraction in main at diff-roots-simple.c:12 (address 400A00)\n43.129555 bits average error\n43.129555 bits max error\nAggregated over 1 instances</pre>\n\n  <p>\n    The first line gives the expression inaccurately evaluated, and\n    the second line gives its location. That line\n    in <code>diff-roots-simple.c</code> is actually:\n  </p>\n\n  <pre>y = sqrt(x + 1) - sqrt(x);</pre>\n  \n  <p>\n    Since this line of code is run only once, Herbgrind doesn't know\n    that <code>x</code> is intended to be a variable, and instead\n    inlines its value.\n  </p>\n  \n  <p>\n    The next three lines of the output give the error incurred by the\n    inaccurate computation: 43.1 bits of error over 1 instance of computing that expression.\n  </p>\n  \n  <h2>Turning Herbgrind on and off</h2>\n\n  <p>\n    While running on <code>diff-roots-simple.out</code>, Herbgrind\n    found inaccurate computations not only\n    in <code>diff-roots-simple.out</code> but also in several GNU\n    library calls. Herbgrind has a feature to avoid tracking floating\n    point operations in libraries and other code not within your\n    control by adding instrumentation to your source code.\n  </p>\n  \n  <p>\n    Simply surround the numerically-interesting parts of your\n    computation in the <code>HERBGRIND_BEGIN()</code>\n    and <code>HERBGRIND_END()</code> macros:\n  </p>\n  \n  <pre>// initialization code ...\nHERBGRIND_BEGIN();\n// numerical code ...\nHERBGRIND_END();\n// cleanup code ...</pre>\n\n  <p>The <code>diff-roots-simple.c</code> example does this on lines\n    11 and 13. You can then run Herbgrind with\n    the <code>--start-off</code> flag, which tells Herbgrind not to\n    begin analyzing floating point operations until it sees\n    a <code>HERBGRIND_BEGIN()</code> region:\n  </p>\n\n  <pre>valgrind/herbgrind-install/bin/valgrind --tool=herbgrind \\\n      <b>--start-off</b> bench/diff-roots-simple.out</pre>\n\n  <p>\n    The report file now contains only the inaccurate expression\n    described before, and no library computations.\n  </p>\n  \n  <p>\n    The <code>HERBGRIND_BEGIN()</code>/<code>HERBGRIND_END()</code>\n    regions can be sprinkled anywhere in your source code; it's common\n    to use them to start Herbgrind only after initializing your\n    program and before cleaning up and outputting results. Herbgrind\n    can be turned on and off multiple times.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.0/using-herbie.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie</title>\n  <base href=\"../..\"/>\n  <link rel='stylesheet' type='text/css' href='main.css'>\n</head>\n<body>\n  <header>\n    <h1>Using Herbie</h1>\n    <a href=\".\"><img class=\"logo\" src=\"logo-car.png\" /></a>\n  </header>\n\n  <p>\n    <a href=\".\">Herbie</a> rewrites floating point expressions to\n    make them more accurate. The expressions could come from\n    anywhere—your source code, mathematical papers, or even the output\n    of <a href=\"doc/1.0/using-herbgrind.html\">Herbgrind</a>, our tool for\n    finding inaccurate expressions in binaries. This tutorial run\n    Herbie on the benchmark programs that Herbie ships with.\n  </p>\n  \n  <h2>The benchmark programs</h2>\n\n  <p>\n    Herbie ships a collection of binaries in its <code>bench/</code>\n    directory. For example, <code>bench/tutorial.fpcore</code> contains the following code:\n  </p>\n  \n  <pre>(FPCore (x)\n  :name \"Cancel like terms\"\n  (- (+ 1 x) x))\n\n(FPCore (x)\n  :name \"Expanding a square\"\n  (- (sqr (+ x 1)) 1))\n\n(FPCore (x y z)\n  :name \"Commute and associate\"\n  (- (+ (+ x y) z) (+ x (+ y z))))</pre>\n  \n  <p>\n    This code defines three floating point expressions that we want to\n    run Herbie on: the expression <code>(1 + x) - x</code>, the\n    expression <code>(x + 1)² - 1</code>, and finally the\n    expression <code>((x + y) + z) - (x + (y + z))</code>. You can\n    check out our <a href=\"doc/1.0/input.html\">input format documentation</a>\n    for more information about how to format Herbie inputs.\n  </p>\n\n  <h2>Running Herbie</h2>\n\n  <p>\n    Let's analyze these three examples using Herbie. Run Herbie:\n  </p>\n\n  <pre>racket src/herbie.rkt</pre>\n\n  <p>\n    After a few seconds, Herbie will start up and wait for input:\n  </p>\n  \n  <pre><strong>$</strong> racket src/herbie.rkt \nSeed: #(4084085515 1217806925 3915723770 1268025332 545417352 1092579889) </pre>\n\n  \n  <p>\n    You can now paste inputs directly into your terminal for Herbie to improve:\n  </p>\n\n  <pre>(FPCore (x)\n  :name \"Cancel like terms\"\n  (- (+ 1 x) x))\n[ 1586.644ms]\tCancel like terms\t(29→ 0)\n(FPCore (x) :name \"Cancel like terms\" 1)</pre>\n\n  <p>\n    Alternatively, you can run Herbie on a file with expressions with:\n  </p>\n  \n  <pre><strong>$</strong> racket src/herbie.rkt bench/tutorial.fpcore > out.rkt\nSeed: #(1637424072 4209802118 1686524629 1009825284 4285017075 2209820745)\n[ 1563.552ms]\tCancel like terms\t(29→ 0)\n[ 4839.121ms]\tExpanding a square\t(38→ 0)\n[ 3083.238ms]\tCommute and associate\t( 0→ 0)</pre>\n  \n  <p>\n    The output file <code>out.rkt</code> contains more accurate\n    versions of each program:\n  </p>\n  \n  <pre>(FPCore (x)\n :name \"Cancel like terms\"\n 1)\n\n(FPCore (x)\n :name \"Expanding a square\"\n (+ (* x 2) (* x x)))\n\n(FPCore (x y z)\n :name \"Commute and associate\"\n (- (+ (+ x y) z) (+ x (+ y z))))</pre>\n  \n  <p>\n    Note that the final expression was not simplified to <code>0</code> by Herbie,\n    since the difference in accuracy is negligible.\n  </p>\n  \n  <p>\n    For more control over Herbie, see the documentation of\n    Herbie's <a href=\"doc/1.0/options.html\">command-line options</a>.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.1/compare.js",
    "content": "margin = 10;\nbarheight = 10;\nwidth = 505;\ntextbar = 20;\n\nfunction sort_by(i1, i2) {\n    return function(a, b) {\n        return b[i1][i2] - a[i1][i2];\n    }\n}\n\nfunction r10(d) {\n    return \"\" + (Math.round(d * 10) / 10);\n}\n\nfunction make_graph(node, data, start, end) {\n    var len = data.length;\n    var precision = 64; // TODO\n\n    var a = d3.selectAll(\"script\");\n    var script = a[0][a[0].length - 1];\n\n    var svg = node\n        .attr(\"width\", width + 2 * margin)\n        .attr(\"height\", len * barheight + 2 * margin + textbar)\n        .append(\"g\").attr(\"transform\", \"translate(\" + margin + \",\" + margin + \")\");\n\n    for (var i = 0; i <= precision; i += 4) {\n        svg.append(\"line\")\n            .attr(\"class\", \"gridline\")\n            .attr(\"x1\", i / precision * width)\n            .attr(\"x2\", i / precision * width)\n            .attr(\"y1\", 0)\n            .attr(\"y2\", len * barheight);\n\n        svg.append(\"text\").text(i)\n            .attr(\"x\", i / precision * width)\n            .attr(\"width\", 80)\n            .attr(\"y\", len * barheight + textbar);\n    }\n\n    var bar = svg.selectAll(\"g\").data(data).enter();\n\n    function line_y(d, i) { return (i + .5) * barheight; }\n    function title(d, i) { return d.name + \" (\" + r10(precision - d[\"Old\"][start]) + \" to \" + r10(precision - d[\"Old\"][end]) + \")\"; }\n\n    bar.append(\"line\")\n        .attr(\"class\", \"guide\")\n        .attr(\"x1\", 0)\n        .attr(\"x2\", function(d) { return (precision - Math.max(d[\"Old\"][start], d[\"Old\"][end])) / precision * width })\n        .attr(\"y1\", line_y)\n        .attr(\"y2\", line_y);\n\n    var g = bar.append(\"g\").attr(\"title\", title);\n\n    g.append(\"line\").attr(\"class\", \"old\")\n        .attr(\"x1\", function(d) {return (precision - d[\"Old\"][start]) / precision * width})\n        .attr(\"x2\", function(d) { return (precision - d[\"Old\"][end]) / precision * width })\n        .attr(\"y1\", line_y)\n        .attr(\"y2\", line_y);\n\n    g.append(\"line\").attr(\"class\", \"new\")\n        .attr(\"x1\", function(d) {return (precision - d[\"Old\"][end]) / precision * width})\n        .attr(\"x2\", function(d) { return (precision - d[\"New\"][end]) / precision * width })\n        .attr(\"y1\", line_y)\n        .attr(\"y2\", line_y);\n\n    g.append(\"g\")\n        .attr(\"class\", function(d) { return d[\"New\"][end] < d[\"Old\"][end] - .5 ? \"new\" : \"old\" })\n        .attr(\"transform\", function(d, i) {\n        return \"translate(\" + ((precision - d[\"New\"][end]) / precision * width) + \", \" + line_y(d, i) + \")\";\n    })\n        .append(\"polygon\").attr(\"points\", \"0,-3,0,3,5,0\");\n}\n\nfunction draw_results(node) {\n    d3.json(\"results-old.json\", function(err, old_data) {\n        d3.json(\"results-new.json\", function(err, new_data) {\n            if (err) return console.error(err);\n            data = [];\n            old_data.tests.sort(function(a, b) { return (a.input < b.input) ? -1 : (a.input == b.input) ? 0 : 1});\n            new_data.tests.sort(function(a, b) { return (a.input < b.input) ? -1 : (a.input == b.input) ? 0 : 1});\n            for (var i = 0; i < old_data.tests.length; i++) {\n                data.push({Old: old_data.tests[i], New: new_data.tests[i]});\n            }\n    \n            data.sort(sort_by(\"Old\", \"start\"));\n            make_graph(node, data, \"start\", \"end\");\n        });\n    });\n}\n"
  },
  {
    "path": "www/doc/1.1/docker.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie on Docker</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n</head>\n<body>\n  <header>\n    <h1>Installing with Docker</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"using-web.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a>'s is available\n    through <a href=\"https://www.docker.com/\">Docker</a>, which is a\n    sort of like an easily-scriptable virtual machine. This page\n    describes how to install\n    the <a href=\"https://hub.docker.com/uwplse/herbie\">official Docker\n    image</a> for Herbie.\n  </p>\n  \n  <p>\n    Herbie can also be <a href=\"installing.html\">installed\n    normally</a>.\n  </p>\n  \n  <h2>Installing the Herbie image</h2>\n\n  <p>\n    First, <a href=\"https://docs.docker.com/installation/\">install\n    Docker</a>. Docker supports Windows, OS X, and Linux. Depending on\n    how you install Docker, you may need to prefix\n    all <code>docker</code> commands on this page\n    with <code>sudo</code> or run them as the root or administrative\n    user.\n  </p>\n  \n  <p>\n    With Docker installed, you should be able to download the Herbie image with:\n  </p>\n \n\n  <pre>docker pull uwplse/herbie</pre>\n  \n  <p>\n    You can now run Herbie:\n  </p>\n\n  <pre>docker run -it uwplse/herbie shell</pre>\n  \n  <p>\n    This will run the <a href=\"using-cli.html\">Herbie shell</a>,\n    reading input from the standard input.\n  </p>\n\n  <h2>Generating files and reports</h2>\n\n  <p>\n    To use Herbie in <a href=\"using-cli.html\">batch mode</a>, you will\n    need to mount the input in the Docker container. Do that with:\n  </p>\n  \n  <pre><strong>$</strong> docker run -it \\\n    -v <var>in-dir</var>:/in \\\n    -v <var>out-dir</var>:/out \\\n    -u $USER \\\n    uwplse/herbie improve /in/<var>in-file</var> /out/<var>out-file</var></pre>\n\n  <p>\n    In this command, you are asking Herbie to read input\n    from <var>in-file</var> in <var>in-dir</var>, and write output\n    to <var>out-file</var> in <var>out-dir</var>. The command looks\n    the same if you want Herbie to read input from a directory;\n    just leave <var>in-file</var> blank.\n  </p>\n\n  <p>\n    To generate reports from Herbie, you can run:\n  </p>\n\n  <pre><strong>$</strong> docker run -it \\\n    -v <var>in-dir</var>:/in \\\n    -v <var>out-dir</var>:/out \\\n    -u $USER \\\n    uwplse/herbie report /in/<var>in-file</var> /out/</pre>\n\n  <p>\n    As before, the input and output directories must be mounted inside\n    the Docker container. Note that both here and above, the user is\n    set to the current user. This is to ensure that the files Herbie creates\n    have the correct permissions set.\n  </p>\n\n  <h2>Running the web shell</h2>\n\n  <p>\n    Running the web shell in Docker requires exposing the ports inside\n    the container. Use the <code>-p</code> option to Docker to expose\n    whatever ports Herbie chooses to use, and then use\n    the <code>--port</code> option to Herbie to choose that port.\n  </p>\n\n  <pre><strong>$</strong> docker run -itp \\\n    uwplse/herbie web --quiet</pre>\n\n  <p>\n    Note that the <code>--quiet</code> flag is passed,\n    to prevent Herbie from attempting to start a web server\n    inside the Docker container.\n  </p>\n\n  <p>\n    If you are using the <code>--log</code>\n    or <code>--save-session</code> flags for the web shell,\n    you will also need to mount the relevant directories into the\n    Docker container using the <code>-v</code> Docker option, as in\n    the examples above.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.1/faq.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie FAQ</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n</head>\n<body>\n  <header>\n    <h1>Frequently Asked Questions</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"using-web.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> automatically transforms floating point\n    expressions into more accurate forms. This page catalogs questions\n    frequently asked questions about Herbie.\n  </p>\n\n  <h2>Troubleshooting common errors</h2>\n\n  <p>\n    Several Herbie error messages refer to this page for additional\n    information and debugging tips.\n  </p>\n\n  <h3 id=\"invalid-syntax\">“Invalid syntax” error</h3>\n\n  <p>\n    This error means you mis-formatted Herbie's input. Common errors\n    include misspelling function names and parenthesizing expressions\n    that must not be parenthesized. For example, in\n    <code>(- (exp (x)) 1)</code>, <code>(x)</code> is incorrect:\n    <code>x</code> is a variable so isn't parenthesized. <code>(- (exp\n    x) 1)</code> would be the correct way of writing that expression.\n    Please review the <a href=\"input.html\">input format</a>\n    documentation for more.\n  </p>\n\n  <h3 id=\"sample-valid-points\">“Cannot sample enough valid points” error</h3>\n\n  <p>\n    Herbie uses random sampling to select the points which it will use\n    to evaluate the error of an expression. This error occurs when it\n    is not able to find enough valid points. For example, consider the\n    expression <code>(acos (+ 1000 x))</code>. This expression yields\n    a valid result only when <code>x</code> is between -1001 and -999,\n    a rather narrow range.\n  </p>\n\n  <p>\n    The solution is to help out Herbie by specifying a precondition.\n    Specify <code>:pre (&lt; -1001 x -999)</code> for the example\n    above. Herbie will use the precondition to improve its sampling\n    strategy.\n  </p>\n\n  <h3 id=\"no-valid-values\">“No valid values” error</h3>\n\n  <p>\n    This error indicates that your precondition excludes all possible\n    inputs. For example, the precondition <code>(&lt 3 x 2)</code>\n    excludes all inputs. Herbie raises this exception only when it can\n    determine that no inputs work. The solution is to fix the\n    precondition to allow some inputs. Note that sufficiently complex\n    unsatisfiable preconditions instead raise the error above.\n  </p>\n\n  <h3>Missing reports chart on Chrome</h3>\n\n  <p>\n    When using Chrome to view web pages on your local machine, Chrome\n    disables certain APIs for security reasons; this prevents the\n    Herbie reports from drawing the chart. Run Chrome\n    with <code>--allow-file-access-from-files</code> to fix this error.\n  </p>\n\n  <h2>Reported but unreproduced errors</h2>\n\n  <p>\n    We've not been able to reproduce these errors, but\n    please <a href=\"https://github.com/uwplse/herbie/issues\">report an\n    issue</a>.\n\n  <h3>“place-channel-put” error with threads</h3>\n\n  <p>\n    <a href=\"https://github.com/uwplse/herbie/issues/145\">Some\n    users</a> report errors with using Herbie threads.\n  </p>\n\n  <h3>“tcp-write: error writing” error with web shell</h3>\n\n  <p>\n    Early versions of the web shell intermittently showed this error,\n    which seems to be due to the Racket web server library.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.1/input.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Input Format</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n</head>\n<body>\n  <header>\n    <h1>The Input Format</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"using-web.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a>'s input format is designed for\n    expressing mathematical functions, which Herbie can then search\n    for accurate implementations of. It also allows specifying the\n    distribution that Herbie draws inputs from when evaluating the\n    accuracy of an expression.\n  </p>\n  \n  <h2 id=\"sec1\">General format</h2>\n\n  <p>Herbie uses the <a href=\"http://fpbench.org\">FPCore</a> format\n  for its input expression, which looks like this:</p>\n\n  <pre>(FPCore (<var>inputs ...</var>) <var>properties ...</var> <var>expression</var>)</pre>\n\n  <p>\n    Each input is a variable, like <code>x</code>, which can be used\n    in the expression, whose accuracy Herbie will try to improve.\n    Properties are <a href=\"#properties\">described below</a>.\n  </p>\n\n  <p>\n    The expression is written in prefix form, with every function call\n    parenthesized, as in Lisp. For example, the formula for the\n    hypotenuse of a triangle with legs <i>a</i> and <i>b</i> is\n  </p>\n\n  <pre>(FPCore (a b) (sqrt (+ (sqr a) (sqr b))))</pre>\n\n  <p>\n    We recommend the <code>.fpcore</code> file extension for Herbie input files.\n  </p>\n  \n  <h2>Supported functions</h2>\n  \n  <p>\n    Herbie supports all functions\n    from <a href=\"http://pubs.opengroup.org/onlinepubs/7908799/xsh/math.h.html\">math.h</a>\n    with floating-point-only inputs and outputs. The best supported\n    functions, far from the full list, include:\n  </p>\n\n  <dl class=\"function-list\">\n    <dt><code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>, <code>fabs</code></dt>\n    <dd>The usual arithmetic functions<br/><code>-</code> is both negation and subtraction</dd>\n    <dt><code>sqr</code>, <code>sqrt</code></dt>\n    <dd>Squares and square roots</dd>\n    <dt><code>cube</code>, <code>cbrt</code></dt>\n    <dd>Cubes and cube roots</dd>\n    <dt><code>pow</code>, <code>exp</code>, <code>log</code></dt>\n    <dd>Various exponentiations and logarithms</dd>\n    <dt><code>sin</code>, <code>cos</code>, <code>tan</code></dt>\n    <dd>The trigonometric functions</dd>\n    <dt><code>asin</code>, <code>acos</code>, <code>atan</code>, <code>atan2</code></dt>\n    <dd>The inverse trigonometric functions</dd>\n    <dt><code>sinh</code>, <code>cosh</code>, <code>tanh</code></dt>\n    <dd>The hyperbolic functions</dd>\n    <dt><code>asinh</code>, <code>acosh</code>, <code>atanh</code></dt>\n    <dd>The inverse hyperbolic functions</dd>\n    <dt><code>fma</code>, <code>expm1</code>, <code>log1p</code>, <code>hypot</code></dt>\n    <dd>Specialized numeric functions</dd>\n  </dl>\n\n  <p>Herbie also supports the constants <code>PI</code> and <code>E</code>.</p>\n\n  <h2>Conditionals</h2>\n  \n  <p>FPCore uses <code>if</code> for conditional expressions:</p>\n\n  <pre>(if <var>cond</var> <var>if-true</var> <var>if-false</var>)</pre>\n\n  <p>\n    An <code>if</code> epxression evaluates the\n    conditional <code>cond</code> and returns either <code>if-true</code> if\n    it is true or <code>if-false</code> if it is not. Conditionals may use:\n  </p>\n  \n  <dl class=\"function-list\">\n    <dt><code>==</code>, <code>!=</code>, <code>&lt;</code>, <code>&gt;</code>, <code>&lt;=</code>, <code>&gt;=</code></dt>\n    <dd>The usual comparison operators</dd>\n    <dt><code>and</code>, <code>or</code>, <code>not</code></dt>\n    <dd>The usual logical operators</dd>\n  </dl>\n\n  <p>Note that unlike the arithmetic operators, these functions can take any number of arguments.</p>\n\n  <h2>Intermediate variables</h2>\n  \n  <p>Intermediate variables can be defined using <code>let</code>:</p>\n\n  <pre>(let ([<var>variable</var> <var>value</var>] <var>...</var>) <var>body</var>)</pre>\n\n  <p>\n    In a <code>let</code> expression, all the values are evaluated\n    first, and then are bound to their variables in the body. This\n    means that the value of one variable can't refer to another\n    variable in the same <code>let</code> block; nest <code>let</code>\n    constructs if you want to do that. Note that Herbie treats\n    intermediate values only as a notational convenience, and inlines\n    their values before improving the formula's accuracy. Using\n    intermediate variables will not help Herbie improve a formula's\n    accuracy or speed up its run-time.\n  </p>\n  \n  <h2 id=\"properties\">Properties</h2>\n\n  <p>Herbie also uses several FPCore properties for additional meta-data:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>:name <var>string</var></code></dt>\n    <dd>Herbie uses this name in its output</dd>\n    <dt><code>:pre <var>test</var></code></dt>\n    <dd>Herbie samples only points that pass the test</dd>\n    <dt>\n  </dl>\n\n  <p>\n    Several additional properties can be found in the benchmark suite\n    and are used for testing, but they are not supported and can\n    change without warning.\n  </p>\n\n  <h2>Converting from Herbie 0.9</h2>\n\n  <p>\n    Herbie 0.9 used a <a href=\"../0.9/input.html\">different input\n    format</a>, which is not supported Herbie 1.0 and later. To\n    simplify the transition, the <code>infra/convert.rkt</code> script\n    converts from the old to the new format.\n  </p>\n  \n  <p>To use the conversion tool, run:</p>\n\n  <pre>racket infra/convert.rkt <var>file.rkt</var> > <var>file.fpcore</var></pre>\n  \n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.1/installing.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Installing Herbie</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n</head>\n<body>\n  <header>\n    <h1>Installing Herbie</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"using-web.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> can be installed from a package or\n    from source. (It is also available in\n    a <a href=\"docker.html\">Docker</a> image.) To install Herbie, first install\n    <a href=\"https://racket-lang.org\">Racket</a>, which Herbie is\n    written in.\n  </p>\n\n  <h2>Installing Racket</h2>\n\n  <p>\n    Herbie currently supports Linux and OS X. (Windows has known bugs\n    we are working to resolve, due to the lack of a\n    full <code>math.h</code> library.) Use\n    the <a href=\"http://download.racket-lang.org/racket-v6.8.html\">official\n    installer</a> to install Racket, or use distro-provided packages\n    provided they are version 6.4 or later of Racket (earlier versions\n    are not supported).\n  </p>\n\n  <p>\n    Test that Racket is installed correctly and has a correct version:\n  </p>\n\n  <pre><strong>$</strong> racket\nWelcome to Racket v6.8.\n> (exit)</pre>\n  \n  <h2>Installing Herbie from a package</h2>\n\n  <p>Once Racket is installed, install Herbie with:</p>\n\n  <pre>raco pkg install herbie</pre>\n\n  <p>\n    This will install Herbie, compile it for faster startup, and place\n    an executable in your Racket user path, likely\n    into <code>~/.racket/6.8/</code>. If you add this directory to\n    your <code>PATH</code> you will be able to run herbie with\n    the <code>herbie</code> command.\n  </p>\n\n  <h2>Installing Herbie from source</h2>\n\n  <p>\n    Once Racket is installed, download the Herbie source\n    <a href=\"https://github.com/uwplse/herbie\">from GitHub</a> with:\n  </p>\n\n  <pre>git clone https://github.com/uwplse/herbie</pre>\n\n  <p>\n    If you go to the <code>herbie</code> directory,\n    you should see a <code>README.md</code> file, a directory named <code>src</code>,\n    a directory named <code>bench/</code>, and a few other directories.\n    Do a trial run of Herbie to make sure everything is installed and working correctly:\n  </p>\n\n  <pre>racket src/herbie.rkt report bench/tutorial.fpcore graphs/</pre>\n\n  <p>\n    This command will take approximately a minute to run.\n    After the command completes,\n      a directory named <code>graphs</code> should be created.\n    Open the <code>report.html</code> file inside with your browser;\n      you will see a listing of the expressions Herbie was run on,\n      all of which should be green.\n    If not, please check that your Racket installation is at least version 6.4,\n      and if the error still persists,\n      please <a href=\"https://github.com/uwplse/herbie/issues\">submit a bug</a>.\n  </p>\n\n  <p>You can make Herbie start up faster by byte-compiling it:</p>\n\n  <pre>raco make src/herbie.rkt</pre>\n\n  <p>\n    Once Herbie is installed and working correctly,\n    check out the <a href=\"tutorial.html\">tutorial</a>.\n  </p>\n\n  <h2>Installing Herbie from Docker</h2>\n\n  <p>\n    <a href=\"https://docker.com\">Docker</a> is a container manager,\n    which is sort of like an easily-scriptable virtual machine. We do\n    not recommend using Herbie through Docker without prior Docker\n    experience.\n  </p>\n\n  <p>\n    First, <a href=\"https://docs.docker.com/installation/\">install\n    Docker</a>. Docker supports Windows, OS X, and Linux. Depending on\n    how you install Docker, you may need to prefix\n    all <code>docker</code> commands on this page\n    with <code>sudo</code> or run them as the root or administrative\n    user.\n  </p>\n\n  <p>\n    With Docker installed, you should be able to download the Herbie image with:\n  </p>\n \n  <pre>docker pull uwplse/herbie</pre>\n  \n  <p>\n    Check out the <a href=\"docker.html\">Docker page</a> for more on\n    how to run Herbie with Docker.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.1/options.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Command-line Options</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n</head>\n<body>\n  <header>\n    <h1>Command-line Options</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"using-web.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    The <a href=\"../../\"><code>herbie</code></a> command has several\n    subcommands and allows multiple options that influence its search\n    procedure and the types of solutions it finds. These options apply\n    both to the report generator and the one-off command-line tool.\n  </p>\n\n  <h2>Herbie commands</h2>\n\n  <p>Herbie can be run both interactively and in batch mode, and can\n  generate output intended either for the command line or the web. We\n  call these different ways of running Herbie different tools. Herbie\n  provides four tools:</p>\n\n  <dl>\n    <dt><code>herbie web</code></dt>\n    <dd>Use Herbie through your browser. <code>herbie web</code>\n    starts a web server for running Herbie on your local machine, and\n    directs a browser to visit that server.</dd>\n\n    <dt><code>herbie shell</code></dt>\n    <dd>Starts a command-line interactive shell for using Herbie.\n    Enter an <a href=\"input.html\">FPCore expression</a> and Herbie\n    will print its more-accurate version.</dd>\n\n    <dt><code>herbie improve input output</code></dt>\n    <dd>Runs Herbie on the expressions in the <code>input</code> file\n    or directory, and outputs the result to <code>output</code>, which\n    will be a single file of FPCore outputs.</dd>\n\n    <dt><code>herbie report input output</code></dt>\n    <dd>Runs Herbie on the expressions in the <code>input</code> file\n    or directory, and produces a directory of HTML web pages that\n    describe Herbie's output, how it derived that output, and\n    additional charts and information about the improvement process.\n    These pages can be viewed in any browser (though with\n    a <a href=\"faq.html\">quirk</a> for Chrome).</dd>\n  </dl>\n\n  <p>We recommend using the web tools, <code>web</code>\n  and <code>report</code>, since HTML allows Herbie to give you more\n  information about how and why it improved a floating-point\n  expression's accuracy. Particularly useful are the graphs it\n  produces of error versus input, which can help you understand\n  whether Herbie's improvements matter for your user cases.</p>\n\n  <p>For any tool, you can run <code>herbie <var>tool</var> --help</code>\n    to see a listing of all available command-line options. This listing\n    will include unsupported options not listed on this page.</p>\n\n  <h2>Upgrading from Herbie 1.0</h2>\n\n  <p>Herbie 1.0 used\n  a <a href=\"../1.0/using-herbie.html\">different</a> command line\n  syntax, without multiple tools. Translate like so:</p>\n\n  <ul>\n    <li><code>herbie-1.0</code> → <code>herbie-1.1 shell</code></li>\n    <li><code>herbie-1.0 file</code> → <code>herbie-1.1 improve file -</code></li>\n    <li><code>herbie-1.0 files ...</code> → <code>cat files ... | herbie-1.1 improve - -</code><br/>\n      Alternatively, collect the files into a directory and run <code>herbie-1.1 improve dir/ -</code></li>\n  </ul>\n\n  <p>The new syntax somewhat changes Herbie's behavior, such as by\n    using the input expression as the output if Herbie times out. It\n    also makes it easier to write Herbie's output to a file without\n    using command-line redirection. The old syntax still works but is\n    deprecated and will be removed in the next release.</p>\n\n  <h2>General options</h2>\n\n  <p>\n    These options can be set on any tool. Pass them after the tool\n    name but before other arguments, such as:\n  </p>\n\n  <pre><code>herbie improve --timeout 60 in.fpcore out.fpcore</code></pre>\n\n  <p>Arguments cannot be put anywhere else.</p>\n\n  <dl>\n    <dt><code>--seed S</code></dt>\n    <dd>The random seed, which changes the randomly-selected points\n      that Herbie evaluates candidate expressions on. The format of\n      the seed is that used by the\n      Racket <code>vector->pseudo-random-generator!</code> function;\n      in practice, just use a seed produced by an earlier run. This\n      option can be used to make Herbie's results reproducible or to\n      compare two different runs.</dd>\n\n    <dt><code>--num-iters N</code></dt>\n    <dd>The number of improvements Herbie attempts to make to the\n      program. The default, 2, suffices for most programs and helps\n      keep Herbie fast. If this is set very high, Herbie may run out\n      of things to do and terminate before the given number of\n      iterations, but in practice iterations beyond the first few\n      rarely lead to lower error. This option can be increased to 3 or\n      4 to check that there aren't further improvements that Herbie\n      could seek out.</dd>\n\n    <dt><code>--num-points N</code></dt>\n    <dd>The number of randomly-selected points used to evaluate\n      candidate expressions. The default, 256, gives good behavior for\n      most programs. The more points sampled, the slower Herbie is.\n      This option can be increased to 512 or 1024 if Herbie gives very\n      inconsistent results between runs with different seeds.</dd>\n    \n    <dt><code>--timeout T</code></dt>\n    <dd>The timeout to use per-example, in seconds. A fractional\n    number of seconds can be given.</dd>\n\n    <dt><code>--threads N</code>, for <code>improve</code> and <code>reports</code></dt>\n    <dd>Enables multi-threaded operation. By default, no threads are\n      used. A number can be passed to this option to use that many\n      threads, or <code>yes</code> can be passed to tell Herbie to use\n      all but one of the hardware threads.</dd>\n  </dl>\n\n  <h2>Web shell options</h2>\n  \n  <p>The <code>web</code> tool runs Herbie as a web server, and\n  connects to it from your browser. It has additional options to\n  control this server.</p>\n  \n  <dl>\n    <dt><code>--port N</code></dt>\n    <dd>The port to run the Herbie server on. The default port is 8000.</dd>\n\n    <dt><code>--save-session dir</code></dt>\n    <dd>Save all the reports for expressions enterred into the web\n    shell to this directory. The directory is also used as a\n    cache of already-computed expressions.</dd>\n\n    <dt><code>--log file</code></dt>\n    <dd>Write a web access log to this file. The file is formatted\n    similarly to Apache logs. If Herbie crashes for some reason, this\n    log will <emph>not</emph> contain a traceback.</dd>\n\n    <dt><code>--quiet</code></dt>\n    <dd>When set, a browser is not started to point to the server main\n    page, and a smaller banner is printed to the command line.</dd>\n  </dl>\n\n  <h2>Search options</h2>\n\n  <p>\n    These options influence the fine properties of Herbie's search, most\n    importantly the types of transformations that Herbie uses to find\n    candidate programs. These options offer very fine-grained control\n    over Herbie's output, and are only recommended for advanced uses of\n    Herbie.\n  </p>\n\n  <p>\n    Each option can be turned off with the <code>-o X</code>\n    or <code>--disable X</code> command-line flag, and turned on with\n    the <code>+o X</code> or <code>--enable X</code>. The defaults are\n    the recommended options; turning a default-on option off typically\n    results in less-accurate results, while turning a default-off\n    option on typically results in more-complex and more-surprising\n    output expressions.\n  </p>\n\n  <dl>\n    <dt><code>precision:double</code></dt>\n    <dd>This option, on by default, tells Herbie to treat its input as\n      double-precision calculations. If turned off, Herbie treats its\n      input as a single-precision calculation.</dd>\n\n    <dt><code>setup:simplify</code></dt>\n    <dd>This option, on by default, simplifies the expression before\n      passing it to Herbie. If turned off, Herbie will not simplify\n      input programs before improving them. You will want to turn off\n      this option if simplifying the program will create a lot of\n      error, say if the association of operations is cleverly\n      chosen.</dd>\n\n    <dt><code>setup:early-exit</code></dt>\n    <dd>This option, off by default, causes Herbie to exit without\n      modifying the input program if it determines that the input\n      program has less than 0.1 bits of error. You will want to turn\n      this option on if you are running Herbie on a large corpus of\n      programs that you do not believe to be inaccurate.</dd>\n\n    <dt><code>generate:rr</code></dt>\n    <dd>This option, on by default, uses Herbie's recursive rewriting\n      algorithm to generate candidate programs. If turned off, Herbie\n      will use a non-recursive rewriting algorithm, which will\n      substantially limit the candidates Herbie finds. You will rarely\n      want to turn this option off.</dd>\n\n    <dt><code>generate:taylor</code></dt>\n    <dd>This option, on by default, uses series expansion to produce\n      new candidates during the main improvement loop. If turned off,\n      Herbie will not use series expansion in the main improvement loop.\n      You will want to turn this option off if you want to avoid\n      series-expansion-based rewrites, such as if you need to preserve\n      the equivalence of the input and output expressions as real-number\n      formulas.</dd>\n\n    <dt><code>generate:simplify</code></dt>\n    <dd>This option, on by default, simplifies candidates during the\n      main improvement loop. If turned off, candidates will not be\n      simplified, which typically results in much less accurate\n      expressions, since simplification is often necessary for\n      cancelling terms. You will rarely want to turn this option off.</dd>\n\n    <dt><code>reduce:regimes</code></dt>\n    <dd>This option, on by default, uses Herbie's regime inference\n      algorithm to branch between several program candidates. If\n      turned off, branches will not be inferred and the output program\n      will be straight-line code (if the input was). You will want to\n      turn this option off if your programming environment makes\n      branches very expensive, such as in some cases of GPU\n      programming.</dd>\n\n    <dt><code>reduce:taylor</code></dt>\n    <dd>This option, on by default, uses a final set of series\n      expansions after all improvements have been made. This sometimes\n      improves accuracy further. If turned off, this final series\n      expansion pass will not be done. You will want to turn this\n      option off if you want to avoid series-expansion-based rewrites,\n      such as if you need to preserve the equivalence of the input and\n      output expressions as real-number formulas.</dd>\n\n    <dt><code>reduce:simplify</code></dt>\n    <dd>This option, on by default, uses a final simplification pass\n      after all improvements have been made. This sometimes improves\n      accuracy further. If turned off, this final simplification pass\n      will not be done. You will rarely want to turn this option\n      off.</dd>\n\n    <dt><code>reduce:avg-error</code></dt>\n    <dd>This option, on by default, causes Herbie to output the\n      candidate with the best average error over the chosen inputs. If\n      turned off, Herbie will choose the candidate with the least\n      maximum error instead. This usually produces programs with worse\n      overall accuracy. You may want to turn this option off if\n      worst-case accuracy is more important to you than overall\n      accuracy.</dd>\n\n    <dt><code>rules:arithmetic</code></dt>\n    <dd>This option, on by default, allows Herbie to use basic\n      arithmetic facts during its search. If turned off, Herbie will\n      not be able to use those facts. You will rarely want to turn\n      this option off.</dd>\n\n    <dt><code>rules:polynomials</code></dt>\n    <dd>This option, on by default, allows Herbie to use facts\n      about polynomials during its search. If turned off, Herbie will\n      not be able to use those facts. You will rarely want to turn\n      this option off.</dd>\n\n    <dt><code>rules:fractions</code></dt>\n    <dd>This option, on by default, allows Herbie to use facts about\n      fractions during its search. If turned off, Herbie will not be\n      able to use those facts. You will rarely want to turn this\n      option off.</dd>\n\n    <dt><code>rules:exponents</code></dt>\n    <dd>This option, on by default, allows Herbie to use facts about\n      exponents during its search. If turned off, Herbie will not be\n      able to use those facts. You may want to turn this option off in\n      the rare case that you do not want exponents or logarithms\n      used in Herbie's output expressions, which may be the case when\n      code runtime is more important than accuracy.</dd>\n\n    <dt><code>rules:trigonometry</code></dt>\n    <dd>This option, on by default, allows Herbie to use basic\n      trigonometry facts during its search. If turned off, Herbie will\n      not be able to use those facts. You may want to turn this option\n      off in the rare case that you do not want trigonometric\n      functions used in Herbie's output expressions, which may be the\n      case when code runtime is more important than accuracy.</dd>\n\n    <dt><code>rules:numerics</code></dt>\n    <dd>This option, off by default, allows Herbie to use special\n      numerical functions. If turned off, Herbie will not be able to\n      use these functions. You will want to turn this option on if\n      these functions (currently <code>expm1</code>, <code>log1p</code>,\n      and <code>hypot</code>) are available in your language.</dd>\n  </dl>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.1/release-notes.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie 1.1 Release Notes</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <script src=\"https://d3js.org/d3.v3.min.js\" charset=\"utf-8\"></script>\n  <script type=\"text/javascript\" src=\"compare.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Herbie 1.1 Release Notes</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"using-web.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    After six months of work, the <a href=\"../..\">Herbie</a> developers\n    are excited to announce Herbie 1.1! This release focuses on making\n    Herbie easier to use, including a web interface, clear syntax\n    errors, and detailed reports. This release also expands support\n    for trigonometric and hyperbolic functions, and speeds up\n    preconditions.\n  </p>\n\n  <p>\n    Herbie automatically improves the accuracy of floating point\n    expressions. This avoids the bugs, errors, and surprises that so\n    often occur when working with floating point. Since\n    our <a href=\"../../papers.html\">PLDI'15 paper</a>, we've been hard at\n    work making Herbie more versatile and easier to use.\n  </p>\n\n  <img width=\"100%\" src=\"team.png\" style=\"display: block; margin: 4em 0;\" />\n\n  <h2>Breaking Changes and Deprecations</h2>\n\n  <ul>\n    <li> In line\n    with <a href=\"http://fpbench.org/spec/fpcore-1.0.html\">FPCore\n    1.0</a>, we have removed support for the <code>cotan</code>\n    function, renamed <code>=</code> to <code>==</code>, and added\n    the <code>!=</code> function.</li>\n    <li>In line with the new syntax for calling Herbie from the\n    command line, the old syntax is deprecated and will be removed in\n    the next version.</li>\n    <li>In line with the faster preconditions, we have deprecated\n    the <code>:herbie-samplers</code> property and will remove it in\n    the next release.</li>\n    <li>We have changed the syntax for\n    specifying <a href=\"options.html\">search options</a> for Herbie.\n    Instead of using <code>-o</code> to toggle options,\n    use <code>-o</code> to disable options and <code>+o</code> to\n    enable them.</li>\n  </ul>\n\n  <h2>Usability improvements</h2>\n\n  <ul>\n    <li><a href=\"using-web.html#batch\">HTML reports</a>. Herbie can\n      now generate reports that show graphs, describe how Herbie\n      achieved its result, and more.</li>\n    <li><a href=\"using-web.html#interactive\">Web shell</a>. The\n      old <a href=\"/demo/\">web demo</a> has been cleaned up and made\n      available to users, providing a graphical interface to\n      Herbie.</li>\n    <li><a href=\"using-cli.html#batch\">Batch mode</a>. It's now\n      simpler to run Herbie on an FPCore file and save the results in\n      an output file.\n      The <a href=\"using-cli.html#interactive\">command-line shell</a>\n      is also more user-friendly.</li>\n    <li>Easier <a href=\"installing.html\">installation</a> using\n      the Racket package manager.</li>\n    <li>Simpler, clearer syntax errors. Instead of stack traces,\n      syntax errors now come with file, line, and column\n      information.</li>\n  </ul>\n\n  <figure class=\"showcase\" style=\"background: white; border: 1px solid gray;\">\n    <style scoped>\n      line { pointer-events: all; }\n      .old, .new { stroke-width: 3px; stroke-opacity: 1.0; fill-opacity: 1.0; }\n      .old { stroke: lightgray; fill: lightgray; }\n      .new { stroke: darkgreen; fill: darkgreen; }\n      .gridline, .guide { stroke: lightgray; }\n      text { text-anchor: middle; }\n    </style>\n    <svg id=\"results\" width=\"525\" height=\"320\"></svg>\n    <script>draw_results(d3.select(\"#results\"))</script>\n    <figcaption>Improvement on the Hamming benchmarks from Herbie 1.0 to Herbie 1.1. The improved series expansions, expanded trigonometric and hyperbolic knowledge, and miscellaneous bug fixes have made Herbie smarter.</figcaption>\n  </figure>\n\n  <h2>Improvement to core algorithm</h2>\n\n  <ul>\n    <li>Faster preconditions. A precondition like <code>(&lt; 10 x\n      12)</code> now causes Herbie to only sample points in the\n      relevant range, significantly speeding up Herbie and obviating\n      many \"cannot sample enough valid points\" errors.</li>\n    <li>Better support for trigonometric and hyperbolic functions.\n      We've taught Herbie about many trigonometric identities, which\n      it can now use to improve expressions.</li>\n    <li>Better series expansion. We've taught Herbie to take series\n      expansions of many more functions.</li>\n    <li>Zero-argument expressions are now supported.</li>\n  </ul>\n\n  <h2>Code Cleanup</h2>\n\n  <ul>\n    <li>We have a new, right-facing logo!</li>\n    <li>We now have a complete syntax checker for inputs, giving the\n      Herbie core confidence that it's dealing with valid expressions.</li>\n    <li>The infrastructure for generating reports has been cleaned up.</li>\n    <li>The web demo has been rearchitected. It no longer needs to\n      output files, no longer uses continuations, and is now much more configurable.</li>\n    <li>The new command-line syntax unifies the mess of invokable\n      scripts in Herbie. We will continue the unification in future\n      releases.</li>\n    <li>More unit tests continue to be written, and including a test\n      that ensures that all our rules are valid.</il>\n  </ul>\n  \n  <h2>Try it out!</h2>\n\n  <p>\n    We're excited to continue to improve Herbie and make it more\n    useful to scientists, engineers, and programmers around the world.\n    We've got a lot of features we're excited to work on in the coming\n    months. Please\n    <a href=\"https://github.com/uwplse/herbie/issues\">report bugs</a>,\n    join\n    <a href=\"https://mailman.cs.washington.edu/mailman/listinfo/herbie\">the\n    mailing list</a>,\n    or <a href=\"https://github.com/uw-plse/herbie\">contribute</a>.\n  </p>\n  \n  <p><em style=\"font-weight: bold; font-style: roman;\">If you find Herbie useful, <a href=\"mailto:herbie@cs.washington.edu\">let us know!</em></p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.1/report.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie reports</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n</head>\n<body>\n  <header>\n    <h1>Herbie reports</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"using-web.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  \n  <h1>The Herbie report</h1>\n\n  <p>The Herbie report, which is output by\n  the <a href=\"using-web.html\">Herbie web commands</a>, lists five items.</p>\n\n  <p>First, a brief summary of the results.\n    For most uses, the “Average Error”\n      number, which summarizes how accurate the input and output\n      expressions are, is the most important number in this section.\n    The other numbers are:\n      the time Herbie took to improve the program;\n      the precision Herbie assumed floating-point operations\n      (which can be set at the <a href=\"options.html\">command line</a>);\n      and the internal precision used to ensure accurate results.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-large.png\" />\n    <figcaption>A summary of results from a Herbie report.</figcaption>\n  </figure>\n\n  <p>Second, the input and output programs themselves.\n    These are printed in standard mathematical syntax.\n    Library functions not often used by mathematicians,\n      including <code>atan2</code>, <code>expm1</code>,\n      <code>fma</code>, <code>hypot</code>, <code>lgamma</code>,\n      <code>log1p</code>, and <code>logb</code>\n      are drawn with a sub- or super-script asterisk,\n      while <code>if</code> statements are rendered as in a program.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-prog.png\" />\n    <figcaption>Input and output program from a Herbie report.</figcaption>\n  </figure>\n\n  <p>\n    Third, under <em>Error</em>, a graph of floating-point error\n    versus input value. This is helpful for understanding the sorts of\n    inputs Herbie is improving accuracy on. Sometimes, Herbie improved\n    accuracy on some inputs at the cost of accuracy on other inputs\n    that you care more about. In these cases, you can add\n    a <code>:pre</code>condition to restrict the inputs Herbie reasons\n    about.\n  </p>\n\n  <p>\n    On these graphs, the red line is the error of the input program,\n    while the blue line is the error of the output program\n    (both can be toggled).\n    For expressions with multiple variables,\n    the variable on the horizontal axis can be selected.\n    If Herbie decided to insert\n    an <code>if</code> statement into the program,\n    the locations of those <code>if</code> statements\n    will be marked with vertical bars.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-error.png\" />\n    <figcaption>An error graph from a Herbie report. Note the variable\n    selector (<code>x</code> is selected) and the toggles for the\n    input and output program (both are toggled on).</figcaption>\n  </figure>\n\n  <p>Fourth, a derivation of the output from the input.\n    For complex or unexpected programs, these can be helpful.\n    Each substantive step in the derivation also lists the error,\n    in bits, of that step's output.</p>\n\n  <p>The derivations may name rules built into Herbie,\n    or may claim derivation steps are done by simplification,\n    series expansion, or other Herbie strategies. The derivation will\n    also call out splits of the input into regimes, and strategies\n    Herbie is invoking. When one part of the term is colored blue,\n    that is the only part of the term modified by the operation.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-derivation.png\" />\n    <figcaption>A short derivation from a Herbie report. Note the\n    error at each step, in bits, in gray.</figcaption>\n  </figure>\n  \n  <p>Fifth and finally, a breakdown of Herbie's runtime.\n    This can usually be ignored.\n    The colored bar is a timeline of Herbie's run,\n    with each section of the bar sized proportionally to its runtime,\n    and each color corresponding to a strategy;\n    hover over that section of the bar to learn which strategy.</p>\n\n  <p>If you find a bug, include the code snippet in this section when\n  filing the bug. Please also include the debug log linked from this block.</p>\n    \n  <figure>\n    <img width=\"100%\" src=\"report-runtime.png\" />\n    <figcaption>Runtime breakdown from a Herbie report.</figcaption>\n  </figure>\n\n  <p>We expect the report to grow more informative with future\n  versions. Please <a href=\"mailto:herbie@cs.washington.edu\">get in\n  touch</a> if there is more information you'd like to see.</p>\n\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.1/results-new.json",
    "content": "{\"flags\":[\"precision:double\",\"setup:simplify\",\"reduce:regimes\",\"reduce:taylor\",\"reduce:simplify\",\"reduce:avg-error\",\"rules:arithmetic\",\"rules:polynomials\",\"rules:fractions\",\"rules:exponents\",\"rules:trigonometry\",\"rules:hyperbolic\",\"generate:rr\",\"generate:taylor\",\"generate:simplify\"],\"seed\":\"#(772101555 1905824529 294602591 2478279198 2123125427 4197813737)\",\"points\":256,\"date\":1493418730,\"commit\":\"a6770931126e0702f83b80fffb3cdf362d9e07c9\",\"branch\":\"develop\",\"iterations\":3,\"note\":false,\"bit_width\":64,\"tests\":[{\"bits\":1408,\"start\":39.78563602870575,\"input\":\"(sqrt (/ (- (exp (* 2 x)) 1) (- (exp x) 1)))\",\"output\":\"(sqrt (/ (+ (exp x) 1) 1))\",\"link\":\"0-sqrtexpproblem344\",\"ninf\":0,\"pinf\":0,\"end-est\":0.0078125,\"name\":\"sqrtexp (problem 3.4.4)\",\"samplers\":[\"default\"],\"time\":53697.2470703125,\"status\":\"imp-start\",\"vars\":[\"x\"],\"target\":false,\"end\":0.014412722522414014},{\"bits\":2432,\"start\":31.277522201292555,\"input\":\"(/ (- x (sin x)) (- x (tan x)))\",\"output\":\"(if (<= x -9.950485992669078e-09) (- (/ x (- x (tan x))) (/ (sin x) (- x (tan x)))) (if (<= x 0.16631490308113306) (- (* 9/40 (sqr x)) (+ (* 27/2800 (pow x 4)) 1/2)) (/ (- x (sin x)) (- x (tan x)))))\",\"link\":\"1-sintanproblem345\",\"ninf\":0,\"pinf\":0,\"end-est\":0.36733237039018785,\"name\":\"sintan (problem 3.4.5)\",\"samplers\":[\"default\"],\"time\":135208.11889648438,\"status\":\"imp-start\",\"vars\":[\"x\"],\"target\":false,\"end\":0.1040637469913252},{\"bits\":2432,\"start\":36.53944527020705,\"input\":\"(/ (+ (- b/2) (sqrt (- (sqr b/2) (* a c)))) a)\",\"output\":\"(if (<= b/2 -1.751131060884064e+136) (* -2 (/ b/2 a)) (if (<= b/2 8.548826144111727e-60) (/ 1 (/ a (+ (- b/2) (sqrt (- (sqr b/2) (* a c)))))) (- (/ (+ b/2 (- b/2)) a) (/ (* 1/2 c) b/2))))\",\"link\":\"2-quad2pproblem321positive\",\"ninf\":0,\"pinf\":0,\"end-est\":8.759031935807828,\"name\":\"quad2p (problem 3.2.1, positive)\",\"samplers\":[\"default\",\"default\",\"default\"],\"time\":119061.97412109375,\"status\":\"imp-start\",\"vars\":[\"a\",\"b/2\",\"c\"],\"target\":false,\"end\":5.966762651991987},{\"bits\":2944,\"start\":37.82838784287472,\"input\":\"(/ (- (- b/2) (sqrt (- (sqr b/2) (* a c)))) a)\",\"output\":\"(if (<= b/2 -3.093544874321455e-77) (* (/ -1/2 b/2) c) (if (<= b/2 5.845042913155354e+61) (/ 1 (/ a (- (- b/2) (sqrt (- (sqr b/2) (* a c)))))) (+ (* (/ c b/2) 1/2) (/ (- (- b/2) b/2) a))))\",\"link\":\"3-quad2mproblem321negative\",\"ninf\":0,\"pinf\":0,\"end-est\":8.241281491524308,\"name\":\"quad2m (problem 3.2.1, negative)\",\"samplers\":[\"default\",\"default\",\"default\"],\"time\":126471.29907226562,\"status\":\"imp-start\",\"vars\":[\"a\",\"b/2\",\"c\"],\"target\":false,\"end\":5.326392364138352},{\"bits\":2432,\"start\":31.059705602958424,\"input\":\"(/ (- 1 (cos x)) (sqr x))\",\"output\":\"(* (/ (sin x) x) (/ (/ (sin x) (+ 1 (cos x))) x))\",\"link\":\"4-cos2problem341\",\"ninf\":0,\"pinf\":0,\"end-est\":0.3600447888363383,\"name\":\"cos2 (problem 3.4.1)\",\"samplers\":[\"default\"],\"time\":82701.72485351562,\"status\":\"imp-start\",\"vars\":[\"x\"],\"target\":false,\"end\":0.27141353358701925},{\"bits\":1408,\"start\":31.55214583076247,\"input\":\"(- (pow (+ x 1) (/ 1 n)) (pow x (/ 1 n)))\",\"output\":\"(if (<= n -2.672258838309128e-11) (- (- (/ (/ 1 x) n) (/ (/ 1/2 n) (sqr x))) (/ (log x) (* n (* n x)))) (if (<= n 19699878403.887928) (exp (cube (cbrt (log (- (pow (+ x 1) (/ 1 n)) (pow x (/ 1 n))))))) (- (- (/ (/ 1 x) n) (/ (/ 1/2 n) (sqr x))) (/ (log x) (* n (* n x))))))\",\"link\":\"5-2nthrtproblem346\",\"ninf\":0,\"pinf\":0,\"end-est\":21.21301382692941,\"name\":\"2nthrt (problem 3.4.6)\",\"samplers\":[\"default\",\"default\"],\"time\":143232.169921875,\"status\":\"imp-start\",\"vars\":[\"x\",\"n\"],\"target\":false,\"end\":6.774720844192645},{\"bits\":1408,\"start\":40.755841804999065,\"input\":\"(- (log (+ N 1)) (log N))\",\"output\":\"(if (<= N 9328.390986348908) (log (/ (+ N 1) N)) (+ (/ (- (/ 1/3 N) 1/2) (sqr N)) (/ 1 N)))\",\"link\":\"6-2logproblem336\",\"ninf\":0,\"pinf\":0,\"end-est\":0.11448705279133702,\"name\":\"2log (problem 3.3.6)\",\"samplers\":[\"default\"],\"time\":41444.029052734375,\"status\":\"imp-start\",\"vars\":[\"N\"],\"target\":false,\"end\":19.49352325492048},{\"bits\":896,\"start\":14.049500988425633,\"input\":\"(- (/ 1 (+ x 1)) (/ 1 x))\",\"output\":\"(if (<= x -209135036385.79047) (- (/ 1 (pow x 3)) (+ (pow x (- 2)) (/ 1 (pow x 4)))) (if (<= x 290639.63932394225) (/ (- x (+ 1 x)) (* (+ x 1) x)) (- (/ 1 (pow x 3)) (+ (pow x (- 2)) (/ 1 (pow x 4))))))\",\"link\":\"7-2fracproblem331\",\"ninf\":0,\"pinf\":0,\"end-est\":0.0234375,\"name\":\"2frac (problem 3.3.1)\",\"samplers\":[\"default\"],\"time\":30894.91796875,\"status\":\"imp-start\",\"vars\":[\"x\"],\"target\":false,\"end\":0.014198120312590145},{\"bits\":2432,\"start\":38.890098631337246,\"input\":\"(- (cos (+ x eps)) (cos x))\",\"output\":\"(if (<= eps -3.645937152382937e+19) (- (- (* (cos x) (cos eps)) (* (sin x) (sin eps))) (cos x)) (if (<= eps 4.729663737457019e-05) (* -2 (* (sin (/ eps 2)) (sin (/ (+ (+ x eps) x) 2)))) (- (* (cos x) (cos eps)) (+ (* (sin x) (sin eps)) (cos x)))))\",\"link\":\"8-2cosproblem335\",\"ninf\":0,\"pinf\":0,\"end-est\":0.6303043448114194,\"name\":\"2cos (problem 3.3.5)\",\"samplers\":[\"default\",\"default\"],\"time\":104279.31079101562,\"status\":\"imp-start\",\"vars\":[\"x\",\"eps\"],\"target\":false,\"end\":1.2578573335845715},{\"bits\":1408,\"start\":29.805220676286638,\"input\":\"(- (pow (+ x 1) (/ 1 3)) (pow x (/ 1 3)))\",\"output\":\"(/ 1 (+ (sqr (pow (+ x 1) (/ 1 3))) (+ (sqr (exp (/ (log x) 3))) (* (pow (+ x 1) (/ 1 3)) (pow x (/ 1 3))))))\",\"link\":\"9-2cbrtproblem334\",\"ninf\":0,\"pinf\":0,\"end-est\":2.8592450383022707,\"name\":\"2cbrt (problem 3.3.4)\",\"samplers\":[\"default\"],\"time\":86841.42700195312,\"status\":\"imp-start\",\"vars\":[\"x\"],\"target\":false,\"end\":2.63051098758136},{\"bits\":2432,\"start\":30.222464775570813,\"input\":\"(/ (- 1 (cos x)) (sin x))\",\"output\":\"(* 1 (/ (sin x) (+ (cos x) 1)))\",\"link\":\"10-tanhfexample34\",\"ninf\":0,\"pinf\":0,\"end-est\":0.5284202760025005,\"name\":\"tanhf (example 3.4)\",\"samplers\":[\"default\"],\"time\":51172.2109375,\"status\":\"eq-target\",\"vars\":[\"x\"],\"target\":0.000625,\"end\":0.4384920000497587},{\"bits\":2432,\"start\":34.16168973131298,\"input\":\"(/ (+ (- b) (sqrt (- (sqr b) (* 4 (* a c))))) (* 2 a))\",\"output\":\"(if (<= b -1.751131060884064e+136) (/ (- b) a) (if (<= b -5.335815531470738e-240) (/ 1 (/ (* 2 a) (+ (- b) (sqrt (- (sqr b) (* 4 (* a c))))))) (if (<= b 5.845042913155354e+61) (/ 1 (* (- (- b) (sqrt (- (* b b) (* (* 4 a) c)))) (/ (/ 2 4) c))) (- (/ (+ b (- b)) (+ a a)) (/ c b)))))\",\"link\":\"11-quadpp42positive\",\"ninf\":0,\"pinf\":0,\"end-est\":6.078206418658915,\"name\":\"quadp (p42, positive)\",\"samplers\":[\"default\",\"default\",\"default\"],\"time\":124200.916015625,\"status\":\"gt-target\",\"vars\":[\"a\",\"b\",\"c\"],\"target\":21.51568349447677,\"end\":5.376176978102462},{\"bits\":2944,\"start\":34.438091592742474,\"input\":\"(/ (- (- b) (sqrt (- (sqr b) (* 4 (* a c))))) (* 2 a))\",\"output\":\"(if (<= b -2.049536640230252e+150) (/ (* (/ c 2) 4) (- (/ (+ c c) (/ b a)) (- b (- b)))) (if (<= b 3.902728914492509e-158) (* (/ 4 2) (/ c (+ (- b) (sqrt (- (* b b) (* a (* c 4))))))) (if (<= b 5.845042913155354e+61) (/ 1 (/ (* 2 a) (- (- b) (sqrt (- (sqr b) (* 4 (* a c))))))) (- (/ c b) (/ b a)))))\",\"link\":\"12-quadmp42negative\",\"ninf\":0,\"pinf\":0,\"end-est\":5.090534681871955,\"name\":\"quadm (p42, negative)\",\"samplers\":[\"default\",\"default\",\"default\"],\"time\":127442.75390625,\"status\":\"gt-target\",\"vars\":[\"a\",\"b\",\"c\"],\"target\":21.537857357826326,\"end\":5.5027912650509085},{\"bits\":1408,\"start\":61.40424674064236,\"input\":\"(/ (log (- 1 x)) (log (+ 1 x)))\",\"output\":\"(- (+ (* 1/2 (sqr x)) (+ 1 x)))\",\"link\":\"13-qlogexample310\",\"ninf\":0,\"pinf\":0,\"end-est\":0.5716777813221573,\"name\":\"qlog (example 3.10)\",\"samplers\":[\"default\"],\"time\":22658.823974609375,\"status\":\"eq-target\",\"vars\":[\"x\"],\"target\":0.4463297341631591,\"end\":0.008125},{\"bits\":1408,\"start\":63.323661641605746,\"input\":\"(- (- (* (+ n 1) (log (+ n 1))) (* n (log n))) 1)\",\"output\":\"(- (* (log (+ n 1)) (+ n 1)) (+ (* (log n) (- n)) 1))\",\"link\":\"14-logsexample38\",\"ninf\":0,\"pinf\":0,\"end-est\":60.73435355682203,\"name\":\"logs (example 3.8)\",\"samplers\":[\"default\"],\"time\":43125.350830078125,\"status\":\"gt-target\",\"vars\":[\"n\"],\"target\":60.78763823817359,\"end\":0.2685},{\"bits\":1408,\"start\":59.443513693513,\"input\":\"(log (/ (- 1 eps) (+ 1 eps)))\",\"output\":\"(- (+ (* 2/3 (pow eps 3)) (+ (* 2/5 (pow eps 5)) (* 2 eps))))\",\"link\":\"15-logqproblem343\",\"ninf\":0,\"pinf\":0,\"end-est\":0.13714055965779817,\"name\":\"logq (problem 3.4.3)\",\"samplers\":[\"default\"],\"time\":91070.09790039062,\"status\":\"eq-target\",\"vars\":[\"eps\"],\"target\":0.06565423716474932,\"end\":0.08804107935288033},{\"bits\":2432,\"start\":59.91793067942972,\"input\":\"(- (/ 1 x) (/ 1 (tan x)))\",\"output\":\"(+ (* 2/945 (pow x 5)) (+ (* 1/3 x) (* 1/45 (pow x 3))))\",\"link\":\"16-invcotexample39\",\"ninf\":0,\"pinf\":0,\"end-est\":0.34765625,\"name\":\"invcot (example 3.9)\",\"samplers\":[\"default\"],\"time\":26213.670166015625,\"status\":\"eq-target\",\"vars\":[\"x\"],\"target\":0.0759660601543468,\"end\":0.3295731203125902},{\"bits\":2432,\"start\":61.9783442604534,\"input\":\"(/ (* eps (- (exp (* (+ a b) eps)) 1)) (* (- (exp (* a eps)) 1) (- (exp (* b eps)) 1)))\",\"output\":\"(if (<= (/ (* eps (- (exp (* (+ a b) eps)) 1)) (* (- (exp (* a eps)) 1) (- (exp (* b eps)) 1))) -1.4449365230670285e-180) (+ (/ 1 b) (/ 1 a)) (if (<= (/ (* eps (- (exp (* (+ a b) eps)) 1)) (* (- (exp (* a eps)) 1) (- (exp (* b eps)) 1))) 2.5007607876802412e-113) (+ (/ 1 b) (/ 1 a)) (+ (/ 1 b) (/ 1 a))))\",\"link\":\"17-expq3problem342\",\"ninf\":0,\"pinf\":0,\"end-est\":4.24688513434934,\"name\":\"expq3 (problem 3.4.2)\",\"samplers\":[\"default\",\"default\",\"default\"],\"time\":233948.95581054688,\"status\":\"gt-target\",\"vars\":[\"a\",\"b\",\"eps\"],\"target\":14.651067317747806,\"end\":0.014198120312590145},{\"bits\":1408,\"start\":45.739517733726835,\"input\":\"(/ (exp x) (- (exp x) 1))\",\"output\":\"(if (<= x -9.950485992669078e-09) (/ 1 (- 1 (exp (- x)))) (if (<= x 0.16631490308113306) (+ (/ 1 x) (+ 1/2 (* 1/12 x))) (/ 1 (- 1 (exp (- x))))))\",\"link\":\"18-expq2section311\",\"ninf\":0,\"pinf\":0,\"end-est\":0.22577593043685318,\"name\":\"expq2 (section 3.11)\",\"samplers\":[\"default\"],\"time\":20018.59912109375,\"status\":\"gt-target\",\"vars\":[\"x\"],\"target\":30.12948710533904,\"end\":0.05791712397806687},{\"bits\":1408,\"start\":59.33343129621902,\"input\":\"(- (exp x) 1)\",\"output\":\"(+ (* (* x x) (+ 1/2 (* x 1/6))) x)\",\"link\":\"19-expm1example37\",\"ninf\":0,\"pinf\":0,\"end-est\":0.3642608971118385,\"name\":\"expm1 (example 3.7)\",\"samplers\":[\"default\"],\"time\":35543.492919921875,\"status\":\"eq-target\",\"vars\":[\"x\"],\"target\":0.06436560156295071,\"end\":0.06598364687698317},{\"bits\":1408,\"start\":33.44360243099122,\"input\":\"(- (exp (* a x)) 1)\",\"output\":\"(if (<= (* a x) -1.6665755921255327e-09) (- (exp (* a x)) 1) (+ (* x a) (* 1/2 (* (* x a) (* x a)))))\",\"link\":\"20-expaxsection35\",\"ninf\":0,\"pinf\":0,\"end-est\":0.30826629080627144,\"name\":\"expax (section 3.5)\",\"samplers\":[\"default\",\"default\"],\"time\":31542.9580078125,\"status\":\"gt-target\",\"vars\":[\"a\",\"x\"],\"target\":7.952127997421758,\"end\":0.18645915544792366},{\"bits\":1408,\"start\":33.99583817370671,\"input\":\"(+ (- (exp x) 2) (exp (- x)))\",\"output\":\"(+ (* 1/12 (pow x 4)) (+ (* 1/360 (pow x 6)) (sqr x)))\",\"link\":\"21-exp2problem337\",\"ninf\":0,\"pinf\":0,\"end-est\":0.7811424888959018,\"name\":\"exp2 (problem 3.3.7)\",\"samplers\":[\"default\"],\"time\":51116.8779296875,\"status\":\"gt-target\",\"vars\":[\"x\"],\"target\":8.659910873648657,\"end\":0.11144644300676601},{\"bits\":1152,\"start\":9.49656829978195,\"input\":\"(+ (- (/ 1 (+ x 1)) (/ 2 x)) (/ 1 (- x 1)))\",\"output\":\"(/ (/ (- (/ 2 x) 0) (- x 1)) (+ 1 x))\",\"link\":\"22-3fracproblem333\",\"ninf\":0,\"pinf\":0,\"end-est\":0.060878759768442016,\"name\":\"3frac (problem 3.3.3)\",\"samplers\":[\"default\"],\"time\":139599.76000976562,\"status\":\"eq-target\",\"vars\":[\"x\"],\"target\":0.23795078190808433,\"end\":0.06871936093777044},{\"bits\":2432,\"start\":36.40936010427848,\"input\":\"(- (tan (+ x eps)) (tan x))\",\"output\":\"(if (<= eps -2.4610266585566768e-113) (/ (- (sqr (/ (+ (tan x) (tan eps)) (- 1 (* (tan x) (tan eps))))) (sqr (tan x))) (+ (/ (+ (tan x) (tan eps)) (- 1 (* (tan x) (tan eps)))) (tan x))) (if (<= eps 3.1547769921923584e-35) (+ (* (sqr x) (cube eps)) (+ eps (* (cube x) (pow eps 4)))) (- (* (/ (+ (tan eps) (tan x)) (- 1 (/ (cube (* (tan eps) (sin x))) (cube (cos x))))) (+ (sqr 1) (+ (sqr (* (tan x) (tan eps))) (* 1 (* (tan x) (tan eps)))))) (tan x))))\",\"link\":\"23-2tanproblem332\",\"ninf\":0,\"pinf\":0,\"end-est\":16.79675543908866,\"name\":\"2tan (problem 3.3.2)\",\"samplers\":[\"default\",\"default\"],\"time\":153829.44311523438,\"status\":\"gt-target\",\"vars\":[\"x\",\"eps\"],\"target\":24.868488975311955,\"end\":11.1570419418963},{\"bits\":1408,\"start\":29.901471078747512,\"input\":\"(- (sqrt (+ x 1)) (sqrt x))\",\"output\":\"(/ 1 (+ (sqrt (+ x 1)) (sqrt x)))\",\"link\":\"24-2sqrtexample31\",\"ninf\":0,\"pinf\":0,\"end-est\":0.19988251953688405,\"name\":\"2sqrt (example 3.1)\",\"samplers\":[\"default\"],\"time\":20755.375,\"status\":\"eq-target\",\"vars\":[\"x\"],\"target\":0.16316052656439306,\"end\":0.16316052656439306},{\"bits\":2432,\"start\":36.71325510564527,\"input\":\"(- (sin (+ x eps)) (sin x))\",\"output\":\"(if (<= eps -3.645937152382937e+19) (- (+ (* (sin x) (cos eps)) (* (cos x) (sin eps))) (sin x)) (if (<= eps 6.326235572596747e-15) (* 2 (* (sin (/ eps 2)) (cos (/ (+ (+ x eps) x) 2)))) (- (+ (* (sin x) (cos eps)) (* (cos x) (sin eps))) (sin x))))\",\"link\":\"25-2sinexample33\",\"ninf\":0,\"pinf\":0,\"end-est\":0.40463013074677723,\"name\":\"2sin (example 3.3)\",\"samplers\":[\"default\",\"default\"],\"time\":82629.40185546875,\"status\":\"gt-target\",\"vars\":[\"x\",\"eps\"],\"target\":14.900038199925003,\"end\":1.0798819096901375},{\"bits\":1152,\"start\":19.330732255826693,\"input\":\"(- (/ 1 (sqrt x)) (/ 1 (sqrt (+ x 1))))\",\"output\":\"(* (/ 1 (+ (sqrt (+ 1 x)) (sqrt x))) (/ 1 (* (sqrt x) (sqrt (+ x 1)))))\",\"link\":\"26-2isqrtexample36\",\"ninf\":0,\"pinf\":0,\"end-est\":0.3721339476841681,\"name\":\"2isqrt (example 3.6)\",\"samplers\":[\"default\"],\"time\":35296.56103515625,\"status\":\"eq-target\",\"vars\":[\"x\"],\"target\":0.714170361427429,\"end\":0.3941741281572718},{\"bits\":1408,\"start\":14.541859386925417,\"input\":\"(- (atan (+ N 1)) (atan N))\",\"output\":\"(atan2 (+ 1 0) (+ (* (+ N 1) N) 1))\",\"link\":\"27-2atanexample35\",\"ninf\":0,\"pinf\":0,\"end-est\":0.29506882110978144,\"name\":\"2atan (example 3.5)\",\"samplers\":[\"default\"],\"time\":15547.489990234375,\"status\":\"eq-target\",\"vars\":[\"N\"],\"target\":0.39299853686879893,\"end\":0.39174853686879885}]}"
  },
  {
    "path": "www/doc/1.1/results-old.json",
    "content": "{\"bit_width\":64,\"date\":1490840216,\"commit\":\"58bf255242aa4ff0c47bb93e3c2ea80079b951c5\",\"branch\":\"master\",\"flags\":[\"precision:double\",\"setup:simplify\",\"reduce:regimes\",\"reduce:taylor\",\"reduce:simplify\",\"reduce:avg-error\",\"rules:arithmetic\",\"rules:polynomials\",\"rules:fractions\",\"rules:exponents\",\"rules:trigonometry\",\"generate:rr\",\"generate:taylor\",\"generate:simplify\"],\"points\":256,\"iterations\":3,\"tests\":[{\"status\":\"imp-start\",\"target\":false,\"start\":30.72710658756978,\"vars\":[\"x\",\"n\"],\"samplers\":[\"default\",\"default\"],\"input\":\"(- (pow (+ x 1) (/ 1 n)) (pow x (/ 1 n)))\",\"output\":\"(if (<= n -2.3031253660826823e+26) (- (- (/ (/ 1 x) n) (/ (log x) (* n (* n x)))) (/ (/ 1/2 n) (sqr x))) (if (<= n 479155699082691.3) (cbrt (cube (cbrt (cube (cbrt (cube (- (pow (+ x 1) (/ 1 n)) (pow x (/ 1 n))))))))) (- (- (/ (/ 1 x) n) (/ (log x) (* n (* n x)))) (/ (/ 1/2 n) (sqr x)))))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":26.115579094525142,\"name\":\"NMSE problem 3.4.6\",\"end\":8.352001623029237,\"time\":96880.43798828125,\"link\":\"0-NMSEproblem346\"},{\"status\":\"imp-start\",\"target\":false,\"start\":31.62500906332104,\"vars\":[\"x\"],\"samplers\":[\"default\"],\"input\":\"(/ (- x (sin x)) (- x (tan x)))\",\"output\":\"(if (<= x -3.150653682326084e-06) (- (/ x (- x (tan x))) (/ (sin x) (- x (tan x)))) (if (<= x 0.1680384430276768) (- (* 9/40 (sqr x)) (+ (* 27/2800 (pow x 4)) 1/2)) (- (/ x (- x (tan x))) (/ (sin x) (- x (tan x))))))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":0.16733880207871452,\"name\":\"NMSE problem 3.4.5\",\"end\":0.1104513958526418,\"time\":47490.5791015625,\"link\":\"1-NMSEproblem345\"},{\"status\":\"imp-start\",\"target\":false,\"start\":45.09950437667379,\"vars\":[\"x\"],\"samplers\":[\"default\"],\"input\":\"(sqrt (/ (- (exp (* 2 x)) 1) (- (exp x) 1)))\",\"output\":\"(if (<= x -8.867720861083589e-13) (sqrt (/ (- (exp (* 2 x)) 1) (- (exp x) 1))) (sqrt (+ (* 1/2 (sqr x)) (+ 2 x))))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":0.7376765013424993,\"name\":\"NMSE problem 3.4.4\",\"end\":7.500544686712205,\"time\":26112.76806640625,\"link\":\"2-NMSEproblem344\"},{\"status\":\"imp-start\",\"target\":false,\"start\":31.356953350333576,\"vars\":[\"x\"],\"samplers\":[\"default\"],\"input\":\"(/ (- 1 (cos x)) (sqr x))\",\"output\":\"(* (/ (sin x) x) (/ (/ (sin x) (+ 1 (cos x))) x))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":0.192046331613414,\"name\":\"NMSE problem 3.4.1\",\"end\":0.30161782915000535,\"time\":43265.260986328125,\"link\":\"3-NMSEproblem341\"},{\"status\":\"imp-start\",\"target\":false,\"start\":40.184769151759774,\"vars\":[\"N\"],\"samplers\":[\"default\"],\"input\":\"(- (log (+ N 1)) (log N))\",\"output\":\"(if (<= N 519383.0646430557) (log (/ (+ N 1) N)) (+ (/ (- (/ 1/3 N) 1/2) (sqr N)) (/ 1 N)))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":0.09151380401675037,\"name\":\"NMSE problem 3.3.6\",\"end\":19.38968452894342,\"time\":18756.22607421875,\"link\":\"4-NMSEproblem336\"},{\"status\":\"imp-start\",\"target\":false,\"start\":37.07285680541725,\"vars\":[\"x\",\"eps\"],\"samplers\":[\"default\",\"default\"],\"input\":\"(- (cos (+ x eps)) (cos x))\",\"output\":\"(if (<= eps -1.3296779497386022e-08) (/ (- (cube (* (cos eps) (cos x))) (cube (+ (* (sin eps) (sin x)) (cos x)))) (+ (sqr (* (cos eps) (cos x))) (* (+ (* (cos eps) (cos x)) (+ (* (sin x) (sin eps)) (cos x))) (+ (* (sin x) (sin eps)) (cos x))))) (if (<= eps 7.134416671297405e-12) (- (* (* eps 1/6) (cube x)) (* eps (+ (* 1/2 eps) x))) (/ (- (cube (* (cos eps) (cos x))) (cube (+ (* (sin eps) (sin x)) (cos x)))) (+ (sqr (* (cos eps) (cos x))) (* (+ (* (cos eps) (cos x)) (+ (* (sin x) (sin eps)) (cos x))) (+ (* (sin x) (sin eps)) (cos x)))))))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":15.049825158123982,\"name\":\"NMSE problem 3.3.5\",\"end\":3.8473381505495694,\"time\":68603.96508789062,\"link\":\"5-NMSEproblem335\"},{\"status\":\"apx-start\",\"target\":false,\"start\":29.326846493043334,\"vars\":[\"x\"],\"samplers\":[\"default\"],\"input\":\"(- (pow (+ x 1) (/ 1 3)) (pow x (/ 1 3)))\",\"output\":\"(exp (cube (cbrt (log (- (pow (+ x 1) (/ 1 3)) (pow x (/ 1 3)))))))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":26.112737951959613,\"name\":\"NMSE problem 3.3.4\",\"end\":29.330084230611476,\"time\":48849.850830078125,\"link\":\"6-NMSEproblem334\"},{\"status\":\"imp-start\",\"target\":false,\"start\":14.327571332282405,\"vars\":[\"x\"],\"samplers\":[\"default\"],\"input\":\"(- (/ 1 (+ x 1)) (/ 1 x))\",\"output\":\"(if (<= x -6572693219723.217) (- (/ (/ 1 x) (sqr x)) (/ (/ 1 x) x)) (if (<= x 14125114759858.025) (/ (- x (+ 1 x)) (* (+ x 1) x)) (- (/ (/ 1 x) (sqr x)) (/ (/ 1 x) x))))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":0.078125,\"name\":\"NMSE problem 3.3.1\",\"end\":0.07644812031259013,\"time\":19662.1669921875,\"link\":\"7-NMSEproblem331\"},{\"status\":\"imp-start\",\"target\":false,\"start\":37.568586126435775,\"vars\":[\"a\",\"b/2\",\"c\"],\"samplers\":[\"default\",\"default\",\"default\"],\"input\":\"(/ (+ (- b/2) (sqrt (- (sqr b/2) (* a c)))) a)\",\"output\":\"(if (<= b/2 -5.149274995892533e+86) (- (* (/ 1/2 b/2) c) (* 2 (/ b/2 a))) (if (<= b/2 9.946391916507581e-83) (/ 1 (/ a (+ (- b/2) (sqrt (- (sqr b/2) (* a c)))))) (- (/ (+ b/2 (- b/2)) a) (* 1/2 (/ c b/2)))))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":6.760667970562651,\"name\":\"NMSE problem 3.2.1, positive\",\"end\":4.75003112024967,\"time\":50862.839111328125,\"link\":\"8-NMSEproblem321positive\"},{\"status\":\"imp-start\",\"target\":false,\"start\":35.67879826787097,\"vars\":[\"a\",\"b/2\",\"c\"],\"samplers\":[\"default\",\"default\",\"default\"],\"input\":\"(/ (- (- b/2) (sqrt (- (sqr b/2) (* a c)))) a)\",\"output\":\"(if (<= b/2 -0.004102676064970259) (* (/ c b/2) -1/2) (if (<= b/2 -7.674146973599803e-149) (/ (/ (* a c) (+ (- b/2) (sqrt (- (sqr b/2) (* a c))))) a) (if (<= b/2 9.060571198789832e+80) (/ (- (- b/2) (sqrt (- (sqr b/2) (* a c)))) a) (* -2 (/ b/2 a)))))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":6.283356310763793,\"name\":\"NMSE problem 3.2.1, negative\",\"end\":5.53668681524491,\"time\":41098.823974609375,\"link\":\"9-NMSEproblem321negative\"},{\"status\":\"gt-target\",\"target\":12.539481177734315,\"start\":35.88674549677141,\"vars\":[\"a\",\"x\"],\"samplers\":[\"default\",\"default\"],\"input\":\"(- (exp (* a x)) 1)\",\"output\":\"(if (<= (* a x) -2.6715888843965976e-09) (- (exp (* a x)) 1) (* x a))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":0.43938819654193784,\"name\":\"NMSE section 3.5\",\"end\":0.09584099696101328,\"time\":19852.485107421875,\"link\":\"10-NMSEsection35\"},{\"status\":\"gt-target\",\"target\":45.33809150635401,\"start\":45.32749786530321,\"vars\":[\"x\"],\"samplers\":[\"default\"],\"input\":\"(/ (exp x) (- (exp x) 1))\",\"output\":\"(if (<= x -3.150653682326084e-06) (/ 1 (- 1 (exp (- x)))) (+ (* 1/12 x) (+ 1/2 (/ 1 x))))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":0.6084361289342824,\"name\":\"NMSE section 3.11\",\"end\":0.12805703358889042,\"time\":23151.529052734375,\"link\":\"11-NMSEsection311\"},{\"status\":\"eq-target\",\"target\":0.06576167289182676,\"start\":59.41688754122086,\"vars\":[\"eps\"],\"samplers\":[\"default\"],\"input\":\"(log (/ (- 1 eps) (+ 1 eps)))\",\"output\":\"(- (+ (+ (* (cube eps) 2/3) (* 2/5 (pow eps 5))) (* 2 eps)))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":0.15924746790050592,\"name\":\"NMSE problem 3.4.3\",\"end\":0.08275227445477747,\"time\":31097.13818359375,\"link\":\"12-NMSEproblem343\"},{\"status\":\"gt-target\",\"target\":14.14172034209319,\"start\":61.97294495933572,\"vars\":[\"a\",\"b\",\"eps\"],\"samplers\":[\"default\",\"default\",\"default\"],\"input\":\"(/ (* eps (- (exp (* (+ a b) eps)) 1)) (* (- (exp (* a eps)) 1) (- (exp (* b eps)) 1)))\",\"output\":\"(if (<= (/ (* eps (- (exp (* (+ a b) eps)) 1)) (* (- (exp (* a eps)) 1) (- (exp (* b eps)) 1))) -9.296169205569568e-188) (+ (/ 1 a) (/ 1 b)) (if (<= (/ (* eps (- (exp (* (+ a b) eps)) 1)) (* (- (exp (* a eps)) 1) (- (exp (* b eps)) 1))) 7.819285243784398e-190) (+ (/ 1 a) (/ 1 b)) (+ (/ 1 a) (/ 1 b))))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":3.590759504240281,\"name\":\"NMSE problem 3.4.2\",\"end\":0.012948120312590145,\"time\":200928.28002929688,\"link\":\"13-NMSEproblem342\"},{\"status\":\"gt-target\",\"target\":8.680496323252925,\"start\":34.42699152807259,\"vars\":[\"x\"],\"samplers\":[\"default\"],\"input\":\"(+ (- (exp x) 2) (exp (- x)))\",\"output\":\"(+ (sqr x) (+ (* 1/12 (pow x 4)) (* 1/360 (pow x 6))))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":0.28275930527467336,\"name\":\"NMSE problem 3.3.7\",\"end\":0.1067912674976738,\"time\":18596.828125,\"link\":\"14-NMSEproblem337\"},{\"status\":\"eq-target\",\"target\":0.24535050244616535,\"start\":9.51064615742219,\"vars\":[\"x\"],\"samplers\":[\"default\"],\"input\":\"(+ (- (/ 1 (+ x 1)) (/ 2 x)) (/ 1 (- x 1)))\",\"output\":\"(/ 2 (* (+ x (sqr x)) (- x 1)))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":0.0625,\"name\":\"NMSE problem 3.3.3\",\"end\":0.25036234463429635,\"time\":57014.72998046875,\"link\":\"15-NMSEproblem333\"},{\"status\":\"gt-target\",\"target\":26.24923754199063,\"start\":36.519809893592864,\"vars\":[\"x\",\"eps\"],\"samplers\":[\"default\",\"default\"],\"input\":\"(- (tan (+ x eps)) (tan x))\",\"output\":\"(if (<= eps -6.169079171368681e-49) (/ (/ (- (sqr (cos x)) (sqr (cube (cbrt (* (cotan (+ x eps)) (sin x)))))) (+ (* (cotan (+ eps x)) (sin x)) (cos x))) (* (cotan (+ x eps)) (cos x))) (if (<= eps 2.0116360245016707e-26) (+ (* (sqr x) (cube eps)) (+ eps (* (cube x) (pow eps 4)))) (/ (/ (- (sqr (cos x)) (sqr (cube (cbrt (* (cotan (+ x eps)) (sin x)))))) (+ (* (cotan (+ eps x)) (sin x)) (cos x))) (* (cotan (+ x eps)) (cos x)))))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":27.67891718929942,\"name\":\"NMSE problem 3.3.2\",\"end\":24.756494557676795,\"time\":63485.365966796875,\"link\":\"16-NMSEproblem332\"},{\"status\":\"gt-target\",\"target\":25.77374001912148,\"start\":37.72618589177047,\"vars\":[\"a\",\"b\",\"c\"],\"samplers\":[\"default\",\"default\",\"default\"],\"input\":\"(/ (+ (- b) (sqrt (- (sqr b) (* 4 (* a c))))) (* 2 a))\",\"output\":\"(if (<= b -5.149274995892533e+86) (- (/ c b) (/ b a)) (if (<= b 9.946391916507581e-83) (/ 1 (/ (* 2 a) (+ (- b) (sqrt (- (sqr b) (* 4 (* a c))))))) (/ (* (/ 4 2) c) (- (/ (* c 2) (/ b a)) (* b 2)))))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":6.740241807359317,\"name\":\"NMSE p42, positive\",\"end\":6.310074296845912,\"time\":68592.75610351562,\"link\":\"17-NMSEp42positive\"},{\"status\":\"gt-target\",\"target\":23.40536923119662,\"start\":35.66770760005187,\"vars\":[\"a\",\"b\",\"c\"],\"samplers\":[\"default\",\"default\",\"default\"],\"input\":\"(/ (- (- b) (sqrt (- (sqr b) (* 4 (* a c))))) (* 2 a))\",\"output\":\"(if (<= b -0.004102676064970259) (* (/ -2 2) (/ c b)) (if (<= b -7.674146973599803e-149) (/ (/ (* 4 (* a c)) (+ (- b) (sqrt (- (sqr b) (* 4 (* a c)))))) (* 2 a)) (if (<= b 9.060571198789832e+80) (- (/ (- b) (* 2 a)) (/ (sqrt (- (sqr b) (* 4 (* a c)))) (* 2 a))) (- (/ c b) (/ b a)))))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":6.283669107106033,\"name\":\"NMSE p42, negative\",\"end\":5.544343202430409,\"time\":74686.93579101562,\"link\":\"18-NMSEp42negative\"},{\"status\":\"eq-target\",\"target\":0.07492121385885234,\"start\":59.92910465279442,\"vars\":[\"x\"],\"samplers\":[\"default\"],\"input\":\"(- (/ 1 x) (cotan x))\",\"output\":\"(+ (* 1/45 (cube x)) (+ (* (pow x 5) 2/945) (* x 1/3)))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":0.31640625,\"name\":\"NMSE example 3.9\",\"end\":0.341125,\"time\":19957.39599609375,\"link\":\"19-NMSEexample39\"},{\"status\":\"lt-target\",\"target\":0,\"start\":62.983165481898844,\"vars\":[\"N\"],\"samplers\":[\"default\"],\"input\":\"(- (- (* (+ N 1) (log (+ N 1))) (* N (log N))) 1)\",\"output\":\"(- (exp (- (log (- (sqr (cube (* (cbrt (+ N 1)) (cbrt (log (+ N 1)))))) (sqr (* N (log N))))) (log (+ (* (log N) N) (* (log (+ N 1)) (+ N 1)))))) 1)\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":61.26976387791292,\"name\":\"NMSE example 3.8\",\"end\":61.339891393664374,\"time\":120993.76293945312,\"link\":\"20-NMSEexample38\"},{\"status\":\"eq-target\",\"target\":0.06211560156295071,\"start\":59.381589721029606,\"vars\":[\"x\"],\"samplers\":[\"default\"],\"input\":\"(- (exp x) 1)\",\"output\":\"(+ x (* (sqr x) (+ (* 1/6 x) 1/2)))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":0.41917203895823363,\"name\":\"NMSE example 3.7\",\"end\":0.06528552656439303,\"time\":9809.6240234375,\"link\":\"21-NMSEexample37\"},{\"status\":\"eq-target\",\"target\":0.6404688144198558,\"start\":19.20459512853389,\"vars\":[\"x\"],\"samplers\":[\"default\"],\"input\":\"(- (/ 1 (sqrt x)) (/ 1 (sqrt (+ x 1))))\",\"output\":\"(* (/ 1 (+ (sqrt (+ 1 x)) (sqrt x))) (/ 1 (* (sqrt x) (sqrt (+ x 1)))))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":0.38355263675818835,\"name\":\"NMSE example 3.6\",\"end\":0.3995771199558376,\"time\":22303.14697265625,\"link\":\"22-NMSEexample36\"},{\"status\":\"eq-target\",\"target\":0.3535924396191792,\"start\":14.816015150117126,\"vars\":[\"N\"],\"samplers\":[\"default\"],\"input\":\"(- (atan (+ N 1)) (atan N))\",\"output\":\"(atan2 (+ 1 0) (+ (+ (sqr N) N) 1))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":0.28737647630464624,\"name\":\"NMSE example 3.5\",\"end\":0.3545099208695398,\"time\":13250.199951171875,\"link\":\"23-NMSEexample35\"},{\"status\":\"eq-target\",\"target\":0.00025,\"start\":30.564429941581903,\"vars\":[\"x\"],\"samplers\":[\"default\"],\"input\":\"(/ (- 1 (cos x)) (sin x))\",\"output\":\"(* 1 (/ (sin x) (+ (cos x) 1)))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":0.3672159192193488,\"name\":\"NMSE example 3.4\",\"end\":0.4536472361174264,\"time\":29972.529052734375,\"link\":\"24-NMSEexample34\"},{\"status\":\"gt-target\",\"target\":26.637778727998082,\"start\":36.25290408910504,\"vars\":[\"x\",\"eps\"],\"samplers\":[\"default\",\"default\"],\"input\":\"(- (sin (+ x eps)) (sin x))\",\"output\":\"(if (<= eps -6.169079171368681e-49) (/ (- (sqr (+ (* (sin x) (cos eps)) (* (cos x) (sin eps)))) (sqr (sin x))) (+ (+ (* (sin x) (cos eps)) (* (cos x) (sin eps))) (sin x))) (if (<= eps 2.0116360245016707e-26) (- eps (* (* (+ x eps) (* x eps)) 1/2)) (+ (* (sin x) (cos eps)) (/ (- (sqr (* (cos x) (sin eps))) (sqr (sin x))) (+ (* (cos x) (sin eps)) (sin x))))))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":14.515236082978266,\"name\":\"NMSE example 3.3\",\"end\":2.0782981277949357,\"time\":62088.2919921875,\"link\":\"25-NMSEexample33\"},{\"status\":\"eq-target\",\"target\":0.4427242395058597,\"start\":61.373439946309574,\"vars\":[\"x\"],\"samplers\":[\"default\"],\"input\":\"(/ (log (- 1 x)) (log (+ 1 x)))\",\"output\":\"(- (+ (+ (* 1/2 (sqr x)) x) 1))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":0.35614265339161655,\"name\":\"NMSE example 3.10\",\"end\":0.000875,\"time\":15522.3759765625,\"link\":\"26-NMSEexample310\"},{\"status\":\"eq-target\",\"target\":0.164660526564393,\"start\":29.410104469288694,\"vars\":[\"x\"],\"samplers\":[\"default\"],\"input\":\"(- (sqrt (+ x 1)) (sqrt x))\",\"output\":\"(/ 1 (+ (sqrt (+ x 1)) (sqrt x)))\",\"bits\":128,\"pinf\":0,\"ninf\":0,\"end-est\":0.15234375,\"name\":\"NMSE example 3.1\",\"end\":0.164660526564393,\"time\":8996.474853515625,\"link\":\"27-NMSEexample31\"}],\"note\":false,\"seed\":\"#(2606739721 3337331833 2041942718 3037006954 1385554395 1942462848)\"}\n"
  },
  {
    "path": "www/doc/1.1/using-cli.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie from the Command Line</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n</head>\n<body>\n  <header>\n    <h1>Using Herbie from the Command Line</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"using-web.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> rewrites floating point expressions to\n    make them more accurate. The expressions could come from\n    anywhere—your source code, mathematical papers, or even the output\n    of <a href=\"../1.0/using-herbgrind.html\">Herbgrind</a>, our tool for\n    finding inaccurate expressions in binaries. This tutorial runs\n    Herbie on the benchmark programs that Herbie ships with.\n  </p>\n\n  <p>Herbie can be used from the command-line\n  or from <a href=\"using-web.html\">the browser</a>. This page covers\n  using Herbie from the command line.</p>\n\n  <h2>Input expressions</h2>\n\n  <p>\n    Herbie ships a collection of benchmarks in its <code>bench/</code>\n    directory. For example, <code>bench/tutorial.fpcore</code>\n    contains the following code:\n  </p>\n\n  <pre>(FPCore (x)\n  :name \"Cancel like terms\"\n  (- (+ 1 x) x))\n\n(FPCore (x)\n  :name \"Expanding a square\"\n  (- (sqr (+ x 1)) 1))\n\n(FPCore (x y z)\n  :name \"Commute and associate\"\n  (- (+ (+ x y) z) (+ x (+ y z))))</pre>\n\n  <p> This code defines three floating point expressions that we want\n    to run Herbie on:</p>\n\n  <ul>\n    <li><code>(1 + x) - x</code>, titled “Cancel like terms”</li>\n    <li><code>(x + 1)² - 1</code>, titled “Expanding a square”</li>\n    <li><code>((x + y) + z) - (x + (y + z))</code>, titled “Commute\n    and associate”</li>\n  </ul>\n\n  <p>You can check out our <a href=\"input.html\">input format\n    documentation</a> for more about the Herbie input format. </p>\n\n  <h2 id=\"interactive\">The Herbie shell</h2>\n\n  <p>\n    The Herbie shell lets you interact with Herbie, typing in\n    benchmark expressions and seeing the outputs. Run the Herbie\n    shell:\n  </p>\n\n  <pre>herbie shell</pre>\n\n  <p>\n    After a few seconds, Herbie will start up and wait for input:\n  </p>\n\n  <pre><strong>$</strong> herbie shell\nSeed: #(3123212801 2137904229 2993294009 3035080405 3708006222 26032508)\nherbie> </pre>\n\n  <p>\n    The printed seed can be used to reproduce a Herbie run. You can\n    now paste inputs directly into your terminal for Herbie to\n    improve:\n  </p>\n\n  <pre>(FPCore (x) :name \"Cancel like terms\" (- (+ 1 x) x))\n(FPCore (x) 1)</pre>\n\n  <p>\n    Interactive use is helpful if you want to play with different\n    expressions and try multiple variants, informed by Herbie's\n    advice.\n  </p>\n\n  <h2 id=\"batch\">Batch processing FPCore</h2>\n\n  <p>\n    Alternatively, you can run Herbie on a file with multiple\n    expressions in it, producing the output expressions to a file:\n  </p>\n\n  <pre><strong>$</strong> herbie improve bench/tutorial.fpcore out.fpcore\nSeed: #(3123212801 2137904229 2993294009 3035080405 3708006222 26032508)\n  1/3   [ 1563.552ms]\tCancel like terms\t(29→ 0)\n  2/3   [ 4839.121ms]\tExpanding a square\t(38→ 0)\n  3/3   [ 3083.238ms]\tCommute and associate\t( 0→ 0)</pre>\n\n  <p>\n    The output file <code>out.fpcore</code> contains more accurate\n    versions of each program:\n  </p>\n\n  <pre>;; seed: #(3123212801 2137904229 2993294009 3035080405 3708006222 26032508)\n\n(FPCore (x) 1)\n(FPCore (x) (* (+ 2 x) x))\n(FPCore (x y z) 0)</pre>\n\n  <p>\n    Note that the order of expressions is identical.\n    For more control over Herbie, see the documentation of\n    Herbie's <a href=\"options.html\">command-line options</a>.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.1/using-web.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie from the Browser</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n</head>\n<body>\n  <header>\n    <h1>Using Herbie from the Browser</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"using-web.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> rewrites floating point expressions to\n    make them more accurate. The expressions could come from\n    anywhere—your source code, mathematical papers, or even the output\n    of <a href=\"../1.0/using-herbgrind.html\">Herbgrind</a>, our tool for\n    finding inaccurate expressions in binaries. This tutorial runs\n    Herbie on the benchmark programs that Herbie ships with.\n  </p>\n\n  <p>Herbie can be used from <a href=\"using-cli.html\">the\n  command-line</a> and from the browser. This page covers\n  using Herbie from the command line.</p>\n\n\n  <h2 id=\"interactive\">The Herbie web shell</h2>\n\n  <p>\n    The Herbie web shell lets you interact with Herbie through your\n    browser, featuring a convenient input format. Run the Herbie web\n    shell:\n  </p>\n\n  <pre>herbie web</pre>\n\n  <p>\n    After a few seconds, the web shell will rev up and direct your\n    browser to the main web shell page:\n  </p>\n  \n  <pre><strong>$</strong> herbie web\nYour Web application is running at http://localhost:8000/.\nStop this program at any time to terminate the Web Server.</pre>\n\n  <figure>\n    <img width=\"100%\" src=\"web-main.png\" />\n    <figcaption>The input page for the web shell.</figcaption>\n  </figure>\n\n  <p>\n    As in the screenshot, you can type expressions, in standard\n    mathematical syntax (parsed\n    by <a href=\"http://mathjs.org\">Math.js</a>), and\n    hit <kbd>Enter</kbd> to have Herbie attempt to improve them.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"web-progress.png\" />\n    <figcaption>Herbie improvement in progress.</figcaption>\n  </figure>\n\n\n  <p>\n    The web shell will print Herbie's progress, and redirect to a\n    <a href=\"report.html\">report</a> once Herbie is done.\n  </p>\n\n  <p>\n    Interactive use of the web shell is the friendliest and easiest\n    way to use Herbie. The web shell has <a href=\"options.html\">many\n    options</a>, including automatically saving the generated reports.\n  </p>\n\n  <h2 id=\"batch\">Batch report generation</h2>\n\n  <p>A <a href=\"report.html\">report</a> can also be generated directly\n  from a file of input expressions:</p>\n  \n  <pre><strong>$</strong> herbie report input.fpcore output/\nStarting Herbie on 3 problems...\nSeed: #(327732824 4211992217 3609811086 1098847098 2827724810 3610427321)\n  1/3\t[ 7108.190ms]\t(39→ 0)\tExpanding a square\n  2/3\t[ 1894.348ms]\t( 0→ 0)\tCommute and associate\n  3/3\t[ 873.3889ms]\t(29→ 0)\tCancel like terms</pre>\n\n  <p>\n    This command asks Herbie to generate a report from the input\n    expressions in <code>input.fpcore</code> and save the report in\n    the directory <code>output/</code>, which ought not exist yet.\n    The printed seed can be used to reproduce a run of Herbie.\n  </p>\n\n  <p>\n    Once generated, open the <code>output/report.html</code> page\n    in your favorite browser (but see <a href=\"faq.html\"> the FAQ</a>\n    if you're using Chrome). From that page, you can click on the rows\n    in the table at the bottom to see the report for that expression.\n  </p>\n\n  <p>Batch report generation is the most informative way to run Herbie\n  on a large collection of inputs. Like the web shell, it can be\n  customized through <a href=\"options.html\">command-line options</a>,\n  including running Herbie in multiple threads at once.</p>\n\n\n  <h2>Input expressions</h2>\n\n  <p>An example input file can be found in <code>bench/tutorial.fpcore</code>:</p>\n  \n  <pre>(FPCore (x)\n  :name \"Cancel like terms\"\n  (- (+ 1 x) x))\n\n(FPCore (x)\n  :name \"Expanding a square\"\n  (- (sqr (+ x 1)) 1))\n\n(FPCore (x y z)\n  :name \"Commute and associate\"\n  (- (+ (+ x y) z) (+ x (+ y z))))</pre>\n  \n  <p> This code defines three floating point expressions that we want\n    to run Herbie on:</p>\n\n  <ul>\n    <li><code>(1 + x) - x</code>, titled “Cancel like terms”</li>\n    <li><code>(x + 1)² - 1</code>, titled “Expanding a square”</li>\n    <li><code>((x + y) + z) - (x + (y + z))</code>, titled “Commute\n    and associate”</li>\n  </ul>\n\n  <p>You can check out our <a href=\"input.html\">input format\n    documentation</a> for more about the Herbie input format. </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.2/docker.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie on Docker</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Installing with Docker</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"using-web.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a>'s is available\n    through <a href=\"https://www.docker.com/\">Docker</a>, which is a\n    sort of like an easily-scriptable virtual machine. This page\n    describes how to install\n    the <a href=\"https://hub.docker.com/uwplse/herbie\">official Docker\n    image</a> for Herbie.\n  </p>\n  \n  <p>\n    Herbie can also be <a href=\"installing.html\">installed\n    normally</a>.\n  </p>\n  \n  <h2>Installing the Herbie image</h2>\n\n  <p>\n    First, <a href=\"https://docs.docker.com/installation/\">install\n    Docker</a>. Docker supports Windows, OS X, and Linux. Depending on\n    how you install Docker, you may need to prefix\n    all <code>docker</code> commands on this page\n    with <code>sudo</code> or run them as the root or administrative\n    user.\n  </p>\n  \n  <p>\n    With Docker installed, you should be able to download the Herbie image with:\n  </p>\n \n\n  <pre>docker pull uwplse/herbie</pre>\n  \n  <p>\n    You can now run Herbie:\n  </p>\n\n  <pre>docker run -it uwplse/herbie shell</pre>\n  \n  <p>\n    This will run the <a href=\"using-cli.html\">Herbie shell</a>,\n    reading input from the standard input.\n  </p>\n\n  <h2>Generating files and reports</h2>\n\n  <p>\n    To use Herbie in <a href=\"using-cli.html\">batch mode</a>, you will\n    need to mount the input in the Docker container. Do that with:\n  </p>\n  \n  <pre><strong>$</strong> docker run -it --rm \\\n    -v <var>in-dir</var>:/in \\\n    -v <var>out-dir</var>:/out \\\n    -u $USER \\\n    uwplse/herbie improve /in/<var>in-file</var> /out/<var>out-file</var></pre>\n\n  <p>\n    In this command, you are asking Herbie to read input\n    from <var>in-file</var> in <var>in-dir</var>, and write output\n    to <var>out-file</var> in <var>out-dir</var>. The command looks\n    the same if you want Herbie to read input from a directory;\n    just leave <var>in-file</var> blank.\n  </p>\n\n  <p>\n    To generate reports from Herbie, you can run:\n  </p>\n\n  <pre><strong>$</strong> docker run -it --rm \\\n    -v <var>in-dir</var>:/in \\\n    -v <var>out-dir</var>:/out \\\n    -u $USER \\\n    uwplse/herbie report /in/<var>in-file</var> /out/</pre>\n\n  <p>\n    As before, the input and output directories must be mounted inside\n    the Docker container. Note that both here and above, the user is\n    set to the current user. This is to ensure that the files Herbie creates\n    have the correct permissions set.\n  </p>\n\n  <h2>Running the web shell</h2>\n\n  <p>\n    Running the web shell in Docker requires exposing the ports inside\n    the container. The Herbie Docker image binds to port 80 by default;\n    use the <code>-p &lt;hostport&gt;:80</code> option to Docker to expose\n    Herbie on whatever port you choose.\n  </p>\n\n  <pre><strong>$</strong> docker run -it --rm -p 8000:80 uwplse/herbie</pre>\n\n  <p>\n    If you are using the <code>--log</code>\n    or <code>--save-session</code> flags for the web shell,\n    you will also need to mount the relevant directories into the\n    Docker container using the <code>-v</code> Docker option, as in\n    the examples above.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.2/faq.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie FAQ</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Frequently Asked Questions</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"using-web.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> automatically transforms floating point\n    expressions into more accurate forms. This page catalogs questions\n    frequently asked questions about Herbie.\n  </p>\n\n  <h2>Troubleshooting common errors</h2>\n\n  <p>\n    Several Herbie error messages refer to this page for additional\n    information and debugging tips.\n  </p>\n\n  <h3 id=\"invalid-syntax\">“Invalid syntax” error</h3>\n\n  <p>\n    This error means you mis-formatted Herbie's input. Common errors\n    include misspelling function names and parenthesizing expressions\n    that must not be parenthesized. For example, in\n    <code>(- (exp (x)) 1)</code>, <code>(x)</code> is incorrect:\n    <code>x</code> is a variable so isn't parenthesized. <code>(- (exp\n    x) 1)</code> would be the correct way of writing that expression.\n    Please review the <a href=\"input.html\">input format</a>\n    documentation for more.\n  </p>\n\n  <h3 id=\"sample-valid-points\">“Cannot sample enough valid points” error</h3>\n\n  <p>\n    Herbie uses random sampling to select the points which it will use\n    to evaluate the error of an expression. This error occurs when it\n    is not able to find enough valid points. For example, consider the\n    expression <code>(acos (+ 1000 x))</code>. This expression yields\n    a valid result only when <code>x</code> is between -1001 and -999,\n    a rather narrow range.\n  </p>\n\n  <p>\n    The solution is to help out Herbie by specifying a precondition.\n    Specify <code>:pre (&lt; -1001 x -999)</code> for the example\n    above. Herbie will use the precondition to improve its sampling\n    strategy.\n  </p>\n\n  <h3 id=\"no-valid-values\">“No valid values” error</h3>\n\n  <p>\n    This error indicates that your precondition excludes all possible\n    inputs. For example, the precondition <code>(&lt 3 x 2)</code>\n    excludes all inputs. Herbie raises this exception only when it can\n    determine that no inputs work. The solution is to fix the\n    precondition to allow some inputs. Note that sufficiently complex\n    unsatisfiable preconditions instead raise the error above.\n  </p>\n\n  <h3 id=\"mpfr-prec-limit\">“Exceeded MPFR precision limit” error</h3>\n\n  <p>\n    Herbie computes \"ground truth\" results using\n    <a href=\"http://www.mpfr.org/\">MPFR</a>. For some expressions,\n    like <code>(sin (exp x))</code>, using MPFR in this way requires\n    exponentially many bits to compute a correct result. Instead of\n    simply timing out in such cases, Herbie limits the MPFR precision\n    to 10,000 bits and raises this error when it hits that limit.\n  </p>\n\n  <h3>Missing reports chart on Chrome</h3>\n\n  <p>\n    When using Chrome to view web pages on your local machine, Chrome\n    disables certain APIs for security reasons; this prevents the\n    Herbie reports from drawing the chart. Run Chrome\n    with <code>--allow-file-access-from-files</code> to fix this error.\n  </p>\n\n  <h3 id=\"native-ops\">\"Warning: native <i>operation</i> not supported on your system\"</h3>\n\n  <p>\n    Some systems may not support a native implementation for all\n    operations that Herbie uses. Herbie provides a default fallback\n    implementation which is used by default for functions whose\n    native implementation is not found. You can disable this fallback\n    functionality with <code>--disable precision:fallback</code>.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.2/input.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Input Format</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>The Input Format</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"using-web.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a>'s input format is designed for\n    expressing mathematical functions, which Herbie can then search\n    for accurate implementations of. It also allows specifying the\n    distribution that Herbie draws inputs from when evaluating the\n    accuracy of an expression.\n  </p>\n  \n  <h2 id=\"sec1\">General format</h2>\n\n  <p>Herbie uses the <a href=\"http://fpbench.org\">FPCore</a> format\n  for its input expression, which looks like this:</p>\n\n  <pre>(FPCore (<var>inputs ...</var>) <var>properties ...</var> <var>expression</var>)</pre>\n\n  <p>\n    Each input is a variable, like <code>x</code>, which can be used\n    in the expression, whose accuracy Herbie will try to improve.\n    Properties are <a href=\"#properties\">described below</a>.\n  </p>\n\n  <p>\n    The expression is written in prefix form, with every function call\n    parenthesized, as in Lisp. For example, the formula for the\n    hypotenuse of a triangle with legs <i>a</i> and <i>b</i> is\n  </p>\n\n  <pre>(FPCore (a b) (sqrt (+ (* a a) (* b b))))</pre>\n\n  <p>\n    We recommend the <code>.fpcore</code> file extension for Herbie input files.\n  </p>\n  \n  <h2>Supported functions</h2>\n  \n  <p>\n    Herbie supports all functions\n    from <a href=\"http://pubs.opengroup.org/onlinepubs/7908799/xsh/math.h.html\">math.h</a>\n    with floating-point-only inputs and outputs. The best supported\n    functions, far from the full list, include:\n  </p>\n\n  <dl class=\"function-list\">\n    <dt><code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>, <code>fabs</code></dt>\n    <dd>The usual arithmetic functions<br/><code>-</code> is both negation and subtraction</dd>\n    <dt><code>sqrt</code>, <code>cbrt</code></dt>\n    <dd>Square and cube roots</dd>\n    <dt><code>pow</code>, <code>exp</code>, <code>log</code></dt>\n    <dd>Various exponentiations and logarithms</dd>\n    <dt><code>sin</code>, <code>cos</code>, <code>tan</code></dt>\n    <dd>The trigonometric functions</dd>\n    <dt><code>asin</code>, <code>acos</code>, <code>atan</code>, <code>atan2</code></dt>\n    <dd>The inverse trigonometric functions</dd>\n    <dt><code>sinh</code>, <code>cosh</code>, <code>tanh</code></dt>\n    <dd>The hyperbolic functions</dd>\n    <dt><code>asinh</code>, <code>acosh</code>, <code>atanh</code></dt>\n    <dd>The inverse hyperbolic functions</dd>\n    <dt><code>fma</code>, <code>expm1</code>, <code>log1p</code>, <code>hypot</code></dt>\n    <dd>Specialized numeric functions</dd>\n  </dl>\n\n  <p>Herbie also supports the constants <code>PI</code> and <code>E</code>.</p>\n\n  <p>Herbie links against <code>libm</code> to ensure that every\n  function has the same behavior in Herbie as in your code. However,\n  on Windows platforms some functions are not available in the\n  system <code>libm</code>. In these cases Herbie will use a fallback\n  implementation and print a warning; turning off the\n  the <kbd>precision:fallback</kbd> <a href=\"options.html\">option</a>\n  disables those functions instead.</p>\n\n  <h2>Conditionals</h2>\n  \n  <p>FPCore uses <code>if</code> for conditional expressions:</p>\n\n  <pre>(if <var>cond</var> <var>if-true</var> <var>if-false</var>)</pre>\n\n  <p>\n    An <code>if</code> epxression evaluates the\n    conditional <code>cond</code> and returns either <code>if-true</code> if\n    it is true or <code>if-false</code> if it is not. Conditionals may use:\n  </p>\n  \n  <dl class=\"function-list\">\n    <dt><code>==</code>, <code>!=</code>, <code>&lt;</code>, <code>&gt;</code>, <code>&lt;=</code>, <code>&gt;=</code></dt>\n    <dd>The usual comparison operators</dd>\n    <dt><code>and</code>, <code>or</code>, <code>not</code></dt>\n    <dd>The usual logical operators</dd>\n    <dt><code>TRUE</code>, <code>FALSE</code></dt>\n    <dd>The two boolean values</dd>\n  </dl>\n\n  <p>Note that unlike the arithmetic operators, the comparison functions can take any number of arguments.</p>\n\n  <h2>Intermediate variables</h2>\n  \n  <p>Intermediate variables can be defined using <code>let</code>:</p>\n\n  <pre>(let ([<var>variable</var> <var>value</var>] <var>...</var>) <var>body</var>)</pre>\n\n  <p>\n    In a <code>let</code> expression, all the values are evaluated\n    first, and then are bound to their variables in the body. This\n    means that the value of one variable can't refer to another\n    variable in the same <code>let</code> block; nest <code>let</code>\n    constructs if you want to do that.\n  </p>\n\n  <p>\n    Note that Herbie treats intermediate values only as a notational\n    convenience, and inlines their values before improving the\n    formula's accuracy. Using intermediate variables will not help\n    Herbie improve a formula's accuracy or speed up its run-time.\n  </p>\n\n  <h2 id=\"complex\">Complex Numbers<sup title=\"Supported in beta since Herbie 1.2\">β</sup></h2>\n\n  <p>Herbie includes experimental support for complex numbers;\n  however, this support is currently limited to the basic arithmetic\n  operations. Some of Herbie's internal mechanisms for improving\n  expression accuracy also do not yet support complex-number\n  expressions.</p>\n\n  <p>All input parameters are real numbers; complex numbers must be\n  constructed with <code>complex</code>. The\n  functions <code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>, <code>re</code>, <code>im</code>,\n  and <code>conj</code> are available on complex numbers. Note that\n  complex and real operations use the same syntax; however, complex\n  and real arithmetic cannot be mixed: <code>(+ (complex 1 2)\n  1)</code> is not valid. A type checker will report such errors.</p>\n\n  <p>Complex operations use\n  the <a href=\"https://docs.racket-lang.org/reference/numbers.html#%28tech._complex._number%29\">Racket</a>\n  implementation, so results may differ (slightly) for the complex\n  library used in your language, especially for non-finite complex\n  numbers. Unfortunately, complex number arithmetic is not as\n  standardized as float-point arithmetic.</p>\n\n  <p>In the future, we hope to support complex-number arguments and\n  fully support all complex-number operations.</p>\n\n  <h2 id=\"properties\">Properties</h2>\n\n  <p>Herbie also allows several FPCore properties specified on inputs for additional meta-data:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>:name <var>string</var></code></dt>\n    <dd>Herbie uses this name in its output</dd>\n    <dt><code>:pre <var>test</var></code></dt>\n    <dd>Herbie samples only points that pass the test in the reals</dd>\n    <dt>\n  </dl>\n\n  <p>\n    Several additional properties can be found in the benchmark suite\n    and are used for testing, but are not supported and can change\n    without warning.\n  </p>\n\n  <p>Herbie's output uses custom FPCore properties in its output to\n  provide meta-data about the Herbie improvement process:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>:herbie-status <var>status</var></code></dt>\n    <dd>Describes whether Herbie successfully improved the accuracy of the input; <var>status</var> is one of <code>success</code>, <code>timeout</code>, <code>error</code>, or <code>crash</code>.</dd>\n    <dt><code>:herbie-time <var>ms</var></code></dt>\n    <dd>The time, in milliseconds, used by Herbie to find a more accurate formula.</dd>\n    <dt><code>:herbie-bits-used <var>bits</var></code></dt>\n    <dd>The precision used to find accurate outputs from the formula.</dd>\n    <dt><code>:herbie-error-input ([<var>pts</var> <var>err</var>] ...)</code></dt>\n    <dd>The computed average error of the input program, evaluated on <var>pts</var> points. Multiple entries correspond to multiple training or test sets.</dd>\n    <dt><code>:herbie-error-output ([<var>pts2</var> <var>err1</var>] [<var>pts2</var> <var>err2</var>])</code></dt>\n    <dd>The computed average error of the output program, like above.</dd>\n  </dl>\n\n  <p>Herbie's output also passes through any <code>:name</code>\n  and <code>:pre</code> properties on its inputs.</p>\n\n  <h2>Converting from Herbie 0.9</h2>\n\n  <p>\n    Herbie 0.9 used a <a href=\"../0.9/input.html\">different input\n    format</a>, which is not supported Herbie 1.0 and later. To\n    simplify the transition, the <code>infra/convert.rkt</code> script\n    converts from the old to the new format.\n  </p>\n  \n  <p>To use the conversion tool, run:</p>\n\n  <pre>racket infra/convert.rkt <var>file.rkt</var> > <var>file.fpcore</var></pre>\n  \n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.2/installing.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Installing Herbie</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Installing Herbie</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"using-web.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n  \n  <p>\n    Herbie currently supports Linux, OS X, and\n    Windows<sup title=\"Supported in beta since Herbie 1.2.\">β</sup>.\n  </p>\n\n  <p>\n    <a href=\"../../\">Herbie</a> can be installed from a package or\n    from source. (It is also available in\n    a <a href=\"docker.html\">Docker</a> image.) To install Herbie, first install\n    <a href=\"https://racket-lang.org\">Racket</a>, which Herbie is\n    written in.\n  </p>\n\n  <h2>Installing Racket</h2>\n\n  <p>\n    Use the <a href=\"http://download.racket-lang.org/racket-v6.12.html\">official\n    installer</a> to install Racket, or use distro-provided packages\n    provided they are version 6.7 or later of Racket (earlier versions\n    are not supported).\n  </p>\n\n  <p>\n    Test that Racket is installed correctly and has a correct version:\n  </p>\n\n  <pre><strong>$</strong> racket\nWelcome to Racket v6.12.\n> (exit)</pre>\n  \n  <h2>Installing Herbie from a package</h2>\n\n  <p>Once Racket is installed, install Herbie with:</p>\n\n  <pre>raco pkg install herbie</pre>\n\n  <p>\n    This will install Herbie, compile it for faster startup, and place\n    an executable in your Racket user path, likely\n    into <code>~/.racket/6.12/</code>. If you add this directory to\n    your <code>PATH</code> you will be able to run herbie with\n    the <code>herbie</code> command.\n  </p>\n\n  <h2>Installing Herbie from source</h2>\n\n  <p>\n    Once Racket is installed, download the Herbie source\n    <a href=\"https://github.com/uwplse/herbie\">from GitHub</a> with:\n  </p>\n\n  <pre>git clone https://github.com/uwplse/herbie</pre>\n\n  <p>\n    If you go to the <code>herbie</code> directory,\n    you should see a <code>README.md</code> file, a directory named <code>src</code>,\n    a directory named <code>bench/</code>, and a few other directories.\n    Do a trial run of Herbie to make sure everything is installed and working correctly:\n  </p>\n\n  <pre>racket src/herbie.rkt report bench/tutorial.fpcore graphs/</pre>\n\n  <p>\n    This command will take approximately a minute to run.\n    After the command completes,\n      a directory named <code>graphs</code> should be created.\n    Open the <code>report.html</code> file inside with your browser;\n      you will see a listing of the expressions Herbie was run on,\n      all of which should be green.\n    If not, please check that your Racket installation is at least version 6.7,\n      and if the error still persists,\n      please <a href=\"https://github.com/uwplse/herbie/issues\">submit a bug</a>.\n  </p>\n\n  <p>You can make Herbie start up faster by byte-compiling it:</p>\n\n  <pre>raco make src/herbie.rkt</pre>\n\n  <h2>Installing Herbie from Docker</h2>\n\n  <p>\n    <a href=\"https://docker.com\">Docker</a> is a container manager,\n    which is sort of like an easily-scriptable virtual machine. We do\n    not recommend using Herbie through Docker without prior Docker\n    experience.\n  </p>\n\n  <p>\n    First, <a href=\"https://docs.docker.com/installation/\">install\n    Docker</a>. Docker supports Windows, OS X, and Linux. Depending on\n    how you install Docker, you may need to prefix\n    all <code>docker</code> commands on this page\n    with <code>sudo</code> or run them as the root or administrative\n    user.\n  </p>\n\n  <p>\n    With Docker installed, you should be able to download the Herbie image with:\n  </p>\n \n  <pre>docker pull uwplse/herbie</pre>\n  \n  <p>\n    Check out the <a href=\"docker.html\">Docker page</a> for more on\n    how to run Herbie with Docker.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.2/options.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Command-line Options</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Command-line Options</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"using-web.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    The <a href=\"../../\"><code>herbie</code></a> command has several\n    subcommands and allows multiple options that influence its search\n    procedure and the types of solutions it finds. These options apply\n    both to the report generator and the one-off command-line tool.\n  </p>\n\n  <h2>Herbie commands</h2>\n\n  <p>Herbie can be run both interactively and in batch mode, and can\n  generate output intended either for the command line or the web. We\n  call these different ways of running Herbie different tools. Herbie\n  provides four tools:</p>\n\n  <dl>\n    <dt><code>herbie web</code></dt>\n    <dd>Use Herbie through your browser. <code>herbie web</code>\n    starts a web server for running Herbie on your local machine, and\n    directs a browser to visit that server.</dd>\n\n    <dt><code>herbie shell</code></dt>\n    <dd>Starts a command-line interactive shell for using Herbie.\n    Enter an <a href=\"input.html\">FPCore expression</a> and Herbie\n    will print its more-accurate version.</dd>\n\n    <dt><code>herbie improve input output</code></dt>\n    <dd>Runs Herbie on the expressions in the <code>input</code> file\n    or directory, and outputs the result to <code>output</code>, which\n    will be a single file of FPCore outputs.</dd>\n\n    <dt><code>herbie report input output</code></dt>\n    <dd>Runs Herbie on the expressions in the <code>input</code> file\n    or directory, and produces a directory of HTML web pages that\n    describe Herbie's output, how it derived that output, and\n    additional charts and information about the improvement process.\n    These pages can be viewed in any browser (though with\n    a <a href=\"faq.html\">quirk</a> for Chrome).</dd>\n  </dl>\n\n  <p>We recommend using the web tools, <code>web</code>\n  and <code>report</code>, since HTML allows Herbie to give you more\n  information about how and why it improved a floating-point\n  expression's accuracy. Particularly useful are the graphs it\n  produces of error versus input, which can help you understand\n  whether Herbie's improvements matter for your user cases.</p>\n\n  <p>For any tool, you can run <code>herbie <var>tool</var> --help</code>\n    to see a listing of all available command-line options. This listing\n    will include unsupported options not listed on this page.</p>\n\n  <h2>General options</h2>\n\n  <p>\n    These options can be set on any tool. Pass them after the tool\n    name but before other arguments, such as:\n  </p>\n\n  <pre><code>herbie improve --timeout 60 in.fpcore out.fpcore</code></pre>\n\n  <p>Arguments cannot be put anywhere else.</p>\n\n  <dl>\n    <dt><code>--seed S</code></dt>\n    <dd>The random seed, which changes the randomly-selected points\n      that Herbie evaluates candidate expressions on. The seed is a\n      number between 0 and 2<sup>31</sup> (exclusive both ends). This\n      option can be used to make Herbie's results reproducible or to\n      compare two different runs. Prior versions of Herbie used a\n      different format for seeds, which is also still supported.</dd>\n\n    <dt><code>--num-iters N</code></dt>\n    <dd>The number of improvements Herbie attempts to make to the\n      program. The default, 4, suffices for most programs and helps\n      keep Herbie fast. If this is set very high, Herbie may run out\n      of things to do and terminate before the given number of\n      iterations, but in practice iterations beyond the first few\n      rarely lead to lower error. This option can be increased to 5 or\n      higher to check that there aren't further improvements that Herbie\n      could seek out.</dd>\n\n    <dt><code>--num-points N</code></dt>\n    <dd>The number of randomly-selected points used to evaluate\n      candidate expressions. The default, 256, gives good behavior for\n      most programs. The more points sampled, the slower Herbie is.\n      This option can be increased to 512 or 1024 if Herbie gives very\n      inconsistent results between runs with different seeds.</dd>\n    \n    <dt><code>--timeout T</code></dt>\n    <dd>The timeout to use per-example, in seconds. A fractional\n    number of seconds can be given.</dd>\n\n    <dt><code>--threads N</code>, for <code>improve</code> and <code>reports</code></dt>\n    <dd>Enables multi-threaded operation. By default, no threads are\n      used. A number can be passed to this option to use that many\n      threads, or <code>yes</code> can be passed to tell Herbie to use\n      all but one of the hardware threads.</dd>\n  </dl>\n\n  <h2>Web shell options</h2>\n  \n  <p>The <code>web</code> tool runs Herbie as a web server, and\n  connects to it from your browser. It has additional options to\n  control this server.</p>\n  \n  <dl>\n    <dt><code>--port N</code></dt>\n    <dd>The port to run the Herbie server on. The default port is 8000.</dd>\n\n    <dt><code>--save-session dir</code></dt>\n    <dd>Save all the reports for expressions enterred into the web\n    shell to this directory. The directory is also used as a\n    cache of already-computed expressions.</dd>\n\n    <dt><code>--log file</code></dt>\n    <dd>Write a web access log to this file. The file is formatted\n    similarly to Apache logs. If Herbie crashes for some reason, this\n    log will <emph>not</emph> contain a traceback.</dd>\n\n    <dt><code>--quiet</code></dt>\n    <dd>When set, a browser is not started to point to the server main\n    page, and a smaller banner is printed to the command line.</dd>\n  </dl>\n\n  <h2>Rulesets</h2>\n\n  <p>\n    Herbie uses a set of rewrite rules to define the changes it is\n    allowed to make to formulas to improve their accuracy. These rules\n    can be turned on and off in groups using <code>--disable\n    rules:<var>group</var></code> and <code>--enable\n    rules:<var>group</var></code>. In general, enabling more rules\n    should only improve the accuracy of Herbie's output. However, if\n    certain functions are not available on your platform, disabling\n    the rules associated with those functions will prevent Herbie from\n    using them.\n  </p>\n\n  <p>The full list of rule groups is:</p>\n\n  <table class=\"function-list\">\n    <thead><tr><th>Rule Group</th><th>Topic of rewrite rules</th></tr></thead>\n    <tr><td>arithmetic</td><td>Basic arithmetic facts</td></tr>\n    <tr><td>polynomials</td><td>Factoring and powers</td></tr>\n    <tr><td>fractions</td><td>Fraction arithmetic</td></tr>\n    <tr><td>exponents</td><td>Exponentiation identities</td></tr>\n    <tr><td>trigonometry</td><td>Trigonometric identities</td></tr>\n    <tr><td>hyperbolic</td><td>Hyperbolic trigonometric identities</td></tr>\n    <tr><td>special</td><td>Special mathematical functions</td></tr>\n    <tr><td>complex</td><td>Complex number arithmetic</td></tr>\n    <tr><td>numerics</td><td>Special numerical functions <code>expm1</code>, <code>log1p</code>, <code>fma</code>, and <code>hypot</code></td></tr>\n  </table>\n\n  <p>All groups except <code>numerics</code> are enabled by default,\n  and we recommend turning it on if these functions are available in\n  your language. If complex arithmetic or special mathematical\n  functions are poorly implemented in your language, you may wish to\n  disable those rule groups as well.</p>\n\n  <h2>Search options</h2>\n\n  <p>\n    These options influence the fine properties of Herbie's search, most\n    importantly the types of transformations that Herbie uses to find\n    candidate programs. These options offer very fine-grained control\n    over Herbie's output, and are only recommended for advanced uses of\n    Herbie.\n  </p>\n\n  <p>\n    Each option can be turned off with the <code>-o X</code>\n    or <code>--disable X</code> command-line flag, and turned on with\n    the <code>+o X</code> or <code>--enable X</code>. The defaults are\n    the recommended options; turning a default-on option off typically\n    results in less-accurate results, while turning a default-off\n    option on typically results in more-complex and more-surprising\n    output expressions.\n  </p>\n\n  <dl>\n    <dt><code>precision:double</code></dt>\n    <dd>This option, on by default, tells Herbie to treat its input as\n      double-precision calculations. If turned off, Herbie treats its\n      input as a single-precision calculation.</dd>\n\n    <dt><code>precision:fallback</code></dt>\n    <dd>This option, on by default, tells Herbie to use fallback\n      functions if a native implementation is not found for any\n      operations. If turned off, operations with no native\n      implementation will be disabled from use in the input or output.\n      You will want to turn this option off if you are concerned with\n      the specific behavior of libm functions.</dd>\n\n    <dt><code>setup:simplify</code></dt>\n    <dd>This option, on by default, simplifies the expression before\n      passing it to Herbie. If turned off, Herbie will not simplify\n      input programs before improving them. You will want to turn off\n      this option if simplifying the program will create a lot of\n      error, say if the association of operations is cleverly\n      chosen.</dd>\n\n    <dt><code>setup:early-exit</code></dt>\n    <dd>This option, off by default, causes Herbie to exit without\n      modifying the input program if it determines that the input\n      program has less than 0.1 bits of error. You will want to turn\n      this option on if you are running Herbie on a large corpus of\n      programs that you do not believe to be inaccurate.</dd>\n\n    <dt><code>generate:rr</code></dt>\n    <dd>This option, on by default, uses Herbie's recursive rewriting\n      algorithm to generate candidate programs. If turned off, Herbie\n      will use a non-recursive rewriting algorithm, which will\n      substantially limit the candidates Herbie finds. You will rarely\n      want to turn this option off.</dd>\n\n    <dt><code>generate:taylor</code></dt>\n    <dd>This option, on by default, uses series expansion to produce\n      new candidates during the main improvement loop. If turned off,\n      Herbie will not use series expansion in the main improvement loop.\n      You will want to turn this option off if you want to avoid\n      series-expansion-based rewrites, such as if you need to preserve\n      the equivalence of the input and output expressions as real-number\n      formulas.</dd>\n\n    <dt><code>generate:simplify</code></dt>\n    <dd>This option, on by default, simplifies candidates during the\n      main improvement loop. If turned off, candidates will not be\n      simplified, which typically results in much less accurate\n      expressions, since simplification is often necessary for\n      cancelling terms. You will rarely want to turn this option off.</dd>\n\n    <dt><code>reduce:regimes</code></dt>\n    <dd>This option, on by default, uses Herbie's regime inference\n      algorithm to branch between several program candidates. If\n      turned off, branches will not be inferred and the output program\n      will be straight-line code (if the input was). You will want to\n      turn this option off if your programming environment makes\n      branches very expensive, such as in some cases of GPU\n      programming.</dd>\n\n    <dt><code>reduce:simplify</code></dt>\n    <dd>This option, on by default, uses a final simplification pass\n      after all improvements have been made. This sometimes improves\n      accuracy further. If turned off, this final simplification pass\n      will not be done. You will rarely want to turn this option\n      off.</dd>\n\n    <dt><code>reduce:avg-error</code></dt>\n    <dd>This option, on by default, causes Herbie to output the\n      candidate with the best average error over the chosen inputs. If\n      turned off, Herbie will choose the candidate with the least\n      maximum error instead. This usually produces programs with worse\n      overall accuracy. You may want to turn this option off if\n      worst-case accuracy is more important to you than overall\n      accuracy.</dd>\n\n    <dt><code>reduce:binary-search</code></dt>\n    <dd>This option, on by default, uses binary search to refine the\n      values used in <code>if</code> statement conditionals. This\n      makes different runs of Herbie produce more similar results, and\n      improves accuracy near those values. If turned off, binary\n      search will not be used, and the branch values will be less\n      accurately chosen. You will want to turn this option off if\n      behavior near branches is not important to you, in which case\n      turning off this option will make Herbie slightly faster.</dd>\n\n    <dt><code>reduce:branch-expressions</code></dt>\n    <dd>This option, on by default, allows Herbie to branch on\n      expressions, not just variables. This can improve accuracy on\n      regime branching, but can significantly increase the runtime,\n      particularly for large programs. If turned off, Herbie will only\n      try to branch on variables. You may want to turn this option off\n      if Herbie runtime is more important to you than expression\n      accuracy.</dd>\n  </dl>\n\n  <h2>Upgrading from Herbie 1.0</h2>\n\n  <p>Herbie 1.0 used\n  a <a href=\"../1.0/using-herbie.html\">different</a> command line\n  syntax, without multiple tools. Translate like so:</p>\n\n  <ul>\n    <li><code>herbie-1.0</code> → <code>herbie-1.1 shell</code></li>\n    <li><code>herbie-1.0 file</code> → <code>herbie-1.1 improve file -</code></li>\n    <li><code>herbie-1.0 files ...</code> → <code>cat files ... | herbie-1.1 improve - -</code><br/>\n      Alternatively, collect the files into a directory and run <code>herbie-1.1 improve dir/ -</code></li>\n  </ul>\n\n  <p>The new syntax somewhat changes Herbie's behavior, such as by\n    using the input expression as the output if Herbie times out. It\n    also makes it easier to write Herbie's output to a file without\n    using command-line redirection. The old syntax still works but is\n    deprecated and will be removed in the next release.</p>\n\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.2/release-notes.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie 1.2 Release Notes</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <script src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML\"></script>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Herbie 1.2 Release Notes</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"using-web.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    The <a href=\"../..\">Herbie</a> developers are excited to announce\n    Herbie 1.2! This release focuses on <em>accuracy and\n    reliability</em>, including better conditionals, more accurate\n    defaults, and significant bug fixes to the core algorithms.\n  </p>\n\n  <p>\n    Herbie automatically improves the accuracy of floating point\n    expressions. This avoids the bugs, errors, and surprises that so\n    often occur when working with floating point. Since\n    our <a href=\"../../papers.html\">PLDI'15 paper</a>, we've been hard at\n    work making Herbie more versatile and easier to use.\n  </p>\n\n  <img width=\"100%\" src=\"team.png\" style=\"display: block; margin: 4em 0;\" />\n\n  <h2>Breaking Changes and Deprecations</h2>\n\n  <ul>\n    <li> This release fixes a significant and important bug in\n      Herbie's measurement of program accuracy. Herbie's prior results\n      had a small chance of recommending an inaccurate program as\n      accurate. </li>\n    <li> In line\n      with <a href=\"http://fpbench.org/spec/fpcore-1.0.html\">FPCore\n      1.0</a>, we have deprecated the <code>sqr</code>\n      and <code>cube</code> functions.</li>\n    <li> Herbie no longer\n      supports <a href=\"https://racket-lang.org\">Racket</a> versions\n      prior to 6.7. Future Herbie releases may continue to step up\n      supported Racket versions to make better use of recent language\n      features.</li>\n  </ul>\n\n  <h2>Improvement to core algorithm</h2>\n\n  <ul>\n    <li>Herbie now uses a more rigorous algorithm to evaluate its results,\n      both increasing reproducibility of its results and better measuring\n      its output.</li>\n    <li>Herbie has become much more inventive in what expressions it\n      can branch on. This leads to more accurate results in many\n      cases. The <kbd>reduce:branch-expressions</kbd>\n      <a href=\"options.html\">option</a> controls this feature.</li>\n    <li>Herbie now uses a binary search algorithm to choose more\n      accurate values for conditionals in <code>if</code> statements.\n      This should make different runs of Herbie produce more similar\n      results. The <kbd>reduce:binary-search</kbd>\n      <a href=\"options.html\">option</a> controls this feature.</li>\n    <li>Herbie has a higher default value for\n      the <code>--num-iters</code> <a href=\"options.html\">parameter</a>.\n      Users should expect Herbie to be slower but to produce more\n      accurate results.</li>\n    <li>A significant bug in the series expansion algorithm has been\n      fixed, improving Herbie's performance in the presence of\n      logarithms.</li>\n    <li>A small tweak to the simplification algorithm results in\n      simpler and more accurate output from Herbie.</li>\n  </ul>\n\n  <h2>Beta-quality features</h2>\n\n  <ul>\n    <li>Herbie now supports basic operations\n      on <a href=\"input.html#complex\">complex numbers</a>, using\n      the <code>complex</code>, <code>re</code>, and <code>im</code>\n      functions. We look forward to releasing high-quality complex\n      number support in the future.</li>\n    <li>Herbie now supports Windows. Note that the Bessel functions\n      are not available in the Windows <code>math.h</code> library and\n      use a fallback. The <kbd>precision:fallback</kbd>\n      <a href=\"options.html\">option</a> controls this feature.</li>\n  </ul>\n\n  <figure class=\"showcase\" style=\"background: white; border: 1px solid gray;\">\n    <style scoped>.arrow { text-align: center; font-size: 200%; }</style>\n    <div class=\"program\">\\[c0 \\cdot \\sqrt{\\frac{A}{V \\cdot \\ell}}\\]</div>\n    <div class=\"arrow\">↓</div>\n    <div class=\"program\">\\[\\begin{array}{l}\n\\mathbf{if}\\;\\frac{1}{V \\cdot \\ell} \\le -3.767671897931721 \\cdot 10^{+27}:\\\\\n\\;\\;\\;\\;\\frac{c0 \\cdot \\sqrt{1}}{\\sqrt{\\frac{V \\cdot \\ell}{A}}}\\\\\n\n\\mathbf{elif}\\;\\frac{1}{V \\cdot \\ell} \\le -2.9824307461679933 \\cdot 10^{-248}:\\\\\n\\;\\;\\;\\;\\left(c0 \\cdot \\sqrt{\\sqrt{\\frac{A}{V \\cdot \\ell}}}\\right) \\cdot \\sqrt{\\sqrt{\\frac{A}{V \\cdot \\ell}}}\\\\\n\n\\mathbf{elif}\\;\\frac{1}{V \\cdot \\ell} \\le 7.59312080698644 \\cdot 10^{-301}:\\\\\n\\;\\;\\;\\;c0 \\cdot \\sqrt{\\frac{\\frac{A}{V}}{\\ell}}\\\\\n\n\\mathbf{else}:\\\\\n\\;\\;\\;\\;c0 \\cdot \\frac{\\sqrt{A}}{\\sqrt{V \\cdot \\ell}}\\\\\n\n\\end{array}\\]</div>\n    <figcaption>A program produced by the new branch inference system\n    in Herbie 1.2. Herbie 1.2 is more creative and produces more\n    accurate output than prior versions.</figcaption>\n  </figure>\n\n  <h2>Usability improvements</h2>\n\n  <ul>\n    <li>A new <a href=\"report.html#try-it\">Try It</a> feature in\n      reports lets you run the input program and Herbie's suggested\n      version on argument values of your choice.</li>\n    <li>Herbie can now efficiently sample from preconditions such\n      as <code>(or (&lt; 1 x 2) (&lt; 1001 x 1002))</code>. Previously\n      such preconditions would produce the dreaded\n      “<a href=\"faq.html#sample-valid-points\">could not sample</a>”\n      error message.</li>\n    <li>Herbie's web output now includes additional descriptive text,\n      such as color keys, and additional intuitive interactions, such\n      as clicking on report page arrows.</li>\n    <li>Herbie's FPCore output now includes\n      its <a href=\"input.html#properties\">error estimates</a>, making\n      this information easier for other tools to access.</li>\n    <li><code>let</code> statements and variary arithmetic operators\n      are now supported in preconditions.</li>\n    <li>Herbie will now type-check inputs and report errors for\n      mismatches, helping further cut down on confusing error\n      messages.</li>\n    <li>User errors and Herbie crashes now look different in\n      reports.</li>\n  </ul>\n\n  <h2>Code Cleanup</h2>\n\n  <ul>\n    <li>Many bugs fixed, including missing rules, infinite loops, and\n      a few crashes in exceptional circumstances.</li>\n    <li>Herbie’s HTML output now uses the Racket XML library,\n      eliminating the possibility of generating invalid HTML.</li>\n    <li>Herbie uses a new mechanism for defining supported functions,\n      which should make it easier to add functions in the future.</li>\n  </ul>\n  \n  <h2>Try it out!</h2>\n\n  <p>\n    We're excited to continue to improve Herbie and make it more\n    useful to scientists, engineers, and programmers around the world.\n    We've got a lot of features we're excited to work on in the coming\n    months. Please\n    <a href=\"https://github.com/uwplse/herbie/issues\">report bugs</a>,\n    join\n    <a href=\"https://mailman.cs.washington.edu/mailman/listinfo/herbie\">the\n    mailing list</a>,\n    or <a href=\"https://github.com/uw-plse/herbie\">contribute</a>.\n  </p>\n  \n  <p><em style=\"font-weight: bold; font-style: roman;\">If you find Herbie useful, <a href=\"mailto:herbie@cs.washington.edu\">let us know!</em></p>\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.2/report.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie reports</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Herbie reports</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"using-web.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  \n  <h1>The Herbie report</h1>\n\n  <p>The Herbie report, which is output by\n  the <a href=\"using-web.html\">Herbie web commands</a>, lists five items.</p>\n\n  <h2 id=\"summary\">Summary numbers</h2>\n\n  <p>First, a brief summary of the results.\n    For most uses, the “Average Error”\n      number, which summarizes how accurate the input and output\n      expressions are, is the most important number in this section.\n    The other numbers are:\n      the time Herbie took to improve the program;\n      the precision Herbie assumed floating-point operations\n      (which can be set at the <a href=\"options.html\">command line</a>);\n      and the internal precision used to ensure accurate results.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-large.png\" />\n    <figcaption>A summary of results from a Herbie report.</figcaption>\n  </figure>\n\n  <h2 id=\"programs\">Input and output programs</h2>\n\n  <p>Second, the input and output programs themselves.\n    These are printed in standard mathematical syntax.\n    Library functions not often used by mathematicians,\n      including <code>atan2</code>, <code>expm1</code>,\n      <code>fma</code>, <code>hypot</code>, <code>lgamma</code>,\n      <code>log1p</code>, and <code>logb</code>\n      are drawn with a sub- or super-script asterisk,\n      while <code>if</code> statements are rendered as in a program.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-prog.png\" />\n    <figcaption>Input and output program from a Herbie report.</figcaption>\n  </figure>\n\n  <h2 id=\"graph\">Error graph</h2>\n\n  <p>\n    Third, under <em>Error</em>, a graph of floating-point error\n    versus input value. This is helpful for understanding the sorts of\n    inputs Herbie is improving accuracy on. Sometimes, Herbie improved\n    accuracy on some inputs at the cost of accuracy on other inputs\n    that you care more about. In these cases, you can add\n    a <code>:pre</code>condition to restrict the inputs Herbie reasons\n    about.\n  </p>\n\n  <p>\n    On these graphs, the red line is the error of the input program,\n    while the blue line is the error of the output program\n    (both can be toggled).\n    For expressions with multiple variables,\n    the variable on the horizontal axis can be selected.\n    If Herbie decided to insert\n    an <code>if</code> statement into the program,\n    the locations of those <code>if</code> statements\n    will be marked with vertical bars.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-error.png\" />\n    <figcaption>An error graph from a Herbie report. Note the variable\n    selector (<code>x</code> is selected) and the toggles for the\n    input and output program (both are toggled on).</figcaption>\n  </figure>\n\n  <h2 id=\"try-it\">Try it</h2>\n\n  <p>\n    Fourth, a form where you can try out specific inputs on the input\n    program and Herbie's output program. Enter the argument values on\n    the left, and the input and output programs will be evaulated on\n    those arguments and the results printed on the right.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-try-it.png\" />\n    <figcaption>\n      Try it out section on a simple program.\n    </figcaption>\n  </figure>\n\n  <h2 id=\"derivation\">Derivation</h2>\n\n  <p>Fifth, a derivation of the output from the input.\n    For complex or unexpected programs, these can be helpful.\n    Each substantive step in the derivation also lists the error,\n    in bits, of that step's output.</p>\n\n  <p>The derivations may name rules built into Herbie,\n    or may claim derivation steps are done by simplification,\n    series expansion, or other Herbie strategies. The derivation will\n    also call out splits of the input into regimes, and strategies\n    Herbie is invoking. When one part of the term is colored blue,\n    that is the only part of the term modified by the operation.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-derivation.png\" />\n    <figcaption>A short derivation from a Herbie report. Note the\n    error at each step, in bits, in gray.</figcaption>\n  </figure>\n\n  <h2 id=\"time\">Runtime information</h2>\n  \n  <p>Sixth and finally, a breakdown of Herbie's runtime.\n    This can usually be ignored.\n    The colored bar is a timeline of Herbie's run,\n    with each section of the bar sized proportionally to its runtime,\n    and each color corresponding to a strategy;\n    hover over that section of the bar to learn which strategy.</p>\n\n  <p>If you find a bug, include the code snippet in this section when\n  filing the bug. Please also include the debug log linked from this block.</p>\n    \n  <figure>\n    <img width=\"100%\" src=\"report-runtime.png\" />\n    <figcaption>Runtime breakdown from a Herbie report.</figcaption>\n  </figure>\n\n  <p>We expect the report to grow more informative with future\n  versions. Please <a href=\"mailto:herbie@cs.washington.edu\">get in\n  touch</a> if there is more information you'd like to see.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.2/using-cli.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie from the Command Line</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Using Herbie from the Command Line</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"using-web.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> rewrites floating point expressions to\n    make them more accurate. The expressions could come from\n    anywhere—your source code, mathematical papers, or even the output\n    of <a href=\"../1.0/using-herbgrind.html\">Herbgrind</a>, our tool for\n    finding inaccurate expressions in binaries. This tutorial runs\n    Herbie on the benchmark programs that Herbie ships with.\n  </p>\n\n  <p>Herbie can be used from the command-line\n  or from <a href=\"using-web.html\">the browser</a>. This page covers\n  using Herbie from the command line.</p>\n\n  <h2>Input expressions</h2>\n\n  <p>\n    Herbie ships a collection of benchmarks in its <code>bench/</code>\n    directory. For example, <code>bench/tutorial.fpcore</code>\n    contains the following code:\n  </p>\n\n  <pre>(FPCore (x)\n  :name \"Cancel like terms\"\n  (- (+ 1 x) x))\n\n(FPCore (x)\n  :name \"Expanding a square\"\n  (- (sqr (+ x 1)) 1))\n\n(FPCore (x y z)\n  :name \"Commute and associate\"\n  (- (+ (+ x y) z) (+ x (+ y z))))</pre>\n\n  <p> This code defines three floating point expressions that we want\n    to run Herbie on:</p>\n\n  <ul>\n    <li><code>(1 + x) - x</code>, titled “Cancel like terms”</li>\n    <li><code>(x + 1)² - 1</code>, titled “Expanding a square”</li>\n    <li><code>((x + y) + z) - (x + (y + z))</code>, titled “Commute\n    and associate”</li>\n  </ul>\n\n  <p>You can check out our <a href=\"input.html\">input format\n    documentation</a> for more about the Herbie input format. </p>\n\n  <h2 id=\"interactive\">The Herbie shell</h2>\n\n  <p>\n    The Herbie shell lets you interact with Herbie, typing in\n    benchmark expressions and seeing the outputs. Run the Herbie\n    shell:\n  </p>\n\n  <pre>herbie shell</pre>\n\n  <p>\n    After a few seconds, Herbie will start up and wait for input:\n  </p>\n\n  <pre><strong>$</strong> herbie shell\nHerbie 1.2 with seed #(891614428 1933754021 544017565 2852994348 404070416 672462396)\nFind help on <https://herbie.uwplse.org/>, exit with Ctrl-D\nherbie> </pre>\n\n  <p>\n    The printed seed can be used to reproduce a Herbie run. You can\n    now paste inputs directly into your terminal for Herbie to\n    improve:\n  </p>\n\n  <pre>(FPCore (x) :name \"Cancel like terms\" (- (+ 1 x) x))\n(FPCore (x) <var>...</var> 1)</pre>\n\n  <p>\n    Interactive use is helpful if you want to play with different\n    expressions and try multiple variants, informed by Herbie's\n    advice. Note that Herbie will print a variety of additional\n    information (like its error estimates and how long it took to\n    process your input) in the <var>...</var> portion of the output.\n  </p>\n\n  <h2 id=\"batch\">Batch processing FPCore</h2>\n\n  <p>\n    Alternatively, you can run Herbie on a file with multiple\n    expressions in it, producing the output expressions to a file.\n    This mode is intended for use by scripts.\n  </p>\n\n  <pre><strong>$</strong> herbie improve bench/tutorial.fpcore out.fpcore\nSeed: 921081490\n  1/3   [ 1563.552ms]\tCancel like terms\t(29→ 0)\n  2/3   [ 4839.121ms]\tExpanding a square\t(38→ 0)\n  3/3   [ 3083.238ms]\tCommute and associate\t( 0→ 0)</pre>\n\n  <p>\n    The output file <code>out.fpcore</code> contains more accurate\n    versions of each program:\n  </p>\n\n  <pre>;; seed: #(3123212801 2137904229 2993294009 3035080405 3708006222 26032508)\n\n(FPCore (x) 1)\n(FPCore (x) (* (+ 2 x) x))\n(FPCore (x y z) 0)</pre>\n\n  <p>\n    Note that the order of expressions is identical.\n    For more control over Herbie, see the documentation of\n    Herbie's <a href=\"options.html\">command-line options</a>.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.2/using-web.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie from the Browser</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Using Herbie from the Browser</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"using-web.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> rewrites floating point expressions to\n    make them more accurate. The expressions could come from\n    anywhere—your source code, mathematical papers, or even the output\n    of <a href=\"../1.0/using-herbgrind.html\">Herbgrind</a>, our tool for\n    finding inaccurate expressions in binaries. This tutorial runs\n    Herbie on the benchmark programs that Herbie ships with.\n  </p>\n\n  <p>Herbie can be used from <a href=\"using-cli.html\">the\n  command-line</a> and from the browser. This page covers\n  using Herbie from the browser.</p>\n\n\n  <h2 id=\"interactive\">The Herbie web shell</h2>\n\n  <p>\n    The Herbie web shell lets you interact with Herbie through your\n    browser, featuring a convenient input format. Run the Herbie web\n    shell:\n  </p>\n\n  <pre>herbie web</pre>\n\n  <p>\n    After a few seconds, the web shell will rev up and direct your\n    browser to the main web shell page:\n  </p>\n  \n  <pre><strong>$</strong> herbie web\nYour Web application is running at http://localhost:8000/.\nStop this program at any time to terminate the Web Server.</pre>\n\n  <figure>\n    <img width=\"100%\" src=\"web-main.png\" />\n    <figcaption>The input page for the web shell.</figcaption>\n  </figure>\n\n  <p>\n    As in the screenshot, you can type expressions, in standard\n    mathematical syntax (parsed\n    by <a href=\"http://mathjs.org\">Math.js</a>), and\n    hit <kbd>Enter</kbd> to have Herbie attempt to improve them.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"web-progress.png\" />\n    <figcaption>Herbie improvement in progress.</figcaption>\n  </figure>\n\n  <p>\n    The web shell will print Herbie's progress, and redirect to a\n    <a href=\"report.html\">report</a> once Herbie is done.\n  </p>\n\n  <p>\n    Interactive use of the web shell is the friendliest and easiest\n    way to use Herbie. The web shell has <a href=\"options.html\">many\n    options</a>, including automatically saving the generated reports.\n  </p>\n\n\n  <h2 id=\"batch\">Batch report generation</h2>\n\n  <p>A <a href=\"report.html\">report</a> can also be generated directly\n  from a file of input expressions:</p>\n  \n  <pre><strong>$</strong> herbie report input.fpcore output/\nStarting Herbie on 3 problems...\nSeed: 921081490\n  1/3\t[ 7108.190ms]\t(39→ 0)\tExpanding a square\n  2/3\t[ 1894.348ms]\t( 0→ 0)\tCommute and associate\n  3/3\t[ 873.3889ms]\t(29→ 0)\tCancel like terms</pre>\n\n  <p>\n    This command asks Herbie to generate a report from the input\n    expressions in <code>input.fpcore</code> and save the report in\n    the directory <code>output/</code>, which ought not exist yet.\n    The printed seed can be used to reproduce a run of Herbie.\n  </p>\n\n  <p>\n    Once generated, open the <code>output/report.html</code> page\n    in your favorite browser (but see <a href=\"faq.html\"> the FAQ</a>\n    if you're using Chrome). From that page, you can click on the rows\n    in the table at the bottom to see the report for that expression.\n  </p>\n\n  <p>Batch report generation is the most informative way to run Herbie\n  on a large collection of inputs. Like the web shell, it can be\n  customized through <a href=\"options.html\">command-line options</a>,\n  including running Herbie in multiple threads at once.</p>\n\n\n  <h2>Input expressions</h2>\n\n  <p>An example input file can be found in <code>bench/tutorial.fpcore</code>:</p>\n  \n  <pre>(FPCore (x)\n  :name \"Cancel like terms\"\n  (- (+ 1 x) x))\n\n(FPCore (x)\n  :name \"Expanding a square\"\n  (- (* (+ x 1) (+ x 1)) 1))\n\n(FPCore (x y z)\n  :name \"Commute and associate\"\n  (- (+ (+ x y) z) (+ x (+ y z))))</pre>\n  \n  <p> This code defines three floating point expressions that we want\n    to run Herbie on:</p>\n\n  <ul>\n    <li><code>(1 + x) - x</code>, titled “Cancel like terms”</li>\n    <li><code>(x + 1)² - 1</code>, titled “Expanding a square”</li>\n    <li><code>((x + y) + z) - (x + (y + z))</code>, titled “Commute\n    and associate”</li>\n  </ul>\n\n  <p>You can check out our <a href=\"input.html\">input format\n    documentation</a> for more about the Herbie input format. </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.3/docker.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie on Docker</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Installing with Docker</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a>'s is available\n    through <a href=\"https://www.docker.com/\">Docker</a>, which is a\n    sort of like an easily-scriptable virtual machine. This page\n    describes how to install\n    the <a href=\"https://hub.docker.com/uwplse/herbie\">official Docker\n    image</a> for Herbie.\n  </p>\n  \n  <p>\n    Herbie can also be <a href=\"installing.html\">installed\n    normally</a>.\n  </p>\n  \n  <h2>Installing the Herbie image</h2>\n\n  <p>\n    First, <a href=\"https://docs.docker.com/installation/\">install\n    Docker</a>. Docker supports Windows, macOS, and Linux. Depending\n    on how you install Docker, you may need to prefix\n    the <code>docker</code> command with <code>sudo</code> or run them\n    as the administrative user.\n  </p>\n\n  <p>With Docker installed, download the Herbie image:</p>\n \n  <pre class=\"shell\">docker pull uwplse/herbie</pre>\n\n  <p>You can now run Herbie:</p>\n\n  <pre>docker run -it uwplse/herbie shell</pre>\n  \n  <p>This will run the <a href=\"using-cli.html\">Herbie shell</a>,\n  reading input from the standard input.</p>\n  \n  <p>Note that Herbie in Docker is more limited; for example, it will\n  not recognize plugins installed outside the Docker container.</p>\n\n  <h2>Running the web shell</h2>\n\n  <p>Running the web shell in Docker requires exposing the ports\n  inside the container. The Herbie Docker image binds to port 80 by\n  default; use the <code>-p &lt;hostport&gt;:80</code> option to\n  Docker to expose Herbie on whatever port you choose.\n  </p>\n\n  <pre class=\"shell\">docker run -it --rm -p 8000:80 uwplse/herbie</pre>\n\n  <p>\n    If you are using the <code>--log</code>\n    or <code>--save-session</code> flags for the web shell,\n    you will also need to mount the relevant directories into the\n    Docker container using the <code>-v</code> Docker option, as in\n    the examples below.\n  </p>\n\n  <h2>Generating files and reports</h2>\n\n  <p>\n    To use Herbie in <a href=\"using-cli.html\">batch mode</a>, you will\n    need to mount the input in the Docker container. Do that with:\n  </p>\n  \n  <pre class=\"shell\">docker run -it --rm \\\n    -v <var>in-dir</var>:/in \\\n    -v <var>out-dir</var>:/out \\\n    -u $USER \\\n    uwplse/herbie improve /in/<var>in-file</var> /out/<var>out-file</var></pre>\n\n  <p>\n    In this command, you are asking Herbie to read input\n    from <var>in-file</var> in <var>in-dir</var>, and write output\n    to <var>out-file</var> in <var>out-dir</var>. The command looks\n    the same if you want Herbie to read input from a directory;\n    just leave <var>in-file</var> blank.\n  </p>\n\n  <p>\n    To generate reports from Herbie, you can run:\n  </p>\n\n  <pre class=\"shell\">docker run -it --rm \\\n    -v <var>in-dir</var>:/in \\\n    -v <var>out-dir</var>:/out \\\n    -u $USER \\\n    uwplse/herbie report /in/<var>in-file</var> /out/</pre>\n\n  <p>\n    As before, the input and output directories must be mounted inside\n    the Docker container. Note that both here and above, the user is\n    set to the current user. This is to ensure that the files Herbie creates\n    have the correct permissions set.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.3/faq.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie FAQ</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Frequently Asked Questions</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p><a href=\"../../\">Herbie</a> automatically transforms floating\n  point expressions into more accurate forms. This page troubleshoots\n  common Herbie errors.</p>\n\n\n  <h2>Common errors</h2>\n\n  <p>\n    Herbie error messages refer here for additional information and\n    debugging tips.\n  </p>\n\n  <h3 id=\"invalid-syntax\">Invalid syntax</h3>\n\n  <p>\n    This error means you mis-formatted Herbie's input. Common errors\n    include misspelled function names and parenthesized expressions\n    that should not be parenthesized. For example, in\n    <code>(- (exp (x)) 1)</code>, the expression <code>x</code> is a\n    variable so shouldn't be parenthesized. <code>(- (exp x) 1)</code>\n    would be the correct way of writing that expression. Please review\n    the <a href=\"input.html\">input format</a> documentation for more.\n  </p>\n\n  <h3 id=\"sample-valid-points\">Cannot sample enough valid points</h3>\n\n  <p>This error occurs when Herbie is unable to find enough valid\n  points. For example, the expression <code>(acos (+ 1000 x))</code>\n  only yields a valid result when <code>x</code> is between -1001 and\n  -999, a rather narrow range. The solution is to help out Herbie by\n  specifying a precondition: <code>:pre (&lt; -1001 x -999)</code>.\n  Herbie will use the precondition to improve its sampling strategy.\n  </p>\n\n  <h3 id=\"no-valid-values\">No valid values</h3>\n\n  <p>This error indicates that your precondition excludes all possible\n  inputs. For example, the precondition <code>(&lt 3 x 2)</code>\n  excludes all inputs. Herbie raises this exception when it can prove\n  that no inputs could work. The solution is to fix the precondition\n  to allow some inputs.</p>\n\n  <h3 id=\"mpfr-prec-limit\">Exceeded MPFR precision limit</h3>\n\n  <p>This rare error indicates that Herbie could not compute a \"ground\n  truth\" for your expression. For some expressions, like <code>(sin\n  (exp x))</code>, calculating a correct output for large input values\n  requires exponentially many bits. Herbie raises this error when more\n  than 10,000 bits are required.</p>\n\n\n  <h2>Common warnings</h2>\n\n  <p>Herbie warnings refer here for explanations and common actions to\n  take.</p>\n\n  <h3 id=\"ground-truth\">Could not determine a ground truth</h3>\n\n  <p>\n    Herbie will raise this warning when some inputs require more than\n    10 000 bits to compute an exact ground truth value. For example,\n    to compute <code>(/ (exp x) (exp x))</code> for very\n    large <code>x</code>, absurdly large exponents would be required.\n    Herbie discards such inputs and raises this warning. If you see\n    this warning, you should add a restrictive precondition, such\n    as <code>:pre (&lt; -100 x 100)</code>, to prevent large inputs.\n  </p>\n\n  <h3 id=\"native-ops\">Native <var>operation</var> not supported on your system</h3>\n\n  <p>\n    Some systems do not have native implementations for all operations\n    that Herbie uses. (For example, Microsoft's <code>math.h</code>\n    does not provide the <code>y0</code> function.) Herbie provides a\n    fallback implementation, but you can disable the fallback\n    with <code>--disable precision:fallback</code>.\n  </p>\n\n\n  <h2>Known bugs</h2>\n\n  <p>Some bugs cannot be directly fixed and are documented here.</p>\n\n  <h3>Missing reports chart on Chrome</h3>\n\n  <p>\n    When using Chrome to view web pages on your local machine, Chrome\n    disables certain APIs for security reasons; this prevents the\n    Herbie reports from drawing the\n    chart. <a href=\"http://www.chrome-allow-file-access-from-file.com/\">Run\n    Chrome with <code>--allow-file-access-from-files</code></a> to fix\n    this error.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.3/input.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Input Format</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>The Input Format</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> uses\n    the <a href=\"http://fpbench.org\">FPCore</a> input format to\n    specify mathematical expressions, which Herbie searches for\n    accurate implementations of.\n  </p>\n  \n  <h2 id=\"sec1\">General format</h2>\n\n  <p><a href=\"http://fpbench.org\">FPCore</a> format looks like this:</p>\n\n  <pre>(FPCore (<var>inputs ...</var>) <var>properties ...</var> <var>expression</var>)</pre>\n\n  <p>\n    Each input is a variable, like <code>x</code>, which can be used\n    in the expression, whose accuracy Herbie will try to improve.\n    Properties are <a href=\"#properties\">described below</a>.\n  </p>\n\n  <p>\n    The expression is written in prefix form, with every function call\n    parenthesized, as in Lisp. For example, the formula for the\n    hypotenuse of a triangle with legs <i>a</i> and <i>b</i> is\n  </p>\n\n  <pre>(FPCore (a b) (sqrt (+ (* a a) (* b b))))</pre>\n\n  <p>\n    We recommend the <code>.fpcore</code> file extension for Herbie input files.\n  </p>\n  \n  <h2>Supported functions</h2>\n  \n  <p>\n    Herbie supports all functions\n    from <a href=\"http://pubs.opengroup.org/onlinepubs/7908799/xsh/math.h.html\">math.h</a>\n    with floating-point-only inputs and outputs. The best supported\n    functions, far from the full list, include:\n  </p>\n\n  <dl class=\"function-list\">\n    <dt><code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>, <code>fabs</code></dt>\n    <dd>The usual arithmetic functions<br/>(where <code>-</code> is both negation and subtraction)</dd>\n    <dt><code>sqrt</code>, <code>cbrt</code></dt>\n    <dd>Square and cube roots</dd>\n    <dt><code>pow</code>, <code>exp</code>, <code>log</code></dt>\n    <dd>Various exponentiations and logarithms</dd>\n    <dt><code>sin</code>, <code>cos</code>, <code>tan</code></dt>\n    <dd>The trigonometric functions</dd>\n    <dt><code>asin</code>, <code>acos</code>, <code>atan</code>, <code>atan2</code></dt>\n    <dd>The inverse trigonometric functions</dd>\n    <dt><code>sinh</code>, <code>cosh</code>, <code>tanh</code></dt>\n    <dd>The hyperbolic functions</dd>\n    <dt><code>asinh</code>, <code>acosh</code>, <code>atanh</code></dt>\n    <dd>The inverse hyperbolic functions</dd>\n    <dt><code>fma</code>, <code>expm1</code>, <code>log1p</code>, <code>hypot</code></dt>\n    <dd>Specialized numeric functions</dd>\n  </dl>\n\n  <p>Herbie also supports the constants <code>PI</code>\n  and <code>E</code>. The arithmetic operators associate to the\n  left.</p>\n\n  <p>Herbie links against <code>libm</code> to ensure that every\n  function has the same behavior in Herbie as in your code. However,\n  on Windows platforms some functions are not available in the\n  system <code>libm</code>. In these cases Herbie will use a fallback\n  implementation and print a warning; turning off the\n  the <kbd>precision:fallback</kbd> <a href=\"options.html\">option</a>\n  disables those functions instead.</p>\n\n  <h2 id=\"conditionals\">Conditionals</h2>\n  \n  <p>FPCore uses <code>if</code> for conditional expressions:</p>\n\n  <pre>(if <var>cond</var> <var>if-true</var> <var>if-false</var>)</pre>\n\n  <p>\n    The conditional <code><var>cond</var></code> may use:\n  </p>\n  \n  <dl class=\"function-list\">\n    <dt><code>==</code>, <code>!=</code>, <code>&lt;</code>, <code>&gt;</code>, <code>&lt;=</code>, <code>&gt;=</code></dt>\n    <dd>The usual comparison operators</dd>\n    <dt><code>and</code>, <code>or</code>, <code>not</code></dt>\n    <dd>The usual logical operators</dd>\n    <dt><code>TRUE</code>, <code>FALSE</code></dt>\n    <dd>The two boolean values</dd>\n  </dl>\n\n  <p>The comparison functions can take any number of arguments and\n  implement chained comparisons.</p>\n\n  <h2 id=\"intermediates\">Intermediate variables</h2>\n  \n  <p>Intermediate variables can be defined using <code>let</code>:</p>\n\n  <pre>(let ([<var>variable</var> <var>value</var>] <var>...</var>) <var>body</var>)</pre>\n\n  <p>In a <code>let</code> expression, all the values are evaluated\n  first, and then are bound to their variables in the body. This means\n  that the value of one variable can't refer to another variable in\n  the same <code>let</code> block; nest <code>let</code> constructs if\n  you want to do that.</p>\n\n  <p>Note that Herbie treats intermediate values only as a notational\n  convenience, and inlines their values before improving the formula's\n  accuracy. Using intermediate variables will not help Herbie improve\n  a formula's accuracy or speed up its run-time.</p>\n\n  <h2 id=\"preconditions\">Preconditions</h2>\n\n  <p>By default, the arguments to formulas are assumed to be arbitrary\n  floating-point numbers. However, in many cases only a range of\n  argument values are possible. In Herbie, you can describe valid\n  arguments with the <code>:pre</code> property (for\n  “precondition”).</p>\n\n  <p>Preconditions comparison and boolean operators, just\n  like <a href=\"#conditionals\">conditional statements</a>. Herbie is\n  particularly efficient when when the precondition is\n  an <code>and</code> of ranges for each variable, such as:</p>\n\n  <pre>(FPCore (x) :pre (&lt; 1 x 10) (/ 1 (- x 1)))</pre>\n\n  <p>More complex preconditions <em>do</em> work, but may cause\n  the <a href=\"faq.html#sample-valid-points\">“Cannot sample enough\n  valid points”</a> error if it is too hard to find points that\n  satisfy the precondition.</p>\n\n  <h2 id=\"precisions\">Precisions</h2>\n\n  <p>Herbie supports both single- and double-precision values; you can\n  specify the precision with the <code>:precision</code> property:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>binary32</code></dt>\n    <dd>Single-precision IEEE-754 floating point</dd>\n    <dt><code>binary64</code></dt>\n    <dd>Double-precision IEEE-754 floating point</dd>\n  </dl>\n\n  <p>By default, <code>binary64</code> is assumed. Herbie also has\n  a <a href=\"plugins.html\">plugin system</a> to load additional\n  precisions.</p>\n\n  <h2 id=\"complex\">Complex Numbers<sup title=\"Supported in beta since Herbie 1.2\">β</sup></h2>\n\n  <p>Herbie includes experimental support for complex numbers;\n  however, this support is currently limited to a few basic\n  operations.</p>\n\n  <p>All input parameters to an FPCore are real numbers; complex\n  numbers must be constructed with <code>complex</code>. The\n  functions <code>re</code>, <code>im</code>, and <code>conj</code>\n  are available on complex numbers, along with the arithmetic\n  operators, <code>exp</code>, <code>log</code>, <code>pow</code>,\n  and <code>sqrt</code>. Complex and real operations use the same\n  syntax, but cannot be mixed: <code>(+ (complex 1 2) 1)</code> is not\n  valid. Herbie reports type errors in such situations.</p>\n\n  <p>Complex operations use\n  the <a href=\"https://docs.racket-lang.org/reference/numbers.html#%28tech._complex._number%29\">Racket</a>\n  implementation, so results may differ (slightly) from complex\n  numbers in some other language, especially for non-finite complex\n  numbers. Unfortunately, complex number arithmetic is not as\n  standardized as float-point arithmetic.</p>\n\n  <p>In the future, we hope to support complex-number arguments and\n  fully support all complex-number operations.</p>\n\n  <h2 id=\"properties\">Miscellaneous Properties</h2>\n\n  <p>Herbie uses the <code>:name</code> property to name FPCores in\n  its UI. Its value ought to be a string.</p>\n\n  <p>Herbie's out uses custom FPCore properties to provide additional\n  information about the Herbie improvement process:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>:herbie-status <var>status</var></code></dt>\n    <dd><var>status</var> describes whether Herbie worked: it is one\n    of <code>success</code>, <code>timeout</code>, <code>error</code>,\n    or <code>crash</code>.</dd>\n    <dt><code>:herbie-time <var>ms</var></code></dt>\n    <dd>The time, in milliseconds, used by Herbie to find a more accurate formula.</dd>\n    <dt><code>:herbie-error-input<br/>([<var>pts</var> <var>err</var>] ...)</code></dt>\n    <dd>The computed average error of the input program, evaluated on <var>pts</var> points. Multiple entries correspond to multiple training or test sets.</dd>\n    <dt><code>:herbie-error-output<br/>([<var>pts</var> <var>err</var>] ...)</code></dt>\n    <dd>The computed average error of the output program, like above.</dd>\n  </dl>\n\n  <p>Herbie's passes through <code>:name</code>,\n  <code>:pre</code>, and <code>:precision</code> properties to its\n  outputs.</p>\n\n  <p>The benchmark suite uses other properties (such\n  as <code>:herbie-target</code>) for testing, but these are not\n  supported and their use is discouraged.</p>\n  \n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.3/installing.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Installing Herbie</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Installing Herbie</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n  \n  <p>Herbie supports Linux, macOS, and Windows.</p>\n\n  <p>\n    <a href=\"../../\">Herbie</a> can be installed from a package or\n    from source. (It is also available in\n    a <a href=\"docker.html\">Docker</a> image.) To install Herbie, first install\n    <a href=\"https://racket-lang.org\">Racket</a>, which Herbie is\n    written in.\n  </p>\n\n  <h2>Installing Racket</h2>\n\n  <p>\n    Use the <a href=\"http://download.racket-lang.org/racket-v7.3.html\">official\n    installer</a> to install Racket, or use distro-provided packages\n    provided they are version 7.0 or later of Racket (earlier versions\n    are not supported).\n  </p>\n\n  <p>\n    Test that Racket is installed correctly and has a correct version:\n  </p>\n\n  <pre class=\"shell\">racket\nWelcome to Racket v7.3.\n> (exit)</pre>\n  \n  <h2>Installing Herbie from a package</h2>\n\n  <p>Once Racket is installed, install Herbie with:</p>\n\n  <pre class=\"shell\">raco pkg install --auto herbie</pre>\n\n  <p>\n    This will install Herbie, compile it for faster startup, and place\n    an executable in your Racket user path, likely\n    into <code>~/.racket/7.3/</code>. If you add this directory to\n    your <code>PATH</code> you will be able to run herbie with\n    the <kbd>herbie</kbd> command.\n  </p>\n\n  <p>\n    Once Herbie is installed and working correctly,\n    check out the <a href=\"tutorial.html\">tutorial</a>.\n  </p>\n\n  <h2>Installing Herbie from source</h2>\n\n  <p>\n    Once Racket is installed, download and build the Herbie source\n    <a href=\"https://github.com/uwplse/herbie\">from GitHub</a> with:\n  </p>\n\n  <pre class=\"shell\">git clone https://github.com/uwplse/herbie</pre>\n\n  <p>\n    If you go to the <code>herbie</code> directory,\n    you should see a <code>README.md</code> file, a directory named <code>src</code>,\n    a directory named <code>bench/</code>, and a few other directories.\n    Do a trial run of Herbie to make sure everything is installed and working correctly:\n  </p>\n\n  <pre class=\"shell\">racket src/herbie.rkt report bench/tutorial.fpcore graphs/</pre>\n\n  <p>This command will take approximately a minute to run.\n    After the command completes,\n      a directory named <code>graphs</code> should be created.\n    Open the <code>report.html</code> file inside with your browser;\n      you will see a listing of the expressions Herbie was run on,\n      all of which should be green.\n    If not, please check that your Racket installation is at least version 7.3,\n      and if the error still persists,\n      please <a href=\"https://github.com/uwplse/herbie/issues\">submit a bug</a>.\n  </p>\n\n  <p>For faster startup, to create the <kbd>herbie</kbd> command, and\n  to enable plugins, run the following command:</p>\n\n  <pre class=\"shell\">raco pkg install --name herbie src/</pre>\n\n  <p>\n    Once Herbie is installed and working correctly,\n    check out the <a href=\"tutorial.html\">tutorial</a>.\n  </p>\n\n  <h2>Installing Herbie from Docker</h2>\n\n  <p>\n    <a href=\"https://docker.com\">Docker</a> is a container manager,\n    which is sort of like an easily-scriptable virtual machine. We do\n    not recommend using Herbie through Docker without prior Docker\n    experience.\n  </p>\n\n  <p>\n    First, <a href=\"https://docs.docker.com/installation/\">install\n    Docker</a>. Docker supports Windows, macOS, and Linux. Depending\n    on how you install Docker, you may need to prefix\n    the <code>docker</code> command with <code>sudo</code> or run them\n    as the administrative user.\n  </p>\n\n  <p>\n    With Docker installed, you should be able to download the Herbie image with:\n  </p>\n \n  <pre class=\"shell\">docker pull uwplse/herbie</pre>\n  \n  <p>\n    Check out the <a href=\"docker.html\">Docker page</a> for more on\n    how to run Herbie with Docker. Note that Herbie in Docker is more\n    limited; for example, it will not recognize plugins installed\n    outside the Docker container.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.3/options.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Command-line Options</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Command-line Options</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>The <a href=\"../../\"><code>herbie</code></a> command several\n  subcommands and options that influence both its user interface and\n  the quality of solutions that it finds.</p>\n\n  <h2>Herbie commands</h2>\n\n  <p>Herbie can be run both interactively and in batch mode, and can\n  generate output intended either for\n  the <a href=\"using-cli.html\">command line</a>\n  or <a href=\"using-web.html\">the web</a>. We call these different\n  ways of running Herbie different tools. Herbie provides four\n  tools:</p>\n\n  <dl>\n    <dt><code>herbie web</code></dt>\n    <dd>Use Herbie through your browser. <code>herbie web</code>\n    starts a web server for running Herbie on your local machine, and\n    directs a browser to visit that server.</dd>\n\n    <dt><code>herbie shell</code></dt>\n    <dd>Starts a command-line interactive shell for using Herbie.\n    Enter an <a href=\"input.html\">FPCore expression</a> and Herbie\n    will print its more-accurate version.</dd>\n\n    <dt><code>herbie improve <var>input</var> <var>output</var></code></dt>\n    <dd>Runs Herbie on the expressions in the file or\n    directory <var>input</var>, and outputs the result\n    to <var>output</var>, which will be a single file of FPCore\n    outputs.</dd>\n\n    <dt><code>herbie report <var>input</var> <var>output</var></code></dt>\n    <dd>Runs Herbie on the expressions in the file or\n    directory <var>input</var>, and produces a\n    directory <var>output</var> of HTML pages that describe Herbie's\n    output, how it derived that output, and additional charts and\n    information about the improvement process. These pages can be\n    viewed in any browser (though with a <a href=\"faq.html\">quirk</a>\n    for Chrome).</dd>\n  </dl>\n\n  <p>We recommend using the web tools, <code>web</code>\n  and <code>report</code>, since HTML allows Herbie to give you more\n  information about how and why it improved a floating-point\n  expression's accuracy. Particularly useful are the graphs it\n  produces of error versus input, which can help you understand\n  whether Herbie's improvements matter for your user cases.</p>\n\n  <p>For any tool, you can run <code>herbie <var>tool</var> --help</code>\n    to see a listing of all available command-line options. This listing\n    will include unsupported options not listed on this page.</p>\n\n  <h2>General options</h2>\n\n  <p>\n    These options can be set on any tool. Pass them after the tool\n    name but before other arguments, such as:\n  </p>\n\n  <pre class=\"shell\">herbie improve --timeout 60 in.fpcore out.fpcore</pre>\n\n  <p>Arguments cannot be put anywhere else.</p>\n\n  <dl>\n    <dt><code>--seed S</code></dt>\n    <dd>The random seed, which changes the randomly-selected points\n      that Herbie evaluates candidate expressions on. The seed is a\n      number between 0 and 2<sup>31</sup> (exclusive both ends). This\n      option can be used to make Herbie's results reproducible or to\n      compare two different runs. Prior versions of Herbie used a\n      different format for seeds, which is now deprecated.</dd>\n\n    <dt><code>--num-iters N</code></dt>\n    <dd>The number of improvements Herbie attempts to make to the\n      program. The default, 4, suffices for most programs and helps\n      keep Herbie fast. If this is set very high, Herbie may run out\n      of things to do and terminate before the given number of\n      iterations, but in practice iterations beyond the first few\n      rarely lead to lower error. This option can be increased to 5 or\n      higher to check that there aren't further improvements that Herbie\n      could seek out.</dd>\n\n    <dt><code>--num-points N</code></dt>\n    <dd>The number of randomly-selected points used to evaluate\n      candidate expressions. The default, 256, gives good behavior for\n      most programs. The more points sampled, the slower Herbie is.\n      This option can be increased to 512 or 1024 if Herbie gives very\n      inconsistent results between runs with different seeds.</dd>\n    \n    <dt><code>--timeout T</code></dt>\n    <dd>The timeout to use per-input, in seconds. A fractional number\n    of seconds can be given.</dd>\n\n    <dt><code>--threads N</code> (for the <code>improve</code> and <code>report</code> tools)</dt>\n    <dd>Enables multi-threaded operation. By default, no threads are\n      used. A number can be passed to this option to use that many\n      threads, or <code>yes</code> can be passed to tell Herbie to use\n      all of the hardware threads.</dd>\n  </dl>\n\n  <h2>Web shell options</h2>\n  \n  <p>The <code>web</code> tool runs Herbie as a web server, and\n  connects to it from your browser. It has additional options to\n  control this server.</p>\n  \n  <dl>\n    <dt><code>--port N</code></dt>\n    <dd>The port to run the Herbie server on. The default port is 8000.</dd>\n\n    <dt><code>--save-session dir</code></dt>\n    <dd>Save all the reports for expressions enterred into the web\n    shell to this directory. The directory is also used as a\n    cache of already-computed expressions.</dd>\n\n    <dt><code>--log file</code></dt>\n    <dd>Write a web access log to this file. The file is formatted\n    similarly to Apache logs. If Herbie crashes for some reason, this\n    log will <emph>not</emph> contain a traceback.</dd>\n\n    <dt><code>--quiet</code></dt>\n    <dd>By default, but not when this option is set, a browser is\n    started to point to the Herbie page. This option also shrinks the\n    a banner printed to the command line.</dd>\n\n    <dt><code>--public</code></dt>\n    <dd>When set, users on other computers can connect to the demo and\n    use it. (In other words, the server listens\n    on <code>0.0.0.0</code>.). Also useful when Herbie is run\n    through <a href=\"docker.html\">Docker</a>.</dd>\n  </dl>\n\n  <h2>Rulesets</h2>\n\n  <p>\n    Herbie uses rewrite rules to make changes to formulas and improve\n    their accuracy. These rules can be turned on and off in groups\n    using <code>--disable rules:<var>group</var></code>\n    and <code>--enable rules:<var>group</var></code>. In general,\n    enabling rules improves the accuracy of Herbie's output but may\n    allow it to use functions not available on your platform.\n  </p>\n\n  <p>The full list of rule groups is:</p>\n\n  <table class=\"function-list\">\n    <thead><tr><th>Rule Group</th><th>Topic of rewrite rules</th></tr></thead>\n    <tr><td>arithmetic</td><td>Basic arithmetic facts</td></tr>\n    <tr><td>polynomials</td><td>Factoring and powers</td></tr>\n    <tr><td>fractions</td><td>Fraction arithmetic</td></tr>\n    <tr><td>exponents</td><td>Exponentiation identities</td></tr>\n    <tr><td>trigonometry</td><td>Trigonometric identities</td></tr>\n    <tr><td>hyperbolic</td><td>Hyperbolic trigonometric identities</td></tr>\n    <tr><td>special</td><td>Special mathematical functions</td></tr>\n    <tr><td>complex</td><td>Complex number arithmetic</td></tr>\n    <tr><td>numerics</td><td>Special numerical functions <code>expm1</code>, <code>log1p</code>, <code>fma</code>, and <code>hypot</code></td></tr>\n    <tr><td>bools</td><td>Boolean operator identities</td></tr>\n    <tr><td>branches</td><td><code>if</code> statement simplification</td></tr>\n  </table>\n\n  <p>All groups except <code>numerics</code> are enabled by default.\n  We recommend turning <code>numerics</code> on if these functions are\n  available in your language, and disabling <code>complex</code>\n  or <code>special</code> if those functions are poorly implemented in\n  your language.</p>\n\n  <h2>Search options</h2>\n\n  <p>\n    These options influence Herbie's search, most importantly the\n    types of transformations that Herbie uses to find candidate\n    programs. They offer fine-grained control and are only recommended\n    for advanced uses of Herbie.\n  </p>\n\n  <p>\n    Each option can be turned off with the <code>-o</code>\n    or <code>--disable</code> command-line flag, and turned on with\n    <code>+o</code> or <code>--enable</code>. The recommended options\n    are the defaults; turning a default-on option off typically\n    results in less-accurate results, while turning a default-off\n    option on typically results in more-complex and more-surprising\n    output expressions.\n  </p>\n\n  <dl>\n    <dt><code>precision:double</code></dt>\n    <dd>This option, on by default, tells Herbie default to\n    double-precision calculations. If turned off, Herbie defaults to\n    single-precision calculations. This option is a legacy option; use\n    the <a href=\"input.rkt#precisions\"><code>:precision</code> FPCore\n    property</a> to change precisions instead.</dd>\n\n    <dt><code>precision:fallback</code></dt>\n    <dd>This option, on by default, tells Herbie to use fallback\n    functions if a native implementation is not found for an operation\n    (and print a warning). If turned off, operations with no native\n    implementation will be disabled entirely. Turn this option off if\n    you require Herbie to be faithful to your system's implementation\n    of <code>libm</code>.</dd>\n\n    <dt><code>setup:simplify</code></dt>\n    <dd>This option, on by default, simplifies the expression before\n    passing it to Herbie. If turned off, Herbie will not simplify\n    input programs before improving them. Turn this option off if\n    simplifying the input will create a lot of error, say if the\n    association of operations is cleverly chosen.</dd>\n\n    <dt><code>setup:early-exit</code></dt>\n    <dd>This option, off by default, causes Herbie to exit without\n    modifying the input program if it determines that the input\n    program has less than 0.1 bits of error. Turn this option on if\n    you are running Herbie on a large corpus of programs that you do\n    not believe to be inaccurate.</dd>\n\n    <dt><code>generate:rr</code></dt>\n    <dd>This option, on by default, uses Herbie's recursive rewriting\n    algorithm to generate candidate programs. If turned off, Herbie\n    will use a non-recursive rewriting algorithm, which will\n    substantially limit the candidates Herbie finds. You will rarely\n    want to turn this option off.</dd>\n\n    <dt><code>generate:taylor</code></dt>\n    <dd>This option, on by default, uses series expansion to produce\n    new candidates during the main improvement loop. If turned off,\n    Herbie will not use series expansion. Turn this option off if you\n    want to avoid series-expansion-based rewrites, such as if you need\n    to preserve the equivalence of the input and output expressions as\n    real-number formulas.</dd>\n\n    <dt><code>generate:simplify</code></dt>\n    <dd>This option, on by default, simplifies candidates during the\n    main improvement loop. If turned off, candidates will not be\n    simplified, which typically results in much less accurate\n    expressions, since simplification is often necessary for\n    cancelling terms. You will rarely want to turn this option\n    off.</dd>\n\n    <dt><code>reduce:regimes</code></dt>\n    <dd>This option, on by default, uses Herbie's regime inference\n    algorithm to branch between several program candidates. If turned\n    off, branches will not be inferred and the output program will be\n    straight-line code (if the input was). Turn this option off if\n    your programming environment makes branches very expensive, such\n    as in some cases of GPU programming.</dd>\n\n    <dt><code>reduce:avg-error</code></dt>\n    <dd>This option, on by default, causes Herbie to output the\n    candidate with the best average error over the chosen inputs. If\n    turned off, Herbie will choose the candidate with the least\n    maximum error instead. This usually produces programs with worse\n    overall accuracy. Turn this option off if worst-case accuracy is\n    more important to you than overall accuracy.</dd>\n\n    <dt><code>reduce:binary-search</code></dt>\n    <dd>This option, on by default, uses binary search to refine the\n    values used in inferred conditionals. This makes different runs of\n    Herbie produce more similar results, and improves accuracy near\n    those values. If turned off, binary search will not be used, and\n    the branch values will be less accurately chosen. Turn this option\n    off if behavior near branches is not important to you.</dd>\n\n    <dt><code>reduce:branch-expressions</code></dt>\n    <dd>This option, on by default, allows Herbie to branch on\n      expressions, not just variables. This can improve accuracy on\n      regime branching, slows Herbie down, particularly for large\n      programs. If turned off, Herbie will only try to branch on\n      variables. Turn this option off if Herbie runtime is more\n      important to you than expression accuracy.</dd>\n  </dl>\n\n  <h2>Upgrading from Herbie 1.0</h2>\n\n  <p>Herbie 1.0 used\n  a <a href=\"../1.0/using-herbie.html\">different</a> command line\n  syntax, without multiple tools. Translate like so:</p>\n\n  <ul>\n    <li><code>herbie-1.0</code> → <code>herbie-1.3 shell</code></li>\n    <li><code>herbie-1.0 file</code> → <code>herbie-1.3 improve file -</code></li>\n    <li><code>herbie-1.0 files ...</code> → <code>cat files ... | herbie-1.3 improve - -</code><br/>\n      Alternatively, collect the files into a directory and run <code>herbie-1.3 improve dir/ -</code></li>\n  </ul>\n\n  <p>The new syntax somewhat changes Herbie's behavior, such as by\n  using the input expression as the output if Herbie times out. It\n  also makes it easier to write Herbie's output to a file without\n  using command-line redirection.</p>\n\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.3/plugins.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Plugins</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Plugins</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p><a href=\"../../\">Herbie</a> allows plugins to define additional\n  functions, rewrite rules, and even number representations. Plugins\n  are be separately installed. Once installed, Herbie automatically\n  loads and uses them.</p>\n  \n  <h2>Posit arithmetic</h2>\n\n  <p>The <kbd>softposit-herbie</kbd> plugin implements support\n  for <a href=\"https://posithub.org/\">posit</a> arithmetic. Install it\n  with:</p>\n\n  <pre class=\"shell\">raco pkg install --auto softposit-herbie</pre>\n\n  <p>Note that this plugin uses the SoftPosit library, which only\n  supports Linux platforms, and even then is reported to misbehave on\n  some machines.</p>\n\n  <p>Once <kbd>softposit-herbie</kbd> is installed,\n  specify <code>:precision posit16</code> to inform Herbie that it\n  should assume the core's inputs and outputs are posit numbers. Other\n  posit sizes (from 8 to 128 bits) and also quires (for 8, 16, and 32\n  bits) are available, but are poorly supported.</p>\n  \n  <h2>Developing plugins</h2>\n\n  <p>The plugin functionality is currently highly experimental; if you\n  would like to develop your own plugins, please write to\n  the <a href=\"https://mailman.cs.washington.edu/mailman/listinfo/herbie\">mailing\n  list</a>.</p>\n  \n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.3/release-notes.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie 1.3 Release Notes</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <script src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML\"></script>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Herbie 1.3 Release Notes</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    The <a href=\"../..\">Herbie</a> developers are excited to announce\n    Herbie 1.3! This release focuses on <em>speed and\n    transparency</em>: Herbie 1.3 is nearly twice as fast as\n    Herbie 1.2, and includes cleaner, more comprehensive HTML output.\n  </p>\n\n  <p>\n    Herbie automatically improves the accuracy of floating point\n    expressions. This avoids the bugs, errors, and surprises that so\n    often occur when working with floating point. Since\n    our <a href=\"../../papers.html\">PLDI'15 paper</a>, we've been hard at\n    work making Herbie more versatile and easier to use.\n  </p>\n\n  <img width=\"100%\" src=\"team.png\" style=\"display: block; margin: 4em 0;\" />\n\n  <h2>Major features of this release</h2>\n\n  <p><em>Speed:</em> Herbie is roughly twice as fast as in\n  previous releases. Making this happen has involved changes large and\n  small: a clever change to how we use simplification, a new sampling\n  algorithm, and also lots of work tracking down especially slow\n  expressions.</p>\n\n  <p><em>Transparency:</em> Herbie's web output has become\n  cleaner and more comprehensive. Herbie can now show you its output\n  in C and TeX as well as mathematical notation. You can now specify\n  preconditions and precisions when inputting expressions. And Herbie\n  has a new \"Metrics\" tab to show in-depth internal information, which\n  will help us continue to improve Herbie.</p>\n\n  <h2>Beta features in this release</h2>\n\n  <p><em>Windows support</em> has graduated from beta. We\n  intend to support Windows going forward; if you run into any bugs,\n  please <a href=\"https://github.com/uwplse/herbie/issues\">let us\n  know</a>.</p>\n\n  <p><em>Plugins</em> can now\n  <a href=\"plugins.html\">define new number systems</a> and then teach\n  Herbie to use them. There's a new plugin to add support\n  for <a href=\"https://posithub.org/\">posit arithmetic</a>. Right now\n  the plugin system is still in flux, so if you'd like to use it,\n  please <a href=\"https://mailman.cs.washington.edu/mailman/listinfo/herbie\">write\n  to us</a>.</p>\n\n  <figure class=\"showcase\" style=\"background: white; border: 1px solid gray;\">\n    <img src=\"travis-time.png\" style=\"display: block; width: 100%\"/>\n    <figcaption>Herbie 1.3 is roughly 2× faster than Herbie 1.2,\n    thanks to efforts throughout the year. This plot shows how long\n    Herbie's CI takes to run, for every passing CI run this release\n    cycle. In April we added more tests, causing the bump in Travis\n    time around then.</figcaption>\n  </figure>\n\n\n  <h2>Improvement to core algorithm</h2>\n\n  <ul>\n    <li>Careful performance work has made Herbie nearly three times\n      faster than the 1.2 release.</li>\n    <li>Herbie now uses interval arithmetic to compute \"ground truth\"\n      values. This makes Herbie's accuracy estimate for a\n      program more correct.</li>\n    <li>Support for single-precision mode has been significantly improved.</li>\n    <li>Series expansion of <code>pow</code>s with constant exponents\n      is now much faster.</li>\n    <li>Complex numbers are now handled significantly more quickly.</li>\n    <li>Various fixes have eliminated rare but large slowdowns.</li>\n  </ul>\n\n  <h2>Usability improvements</h2>\n\n  <ul>\n    <li>Herbie's web interface now allows you to change preconditions\n      and precisions (click “additional options” below the formula bar).</li>\n    <li>You can now see C code for Herbie's output—use the drop-down\n    above and to the right of the program box.</li>\n    <li>Herbie has a <a href=\"../../index.html\">new website</a>!\n      Hopefully it's a little easier to learn about what Herbie is and\n      how to use it.</li>\n    <li>Herbie now shows preconditions in its HTML output.</li>\n    <li>Herbie now produces somewhat simpler output, for example by\n      simplifying exact constant expressions like <code>(+ 2\n      2)</code>.</li>\n    <li>You can now input if statements on the web using\n      conditional-expression syntax.</li>\n    <li>Herbie will now show warnings in its HTML output, including\n      links to more documentation.</li>\n    <li>Herbie now indents and breaks lines when it prints FPCores in\n      the terminal.</li>\n    <li>Herbie now uses <a href=\"https://katex.org/\">KaTeX</a> to\n      render math in the browser, which is significantly faster than\n      the previous <a href=\"https://www.mathjax.org/\">MathJax</a>\n      library.</li>\n    <li>Error and timeout pages now show the input program.</li>\n  </ul>\n\n  <h2>Code Cleanup</h2>\n\n  <ul>\n    <li>Reports now link to an extensive collection of quality and\n      performance metrics. This should help improve Herbie's speed and\n      accuracy over time.</li>\n    <li>Documentation has been improved, with tables of content and\n      explanations of preconditions and precisions.</li>\n    <li>The new <kbd>reproduce</kbd> tool allows rerunning a\n      report.</li>\n    <li>The timebar on the metrics page now separates regime inference\n      from binary search.</li>\n    <li>Herbie's JavaScript code has been refactored, making it much\n      easier to maintain.</li>\n    <li>Lots of old, unused code has been deleted, including a lot of\n      support code for the\n      obsolete <a href=\"https://pavpanchekha.com/blog/herbie-viz.html\">Herbie\n      Visualizer</a>.</li>\n    <li>Glue code has been moved into a single file, clarifying\n      responsibilities for a lot of modules.</li>\n  </ul>\n  \n  <h2>Try it out!</h2>\n\n  <p>\n    We're excited to continue to improve Herbie and make it more\n    useful to scientists, engineers, and programmers around the world.\n    We've got a lot of features we're excited to work on in the coming\n    months. Please\n    <a href=\"https://github.com/uwplse/herbie/issues\">report bugs</a>,\n    join\n    <a href=\"https://mailman.cs.washington.edu/mailman/listinfo/herbie\">the\n    mailing list</a>,\n    or <a href=\"https://github.com/uw-plse/herbie\">contribute</a>.\n  </p>\n  \n  <p><em style=\"font-weight: bold; font-style: roman;\">If you find Herbie useful, <a href=\"mailto:herbie@cs.washington.edu\">let us know!</em></p>\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.3/report.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie reports</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Herbie reports</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  \n  <h1>The Herbie report</h1>\n\n  <p>Herbie can <a href=\"using-web.html\">generate HTML reports</a>\n  which give its output expression and also how Herbie found it.</p>\n\n  <h2 id=\"summary\">Summary numbers</h2>\n\n  <p>First, a brief summary of the results. For most uses, the\n    “Average Error” number, which summarizes how accurate the input\n    and output expressions are, is the most important number in this\n    section. The other numbers list time Herbie took to improve the\n    program and the <a href=\"input.html#precisions\">precision</a> of\n    floating-point operations.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-large.png\" />\n    <figcaption>Summary numbers from a Herbie report.</figcaption>\n  </figure>\n\n  <h2 id=\"programs\">Input and output programs</h2>\n\n  <p>Second, the input and output programs themselves. These are\n  printed in standard mathematical syntax. In the top-right corner,\n  the drop-down can be used to change to C syntax or raw TeX.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-prog.png\" />\n    <figcaption>Input and output program from a Herbie report.</figcaption>\n  </figure>\n\n  <h2 id=\"graph\">Error graph</h2>\n\n  <p>\n    Third, under <em>Error</em>, a graph of floating-point error\n    versus input value. This is helpful for understanding the sorts of\n    inputs Herbie is improving accuracy on. Sometimes, Herbie improved\n    accuracy on some inputs at the cost of accuracy on other inputs\n    that you care more about. In these cases, you can add\n    a <a href=\"input.html#preconditions\"><code>:pre</code>condition</a>\n    to restrict the inputs Herbie reasons about.\n  </p>\n\n  <p>\n    On these graphs, the red line is the error of the input program,\n    while the blue line is the error of the output program\n    (both can be toggled).\n    For expressions with multiple variables,\n    the variable on the horizontal axis can be selected.\n    If Herbie decided to insert\n    an <code>if</code> statement into the program,\n    the locations of those <code>if</code> statements\n    will be marked with vertical bars.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-error.png\" />\n    <figcaption>An error graph from a Herbie report. Note the variable\n    selector (<code>x</code> is selected) and the toggles for the\n    input and output program (both are toggled on).</figcaption>\n  </figure>\n\n  <h2 id=\"try-it\">Interactive inputs</h2>\n\n  <p>\n    Fourth, a form where you can try out specific inputs on the input\n    program and Herbie's output program. Enter the argument values on\n    the left, and the input and output programs will be evaulated on\n    those arguments and the results printed on the right.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-try-it.png\" />\n    <figcaption>\n      Try it out section on a simple program.\n    </figcaption>\n  </figure>\n\n  <h2 id=\"derivation\">Derivation</h2>\n\n  <p>Fifth, a derivation of the output from the input.\n    For complex or unexpected programs, these can be helpful.\n    Each substantive step in the derivation also lists the error,\n    in bits, of that step's output.</p>\n\n  <p>The derivations may name rules built into Herbie,\n    or may claim derivation steps are done by simplification,\n    series expansion, or other Herbie strategies. The derivation will\n    also call out splits of the input into regimes, and strategies\n    Herbie is invoking. When one part of the term is colored blue,\n    that is the only part of the term modified by the operation.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-derivation.png\" />\n    <figcaption>A short derivation from a Herbie report. Note the\n    error at each step, in bits, in gray.</figcaption>\n  </figure>\n\n  <h2 id=\"reproduction\">Reproduction</h2>\n\n  <p>Sixth, a command you can use to reproduce this Herbie result.\n  If you find a bug, include the code snippet in this section when\n  <a href=\"https://github.com/uwplse/herbie/issues\">filing the\n  bug</a>. Please also include the debug log linked at the top of the\n  page.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-reproduce.png\" />\n    <figcaption>Reproduction information for a Herbie run.</figcaption>\n  </figure>\n\n  <h2 id=\"links\">Additional links</h2>\n  \n  <p>The top of the page has a right-hand menu bar with additional\n  links. “Log” you to a detailed debug log. “Profile” gives\n  a <code>gprof</code>-style profile. and “Metrics” gives detailed\n  internal metrics on Herbie's results.</p>\n\n  <p>We expect the report to grow more informative with future\n  versions. Please <a href=\"mailto:herbie@cs.washington.edu\">get in\n  touch</a> if there is more information you'd like to see.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.3/toc.js",
    "content": "function make_toc() {\n    var headings = document.querySelectorAll(\"h2\");\n    var toc = document.createElement(\"nav\");\n    toc.classList.add(\"toc\")\n    var list = document.createElement(\"ul\");\n    for (var i = 0; i < headings.length; i++) {\n        var li = document.createElement(\"li\");\n        var a = document.createElement(\"a\");\n        var h = headings[i];\n        if (! h.id) {\n            h.setAttribute(\"id\", \"heading-\" + i);\n        }\n        a.setAttribute(\"href\", \"#\" + h.id);\n        a.innerHTML = h.innerHTML;\n        li.appendChild(a);\n        list.appendChild(li);\n    }\n    toc.appendChild(list);\n    headings[0].parentNode.insertBefore(toc, headings[0]);\n}\n\nwindow.addEventListener(\"load\", make_toc);\n"
  },
  {
    "path": "www/doc/1.3/tutorial.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Tutorial</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Herbie Tutorial</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> automatically rewrites\n      floating point expressions to make them more accurate.\n    Floating point arithmetic is inaccurate;\n      hence the jokes that 0.1 + 0.2 ≠ 0.3 for a computer.\n    But it is hard to understand and fix these inaccuracies,\n      creating mysterious and hard-to-fix bugs.\n    Herbie is a tool to help.\n  </p>\n\n  <p>\n    To get started, <a href=\"installing.html\">download and install</a>\n    Herbie. With Herbie installed, you're ready to begin using it.\n  </p>\n\n  <h2>Giving Herbie expressions</h2>\n\n  <p>Now that Herbie is installed, start it with:</p>\n\n  <pre class=\"shell\">herbie web</pre>\n\n  <p>\n    After a brief wait, this ought to open a web browser to a page\n    with Herbie's results. The most important part of the page is this\n    bit:\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"web-input.png\" />\n    <figcaption>The program input field in the Herbie web UI.</figcaption>\n  </figure>\n\n  <p>Go ahead and type <kbd>(1 + x) - x</kbd> into this box and press\n  enter. You should see the entry box gray out, then some additional\n  text appear on the screen describing the various steps Herbie is\n  doing. Eventually (after a few seconds) you'll be redirected to a\n  page with Herbie's results. The most important part of that page is\n  the large gray box in the middle:\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-prog.png\" />\n    <figcaption>Input and output program from a Herbie report.</figcaption>\n  </figure>\n\n  <p>\n    This shows both the input <code>(1 + x) - x</code> that you gave\n    Herbie, and also Herbie's idea of a more accurate way to evaluate\n    that expression: <code>1</code>. Here, Herbie did a good job,\n    which you can double check using the statistics above that box:\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-large.png\" />\n    <figcaption>Statistics and error measures for this Herbie run.</figcaption>\n  </figure>\n\n  <p>\n    Here, Herbie reports that the improved the program has 0 bits of\n    error, on average, whereas the original program had 29.4. That's\n    because, when <code>x</code> is really big, <code>x + 1 = x</code>\n    in floating-point arithmetic, so <code>(x + 1) - x = 0</code>.\n  </p>\n\n  <p>\n    There's <a href=\"report.html\">lots more information</a> on this\n    results web page to help explain both what the accuracy is on\n    different inputs and to describe how Herbie derived its result.\n  </p>\n\n  <h2>Programming with Herbie</h2>\n\n  <p>Now that you've run Herbie and know how to read its results,\n  let's work through applying Herbie to a realistic program.</p>\n\n  <p>\n    When you're working on a numerical program, it's best to keep\n    Herbie open in a browser tab so you can run it easily. That way,\n    when you're writing a complex floating-point expression, you can\n    run Herbie to make sure you use the most accurate version of that\n    expression that you can. Herbie\n    has <a href=\"options.html\">options</a> to log all the expressions\n    you enter, so that you can refer to them later.\n  </p>\n\n  <p>However, if you're tracking down a bug that you think is caused\n  by floating-point error, you'll need to identify the problematic\n  floating-point expression before you can use Herbie on it.</p>\n\n  <p>\n    As an example, let's use <a href=\"http://mathjs.org\">math.js</a>,\n    an extensive math library for JavaScript, and walk\n    through <a href=\"https://github.com/josdejong/mathjs/pull/208\">bug\n    208</a>, which found an inaccuracy in the implementation of complex\n    square root. (For a full write-up of the bug itself, check out\n    a <a href=\"https://pavpanchekha.com/blog/casio-mathjs.html\">blog\n    post</a> by one of the Herbie authors.)\n  </p>\n\n  <h2>Finding the problematic expression</h2>\n\n  <p>\n    Before using Herbie you need to know what floating-point\n    expressions to feed it. In most programs, there's a small core\n    that does the mathematical computations, while the rest of the\n    program sets up parameters, handles control flow, visualizes or\n    print results, and so on. The mathematical core is what Herbie\n    will be interested in.\n  </p>\n\n  <p>\n    For example, in the case of math.js, the mathematical core\n    is in <a href=\"https://github.com/josdejong/mathjs/tree/master/lib/function\"><code>lib/function/</code></a>.\n    Each file in each subdirectory contains a collection of mathematical functions.\n    The bug we're interested in is about complex square root, so let's look at the file\n    <a href=\"https://github.com/josdejong/mathjs/blob/da306e26ed34272db44e35f07a3b015c0155d99a/lib/function/arithmetic/sqrt.js\"><code>arithmetic/sqrt.js</code></a>,\n    which contains real and complex square roots.\n  </p>\n\n  <p>\n    The code handles argument checks, five different number types, and\n    error handling. None of that is of interest to Herbie; we want to\n    extract just the mathematical computation. So let's look at\n    the <code>isComplex(x)</code> case:\n  </p>\n\n  <pre>var r = Math.sqrt(x.re * x.re + x.im * x.im);\nif (x.im &gt;= 0) {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}\nelse {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      -0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}</pre>\n\n  <h2>Converting problematic code to Herbie input</h2>\n\n  <p>\n    This code contains a branch: one option for non-negative <code>x.im</code>,\n    and one for positive <code>x.im</code>.\n    While Herbie supports an <code>if</code> construct,\n    it's usually better to send each branch to Herbie separately.\n  </p>\n\n  <p>\n    Also, in this code, <code>x</code> is of\n    type <code>Complex</code>, a data structure with multiple fields.\n    Herbie only deals with floating-point numbers, not data\n    structures, so we will treat the input <code>x</code> as two\n    separate inputs to Herbie: <code>xre</code> and <code>xim</code>.\n    We'll also pass each field of the output to Herbie separately.\n  </p>\n\n  <p>\n    Finally, each field of the final output uses the\n    variable <code>r</code>, which is defined in the first line of the\n    code snippet. When you're using Herbie, you want to expand or\n    inline intermediate variables like this, because the definition of\n    that variable contains important information that Herbie can use\n    to improve accuracy.</p>\n\n  <p>Putting this all together, let's do the first field of the\n  non-negative <code>x.im</code> case first. It looks like this:</p>\n\n  <pre>0.5 * sqrt(2.0 * (sqrt(xre * xre + xim * xim) + xre))</pre>\n\n  <p>Before running Herbie on this expression, click the “Additional\n  options” link. You should see a box where you can enter a\n  precondition; enter <kbd>xim &lt;= 0</kbd>. This makes sure that\n  Herbie only considers the points this expression will actually be\n  run on when improving the accuracy of this expression.</p>\n  \n  <h2>Using Herbie's results</h2>\n\n  <p>Herbie will churn for a few seconds and produce an output,\n  perhaps something like this:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-prog2.png\" />\n    <figcaption>Herbie's version of the complex square root expression.</figcaption>\n  </figure>\n\n  <p>Herbie's algorithm is randomized, so you likely won't see the\n  exact same thing. For example, the branch expression <code>xre ≤\n  6.68107529348e-308</code> will probably have some other really small\n  number. And perhaps Herbie will choose slightly different\n  expressions. But the result should be recognizably similar. In this\n  case, Herbie reports that the initial expression had 38.7 bits of\n  error, and that the output has 29.4.</p>\n\n  <p>It's a little harder to describe what Herbie found wrong with the\n  original expression, and why its new version is better—it is due to\n  a floating-point phenomenon called “cancellation”. But you can get\n  some insight from the error plot just below the program block:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-plot2.png\" />\n    <figcaption>Herbie's error plot for the complex square root expression.</figcaption>\n  </figure>\n\n  <p>There's a lot going on here. Along the horizontal axis, you have\n  the various input values (of <code>xim</code>). Note that the graph\n  is log-scale, and includes only negative values (thanks to our\n  precondition). So in the middle is the value -1, to the left you have\n  values with large exponents approaching infinity, and to the right\n  you have values with small exponents approaching 0.</p>\n\n  <p>On the vertical axis, you have Herbie's error measure (bits of\n  error), from 0 to 64. There are two lines drawn: a red one for your\n  input expression and a blue one for Herbie's output. Lower is\n  better. You can see from the plot that as <code>xim</code> gets\n  larger (toward the right, closer to zero), Herbie's improvement\n  becomes more and more important. Below the plot, there is a list of\n  the argument names, with <code>xim</code> highlighted. If you switch\n  it to <code>xre</code>, you will see that the two expressions are\n  the same for positive <code>xre</code>, and that Herbie's output is\n  better for negative <code>xre</code>. You can also see that the\n  difference is quite large, with Herbie's output expression being\n  much more accurate than its input.</p>\n\n  <p>Note again that Herbie is randomized, and you may see somewhat\n  different output than the screenshots and descriptions here. The\n  overall gist should be similar, however.</p>\n\n  <p>Now that you have the more accurate version of this expression,\n    all you need to do is insert it back into the program:</p>\n\n  <pre>var r = Math.sqrt(x.re * x.re + x.im * x.im);\n// Herbie version of 0.5 * Math.sqrt(2.0 * (r + x.re))\nvar re;\nif (x.re &lt;= 0) {\n    re = Math.abs(x.im) * Math.sqrt(0.5) / Math.sqrt(r - x.re);\n} else {\n    re = 0.5 * Math.sqrt(2.0 * (r + x.re));\n}\nif (x.im &gt;= 0) {\n  return new Complex(\n      re,\n      0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}\nelse {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      -0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}</pre>\n\n  <p>Note that I've left the original code in place in a comment.\n  That's because the original code is a bit more readable, and it also\n  means that as Herbie gets better, we can re-run it to get future\n  improvements in accuracy.</p>\n\n  <p>By the way, for some languages, like C, you can use the drop-down\n  in the top-right corner of the gray program block to see Herbie's\n  output in that language. You'll probably need to clean up the\n  resulting program a bit, though.</p>\n\n  <h2>Next steps</h2>\n\n  <p>With this change, we've made this part of the complex square root\n  function much more accurate, and we could repeat the same steps for\n  the other branches and other fields in this program. You now have a\n  pretty good understanding of Herbie and how to use it.\n  Please <a href=\"mailto:herbie@cs.washington.edu\">let us know</a> if\n  Herbie has helped you, and check out\n  the <a href=\"../../doc.html\">documentation</a> to learn more about\n  Herbie's various options and outputs.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.3/using-cli.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie from the Command Line</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Using Herbie from the Command Line</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> rewrites floating point expressions to\n    make them more accurate. The expressions could come from\n    anywhere—your source code, mathematical papers, or even the output\n    of <a href=\"../1.0/using-herbgrind.html\">Herbgrind</a>, our tool for\n    finding inaccurate expressions in binaries.\n  </p>\n\n  <p>Herbie can be used from the command-line\n  or from <a href=\"using-web.html\">the browser</a>. This page covers\n  using Herbie from the command line.</p>\n\n  <h2>Input expressions</h2>\n\n  <p>Herbie takes file and command-line input\n  in <a href=\"input.html\">FPCore syntax</a>. You can find example\n  FPCore files in the <code>bench/</code> directory in the source\n  code. For example, <code>bench/tutorial.fpcore</code> contains:</p>\n\n  <pre>(FPCore (x)\n  :name \"Cancel like terms\"\n  (- (+ 1 x) x))\n\n(FPCore (x)\n  :name \"Expanding a square\"\n  (- (sqr (+ x 1)) 1))\n\n(FPCore (x y z)\n  :name \"Commute and associate\"\n  (- (+ (+ x y) z) (+ x (+ y z))))</pre>\n\n  <p> This code defines three floating point expressions that we want\n    to run Herbie on:</p>\n\n  <ul>\n    <li><code>(1 + x) - x</code>, titled “Cancel like terms”</li>\n    <li><code>(x + 1)² - 1</code>, titled “Expanding a square”</li>\n    <li><code>((x + y) + z) - (x + (y + z))</code>, titled “Commute\n    and associate”</li>\n  </ul>\n\n  <p>The <a href=\"input.html\">input format documentation</a> contains more details.</p>\n\n  <h2 id=\"interactive\">The Herbie shell</h2>\n\n  <p>\n    The Herbie shell lets you interact with Herbie, typing in\n    benchmark expressions and seeing the outputs. Run the Herbie\n    shell:\n  </p>\n\n  <pre>herbie shell</pre>\n\n  <p>\n    After a few seconds, Herbie will start up and wait for input:\n  </p>\n\n  <pre class=\"shell\">herbie shell\nHerbie 1.3 with seed 2098242187\nFind help on https://herbie.uwplse.org/, exit with Ctrl-D\nherbie&gt; </pre>\n\n  <p>The printed seed can be used to reproduce a Herbie run. You can\n  now paste inputs directly into your terminal for Herbie to\n  improve:</p>\n\n  <pre><strong>herbie&gt;</strong> (FPCore (x) :name \"Cancel like terms\" (- (+ 1 x) x))\n(FPCore\n  (x)\n  <var>...</var>\n  1.0)</pre>\n\n  <p>The output suggests the expression <code>1</code> as a more\n  accurate variant of the original expression. Note that\n  the <var>...</var> hides lots\n  of <a href=\"file:///home/pavpan/herbie/www/doc/1.3/input.html#properties\">additional\n  information</a> from Herbie, including error estimates and runtime\n  information.</p>\n\n  <p>The Herbie shell makes it easy to play with different expressions\n  and try multiple variants, informed by Herbie's advice.</p>\n\n  <h2 id=\"batch\">Batch processing FPCores</h2>\n\n  <p>\n    Alternatively, you can run Herbie on a file with multiple\n    expressions in it, producing the output expressions to a file.\n    This mode is intended for use by scripts.\n  </p>\n\n  <pre class=\"shell\">herbie improve bench/tutorial.fpcore out.fpcore\nStarting Herbie on 3 problems (seed: 1809676410)...\n  1/3\t[   2.202s]   29→ 0\tCancel like terms\n  2/3\t[  14.875s]   39→ 0\tExpanding a square\n  3/3\t[   8.546s]    0→ 0\tCommute and associate</pre>\n\n  <p>\n    The output file <code>out.fpcore</code> contains more accurate\n    versions of each program:\n  </p>\n\n  <pre>;; seed: 1809676410\n\n(FPCore (x) <var>...</var> 1.0)\n(FPCore (x) <var>...</var> (+ (* x x) (* 2.0 x)))\n(FPCore (x y z) <var>...</var> 0.0)</pre>\n\n  <p>\n    Note that the order of expressions is identical.\n    For more control over Herbie, see the documentation of\n    Herbie's <a href=\"options.html\">command-line options</a>.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.3/using-web.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie from the Browser</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Using Herbie from the Browser</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> rewrites floating point expressions to\n    make them more accurate. The expressions could come from\n    anywhere—your source code, mathematical papers, or even the output\n    of <a href=\"../1.0/using-herbgrind.html\">Herbgrind</a>, our tool for\n    finding inaccurate expressions in binaries.\n  </p>\n\n  <p>Herbie can be used from <a href=\"using-cli.html\">the\n  command-line</a> or from the browser. This page covers\n  using Herbie from the browser.</p>\n\n\n  <h2 id=\"interactive\">The Herbie web shell</h2>\n\n  <p>\n    The Herbie web shell lets you interact with Herbie through your\n    browser, featuring a convenient input format. Run the Herbie web\n    shell:\n  </p>\n\n  <pre class=\"shell\">herbie web</pre>\n\n  <p>After a few seconds, the web shell will rev up and direct your\n  browser to Herbie:</p>\n  \n  <pre class=\"shell\">herbie web\nHerbie 1.3 with seed 841489305\nFind help on https://herbie.uwplse.org/, exit with Ctrl-C\nYour Web application is running at http://localhost:8000/.\nStop this program at any time to terminate the Web Server.</pre>\n\n  <figure>\n    <img width=\"100%\" src=\"web-main.png\" />\n    <figcaption>The Herbie web shell.</figcaption>\n  </figure>\n\n  <p>\n    You can type expressions in standard mathematical syntax (parsed\n    by <a href=\"http://mathjs.org\">Math.js</a>), and\n    hit <kbd>Enter</kbd> to have Herbie attempt to improve them.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"web-progress.png\" />\n    <figcaption>Herbie shows improvement logs as it works.</figcaption>\n  </figure>\n\n  <p>\n    The web shell will print Herbie's progress, and redirect to a\n    <a href=\"report.html\">report</a> once Herbie is done.\n  </p>\n\n  <p>\n    Interactive use of the web shell is the friendliest and easiest\n    way to use Herbie. The web shell has <a href=\"options.html\">many\n    options</a>, including automatically saving the generated reports.\n  </p>\n\n\n  <h2 id=\"batch\">Batch report generation</h2>\n\n  <p>A <a href=\"report.html\">report</a> can also be generated directly\n  from a file of <a href=\"input.html\">input expressions</a>:</p>\n  \n  <pre><strong>$</strong> herbie report input.fpcore output/\nStarting Herbie on 3 problems (seed: 1201949741)...\n  1/3\t[  22.014s]   39→ 0\tExpanding a square\n  2/3\t[   8.616s]    0→ 0\tCommute and associate\n  3/3\t[   1.715s]   29→ 0\tCancel like terms</pre>\n\n  <p>\n    This command asks Herbie to generate a report from the input\n    expressions in <code>input.fpcore</code> and save the report in\n    the directory <code>output/</code>, which ought not exist yet.\n    The printed seed can be used to reproduce a run of Herbie.\n  </p>\n\n  <p>\n    Once generated, open the <code>output/results.html</code> page\n    in your favorite browser (but see <a href=\"faq.html\"> the FAQ</a>\n    if you're using Chrome). From that page, you can click on the rows\n    in the table at the bottom to see the report for that expression.\n  </p>\n\n  <p>Batch report generation is the most informative way to run Herbie\n  on a large collection of inputs. Like the web shell, it can be\n  customized through <a href=\"options.html\">command-line options</a>,\n  including parallelizing Herbie with multiple threads.</p>\n\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.4/docker.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie on Docker</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Installing with Docker</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> is available\n    through <a href=\"https://www.docker.com/\">Docker</a>, which is a\n    sort of like a virtual machine. This page describes how to install\n    the <a href=\"https://hub.docker.com/uwplse/herbie\">official Docker\n    image</a> for Herbie.\n  </p>\n  \n  <p>\n    Herbie can also be <a href=\"installing.html\">installed from\n    package or source</a>. Herbie via Docker is only recommended if\n    you already have Docker experience.\n  </p>\n  \n  <h2>Installing Herbie via Docker</h2>\n\n  <p>\n    First, <a href=\"https://docs.docker.com/installation/\">install\n    Docker</a>. Docker supports Windows, macOS, and Linux. Depending\n    on how you install Docker, you may need to prefix\n    the <code>docker</code> command with <code>sudo</code> or run them\n    as the administrative user.\n  </p>\n\n  <p>With Docker installed, download the Herbie image:</p>\n \n  <pre class=\"shell\">docker pull uwplse/herbie</pre>\n\n  <p>You can now run Herbie:</p>\n\n  <pre>docker run -it uwplse/herbie shell</pre>\n  \n  <p>This will run the <a href=\"using-cli.html\">Herbie shell</a>,\n  reading input from the standard input.</p>\n  \n  <p>Note that Herbie in Docker is more limited; for example, it will\n  not recognize plugins installed outside the Docker container.</p>\n\n  <h2>Running the web shell</h2>\n\n  <p>Running the web shell in Docker requires exposing the ports\n  inside the container. The Herbie Docker image binds to port 80 by\n  default; use the <code>-p &lt;hostport&gt;:80</code> option to\n  Docker to expose Herbie on whatever port you choose.\n  </p>\n\n  <pre class=\"shell\">docker run -it --rm -p 8000:80 uwplse/herbie</pre>\n\n  <p>\n    If you are using the <code>--log</code>\n    or <code>--save-session</code> flags for the web shell,\n    you will also need to mount the relevant directories into the\n    Docker container using the <code>-v</code> Docker option, as in\n    the examples below.\n  </p>\n\n  <h2>Generating files and reports</h2>\n\n  <p>\n    To use Herbie in <a href=\"using-cli.html\">batch mode</a>, you will\n    need to mount the input in the Docker container. Do that with:\n  </p>\n  \n  <pre class=\"shell\">docker run -it --rm \\\n    -v <var>in-dir</var>:/in \\\n    -v <var>out-dir</var>:/out \\\n    -u $USER \\\n    uwplse/herbie improve /in/<var>in-file</var> /out/<var>out-file</var></pre>\n\n  <p>\n    In this command, you are asking Herbie to read input\n    from <var>in-file</var> in <var>in-dir</var>, and write output\n    to <var>out-file</var> in <var>out-dir</var>. The command looks\n    the same if you want Herbie to read input from a directory;\n    just leave <var>in-file</var> blank.\n  </p>\n\n  <p>\n    To generate reports from Herbie, you can run:\n  </p>\n\n  <pre class=\"shell\">docker run -it --rm \\\n    -v <var>in-dir</var>:/in \\\n    -v <var>out-dir</var>:/out \\\n    -u $USER \\\n    uwplse/herbie report /in/<var>in-file</var> /out/</pre>\n\n  <p>\n    As before, the input and output directories must be mounted inside\n    the Docker container. Note that both here and above, the user is\n    set to the current user. This is to ensure that the files Herbie creates\n    have the correct permissions set.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.4/faq.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie FAQ</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Common Errors and Warnings</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p><a href=\"../../\">Herbie</a> automatically transforms floating\n  point expressions into more accurate forms. This page troubleshoots\n  common Herbie errors, warnings, and known issues.</p>\n\n\n  <h2>Common errors</h2>\n\n  <p>\n    Herbie error messages refer to this second for additional\n    information and debugging tips.\n  </p>\n\n  <h3 id=\"invalid-syntax\">Invalid syntax</h3>\n\n  <p>\n    This error means you mis-formatted Herbie's input. Common errors\n    include misspelled function names and parenthesized expressions\n    that should not be parenthesized. For example, in\n    <code>(- (exp (x)) 1)</code>, the expression <code>x</code> is a\n    variable so shouldn't be parenthesized. <code>(- (exp x) 1)</code>\n    would be the correct way to write that expression.\n    The <a href=\"input.html\">input format</a> documentation has more\n    details on Herbie's syntax.\n  </p>\n\n  <h3 id=\"sample-valid-points\">Cannot sample enough valid points</h3>\n\n  <p>This error occurs when Herbie is unable to find enough valid\n  points. For example, the expression <code>(acos (+ 1000 x))</code>\n  is invalid unless <code>(&lt;= -1001 x -999)</code>, a rather narrow\n  range. The simplest fix is to increase\n  the <a href=\"options.html\"><code>--num-analysis</code> flag</a>.\n  Specifying the range of valid points as\n  a <a href=\"input.html#preconditions\">precondition</a> can also help.\n  </p>\n\n  <h3 id=\"no-valid-values\">No valid values</h3>\n\n  <p>This error indicates that your input has no valid inputs, usually\n  due to an overly restriction precondition. For example, the\n  precondition <code>(&lt 3 x 2)</code> excludes all inputs. The\n  solution is to fix the precondition or input program.</p>\n\n  <h3 id=\"mpfr-prec-limit\">Exceeded MPFR precision limit</h3>\n\n  <p>This rare error indicates that Herbie could not compute a \"ground\n  truth\" for your expression. For some expressions, like <code>(sin\n  (exp x))</code>, calculating a correct output for large input values\n  requires exponentially many bits. Herbie raises this error when more\n  than 10,000 bits are required.</p>\n\n\n  <h2>Common warnings</h2>\n\n  <p>Herbie warnings refer to this section for explanations and common\n  actions to take.</p>\n\n  <h3 id=\"ground-truth\">Could not determine a ground truth</h3>\n\n  <p>\n    Herbie raises this warning when some inputs require more than\n    10 000 bits to compute an exact ground truth. For example, to\n    compute <code>(/ (exp x) (exp x))</code> for very\n    large <code>x</code>, absurdly large exponents would be required.\n    Herbie discards such inputs and raises this warning. If you see\n    this warning, you should add a restrictive precondition, such\n    as <code>:pre (&lt; -100 x 100)</code>, to prevent large inputs.\n  </p>\n\n  <h3 id=\"native-ops\">Native <var>operation</var> not supported on your system</h3>\n\n  <p>\n    Microsoft's <code>math.h</code> does not provide implementations\n    of the Bessel functions. Herbie provides fallback implementations\n    which print this warning. You can disable the fallback with\n    the <code>--disable precision:fallback</code> option; Herbie will\n    then not use those functions.\n  </p>\n\n  <h3 id=\"value-to-string\">Could uniquely print <var>val</var></h3>\n\n  <p>\n    Herbie will raise this warning when it needs more than 10,000 bits\n    to produce a string representation for a given value. This is\n    likely the result of a bug in a third-party plugin.\n  </p>\n\n  <h3 id=\"egg-herbie\">Falling back on regraph because egg-herbie package not installed</h3>\n\n  <p>\n    Herbie can use either the <code>egg-herbie</code>\n    or <code>regraph</code> package to simplify\n    expressions; <code>egg-herbie</code> is much faster, but uses\n    compiled binaries that cannot be installed on some systems. Herbie\n    will then fall back to <code>regraph</code>, and get similar\n    results but run roughly twice as long.\n    Install <code>egg-herbie</code> with <code>raco</code>.\n  </p>\n\n\n  <h2>Known bugs</h2>\n\n  <p>Bugs that cannot be directly fixed are documented in this section.</p>\n\n  <h3>Missing reports chart on Chrome</h3>\n\n  <p>\n    When using Chrome to view web pages on your local machine, Herbie\n    reports cannot draw the arrow chart due to security restrictions.\n    <a href=\"http://www.chrome-allow-file-access-from-file.com/\">Run\n    Chrome with <code>--allow-file-access-from-files</code></a> to fix\n    this error.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.4/input.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Input Format</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>The Input Format</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> uses\n    the <a href=\"http://fpbench.org\">FPCore</a> format to specify an\n    input program, and has extensive options for precisely describing\n    its context.\n  </p>\n  \n  <h2 id=\"sec1\">General format</h2>\n\n  <p><a href=\"http://fpbench.org\">FPCore</a> format looks like this:</p>\n\n  <pre>(FPCore (<var>inputs ...</var>) <var>properties ...</var> <var>expression</var>)</pre>\n\n  <p>\n    Each <var>input</var> is a variable name, like <code>x</code>,\n    used in the <var>expression</var>. Properties are used to specify\n    additional information about the <var>expression</var>'s context.\n  </p>\n\n  <p>\n    The expression is written in prefix form, with every function call\n    parenthesized, as in Lisp. For example, the formula for the\n    hypotenuse of a triangle with legs <i>a</i> and <i>b</i> is:\n  </p>\n\n  <pre>(FPCore (a b) (sqrt (+ (* a a) (* b b))))</pre>\n\n  <p>\n    The semicolon (<kbd>;</kbd>) character introduces a line comment.\n    We recommend the <code>.fpcore</code> file extension for Herbie input files.\n  </p>\n  \n  <h2>Supported functions</h2>\n  \n  <p>\n    Herbie supports all functions\n    from <a href=\"http://pubs.opengroup.org/onlinepubs/7908799/xsh/math.h.html\">math.h</a>\n    with floating-point-only inputs and outputs. The best supported\n    functions include:\n  </p>\n\n  <dl class=\"function-list\">\n    <dt><code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>, <code>fabs</code></dt>\n    <dd>The usual arithmetic functions</dd>\n    <dt><code>sqrt</code>, <code>cbrt</code></dt>\n    <dd>Square and cube roots</dd>\n    <dt><code>pow</code>, <code>exp</code>, <code>log</code></dt>\n    <dd>Various exponentiations and logarithms</dd>\n    <dt><code>sin</code>, <code>cos</code>, <code>tan</code></dt>\n    <dd>The trigonometric functions</dd>\n    <dt><code>asin</code>, <code>acos</code>, <code>atan</code>, <code>atan2</code></dt>\n    <dd>The inverse trigonometric functions</dd>\n    <dt><code>sinh</code>, <code>cosh</code>, <code>tanh</code></dt>\n    <dd>The hyperbolic functions</dd>\n    <dt><code>asinh</code>, <code>acosh</code>, <code>atanh</code></dt>\n    <dd>The inverse hyperbolic functions</dd>\n    <dt><code>fma</code>, <code>expm1</code>, <code>log1p</code>, <code>hypot</code></dt>\n    <dd>Specialized numeric functions</dd>\n  </dl>\n\n  <p>Herbie also supports the constants <code>PI</code>\n  and <code>E</code>. The arithmetic operators associate to the left,\n  and <code>-</code> is used for both subtraction and negation.</p>\n\n  <p>Herbie links against your computer's <code>libm</code> to\n  evaluate these functions. So, each function has the same behavior in\n  Herbie as in your code.</p>\n\n  <p>On Windows, the Bessel functions are not available in the\n  system <code>libm</code>, so Herbie will use a fallback\n  implementation and print a warning. Turn off the\n  the <kbd>precision:fallback</kbd> <a href=\"options.html\">option</a>\n  to disable those functions instead.</p>\n\n  <h2 id=\"conditionals\">Conditionals</h2>\n  \n  <p>FPCore uses <code>if</code> for conditional expressions:</p>\n\n  <pre>(if <var>cond</var> <var>if-true</var> <var>if-false</var>)</pre>\n\n  <p>\n    The conditional <code><var>cond</var></code> may use:\n  </p>\n  \n  <dl class=\"function-list\">\n    <dt><code>==</code>, <code>!=</code>, <code>&lt;</code>, <code>&gt;</code>, <code>&lt;=</code>, <code>&gt;=</code></dt>\n    <dd>The usual comparison operators</dd>\n    <dt><code>and</code>, <code>or</code>, <code>not</code></dt>\n    <dd>The usual logical operators</dd>\n    <dt><code>TRUE</code>, <code>FALSE</code></dt>\n    <dd>The two boolean values</dd>\n  </dl>\n\n  <p>The comparison functions implement chained comparisons with more than two arguments.</p>\n\n  <h2 id=\"intermediates\">Intermediate variables</h2>\n  \n  <p>Intermediate variables can be defined\n    using <code>let</code> and <code>let*</code>:</p>\n\n  <pre>(let ([<var>variable</var> <var>value</var>] <var>...</var>) <var>body</var>)</pre>\n\n  <p>In both <code>let</code> and <code>let*</code>,\n  each <var>variable</var> is bound to its <var>value</var> and can be\n  used in the <var>body</var>. The difference between <code>let</code>\n  and <code>let*</code> is what order the values are\n  evaluated in:</p>\n\n  <dl>\n    <dt><code>let</code> expressions</dt>\n    <dd>In a <code>let</code> expression, all the values are evaluated\n      in parallel, before they are bound to their variables. This\n      means that later values can't refer to earlier variables in the\n      same <code>let</code> block.</dd>\n\n    <dt><code>let*</code> expressions</dt>\n    <dd>A <code>let*</code> block looks the same as a <code>let</code>\n      block, except the values are evaluated one at a time, and later\n      values can refer to earlier variables.</dd>\n  </dl>\n\n  <p>Note that Herbie treats intermediate values only as a notational\n  convenience, and inlines their values before improving the formula's\n  accuracy. Using intermediate variables will not help Herbie improve\n  a formula's accuracy or speed up its run-time.</p>\n\n  <h2 id=\"preconditions\">Preconditions</h2>\n\n  <p>By default, the arguments to formulas are assumed to be\n  arbitrarily large or small floating-point numbers. However, in most\n  programs a smaller range of argument values is possible.\n  The <code>:pre</code> property (for “precondition”) describes this\n  smaller range.</p>\n\n  <p>Preconditions use comparison and boolean operators, just\n  like <a href=\"#conditionals\">conditional statements</a>:</p>\n\n  <pre>(FPCore (x) :pre (&lt; 1 x 10) (/ 1 (- x 1)))</pre>\n\n  <p>Herbie is particularly efficient when when the precondition is\n  an <code>and</code> of ranges for each variable, but more complex\n  preconditions also work.</p>\n\n  <h2 id=\"precisions\">Precisions</h2>\n\n  <p>Herbie supports both single- and double-precision values; you can\n  specify the precision with the <code>:precision</code> property:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>binary32</code></dt>\n    <dd>Single-precision IEEE-754 floating point</dd>\n    <dt><code>binary64</code></dt>\n    <dd>Double-precision IEEE-754 floating point</dd>\n  </dl>\n\n  <p>By default, <code>binary64</code> is assumed. Herbie also has\n  a <a href=\"plugins.html\">plugin system</a> to load additional\n  precisions.</p>\n\n  <h2 id=\"specs\">Specifications</h2>\n\n  <p>In some cases, your input program is an approximation of some\n  more complex mathematical expression. The <code>:spec</code> (for\n  “specification”) lets you specify the more complex ideal case.\n  Herbie will then try to modify the input program to make it more\n  accurately evaluate the specification.</p>\n\n  <p>For example, suppose you want to evaluate <code>sin(1/x)</code>\n  via a series expansion. Write:</p>\n\n  <pre>(FPCore (x)\n  :spec (sin (/ 1 x))\n  (+ (/ 1 x) (/ 1 (* 6 (pow x 3)))))</pre>\n\n  <p>Herbie will only use the <code>:spec</code> expression to\n  evaluate error, not to search for accurate expressions.</p>\n\n  <h2 id=\"properties\">Miscellaneous Properties</h2>\n\n  <p>Herbie uses the <code>:name</code> property to name FPCores in\n  its UI. Its value ought to be a string.</p>\n\n  <p>Herbie's output provide additional information in custom\n  properties:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>:herbie-status <var>status</var></code></dt>\n    <dd><var>status</var> describes whether Herbie worked: it is one\n    of <code>success</code>, <code>timeout</code>, <code>error</code>,\n    or <code>crash</code>.</dd>\n    <dt><code>:herbie-time <var>ms</var></code></dt>\n    <dd>The time, in milliseconds, used by Herbie to find a more accurate formula.</dd>\n    <dt><code>:herbie-error-input<br/>([<var>pts</var> <var>err</var>] ...)</code></dt>\n    <dd>The average <var>err</var>or of the input program at <var>pts</var> points. Multiple entries correspond to Herbie's training and test sets.</dd>\n    <dt><code>:herbie-error-output<br/>([<var>pts</var> <var>err</var>] ...)</code></dt>\n    <dd>The computed average error of the output program, similar to <code>:herbie-error-input</code>.</dd>\n  </dl>\n\n  <p>Herbie's benchmark suite also uses properties such\n  as <code>:herbie-target</code> for continuous integration, but these\n  are not supported and their use is discouraged.</p>\n  \n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.4/installing.html",
    "content": "<!doctype html>\n<html>\n\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Installing Herbie</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n\n<body>\n  <header>\n    <h1>Installing Herbie</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> supports Linux, macOS, and Windows. It\n    can be installed from a package or from source. To start, install\n    <a href=\"https://racket-lang.org\">Racket</a>, which Herbie is\n    written in. (Herbie is also available as\n    a <a href=\"docker.html\">Docker image</a>.)\n  </p>\n\n  <h2>Installing Racket</h2>\n\n  <p>\n    Install Racket, version 7.0 or later, either using\n    the <a href=\"http://download.racket-lang.org/racket-v7.7.html\">official\n      installer</a> or distro-provided packages. Versions 7.5 and later\n    are significantly faster, and we recommend upgrading.\n  </p>\n\n  <p>\n    Test that Racket is installed correctly and has a correct version:\n  </p>\n\n  <pre class=\"shell\">racket\nWelcome to Racket v7.7.\n> (exit)</pre>\n\n  <h2>Installing Herbie from a package</h2>\n\n  <p>Once Racket is installed, install Herbie from a package with:</p>\n\n  <pre class=\"shell\">raco pkg install --auto herbie</pre>\n\n  <p>\n    This command installs Herbie and its dependencies, compiles it for\n    faster startup, and places the <code>herbie</code> executable in\n    your Racket user path (example paths for Racket 7.7):\n  </p>\n\n  <ul>\n    <li>On Windows, <code>AppData\\Roaming\\Racket\\7.7\\bin</code> in your user folder.</li>\n    <li>On macOS, <code>Library/Racket/7.7/bin</code> in your user folder.</li>\n    <li>On Linux, <code>.racket/7.7/bin</code> in your home directory.</li>\n  </ul>\n\n  <p>\n    You can run <code>herbie</code> from that directory, or add it to\n    your executable path. Once Herbie is installed and working\n    correctly, check out the <a href=\"tutorial.html\">tutorial</a>.\n  </p>\n\n  <h2>Installing Herbie from source</h2>\n\n  <p>\n    Install Rust, using <a href=\"https://rustup.rs/\">rustup</a> or via\n    some other means. Also install Racket, version 7.0 or later, either using\n    the <a href=\"http://download.racket-lang.org/racket-v7.7.html\">official\n      installer</a> or distro-provided packages.\n  </p>\n\n  <p>\n    Once Racket and Rust are installed, download the Herbie source\n    <a href=\"https://github.com/uwplse/herbie\">from GitHub</a> with:\n  </p>\n\n  <pre class=\"shell\">git clone https://github.com/uwplse/herbie</pre>\n\n  <p>\n    Change to the <code>herbie</code> directory;\n    you should see a <code>README.md</code> file, a directory named <code>src</code>,\n    a directory named <code>bench/</code>, and a few other directories.\n    Install Herbie on your system with:\n  </p>\n\n  <pre class=\"shell\">make install</pre>\n\n  <!-- This is a copy of the text above -->\n\n  <p>\n    This command installs Herbie and its dependencies, compiles it for\n    faster startup, and places the <code>herbie</code> executable in\n    your Racket user path:\n  </p>\n\n  <ul>\n    <li>On Windows, <code>AppData\\Roaming\\Racket\\7.7\\bin</code> in your user folder.</li>\n    <li>On macOS, <code>Library/Racket/7.7/bin</code> in your user folder.</li>\n    <li>On Linux, <code>.racket/7.7/bin</code> in your home directory.</li>\n  </ul>\n\n  <p>\n    You can run <code>herbie</code> from that directory, or add it to\n    your executable path. Once Herbie is installed and working\n    correctly, check out the <a href=\"tutorial.html\">tutorial</a>.\n  </p>\n\n  <!-- End of copy -->\n\n  <h2>Installing Herbie with Docker</h2>\n\n  <p>\n    <a href=\"https://docker.com\">Docker</a> is a container manager,\n    which is sort of like an easily-scriptable virtual machine. Herbie\n    in Docker is more limited; we do not recommend using Herbie\n    through Docker without prior Docker experience.\n  </p>\n\n  <p>\n    The <a href=\"docker.html\">Docker documentation</a> describes how\n    to install and run the official <code>uwplse/herbie</code> image.\n  </p>\n\n</body>\n\n</html>"
  },
  {
    "path": "www/doc/1.4/options.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Command-line Options</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Command-line Options</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>The <a href=\"../../\"><code>herbie</code></a> command has\n  subcommands and options that influence both its user interface and\n  the quality of its output.</p>\n\n  <h2>Herbie commands</h2>\n\n  <p>Herbie can be run both interactively and in batch mode, and can\n  generate output intended either for\n  the <a href=\"using-cli.html\">command line</a>\n  or <a href=\"using-web.html\">the web</a>. We call these different\n  ways of running Herbie different tools. Herbie provides four\n  tools:</p>\n\n  <dl>\n    <dt><code>herbie web</code></dt>\n    <dd>Use Herbie <a href=\"using-web.html\">through your browser</a>.\n    The <code>herbie web</code> command runs Herbie on your local\n    machine and opens your browser to its main page.</dd>\n\n    <dt><code>herbie shell</code></dt>\n    <dd>Use Herbie <a href=\"using-cli.html\">via a command-line shell</a>.\n    Enter an <a href=\"input.html\">FPCore expression</a> and Herbie\n    will print its more-accurate version.</dd>\n\n    <dt><code>herbie improve <var>input</var> <var>output</var></code></dt>\n    <dd>Run Herbie on the expressions in the file or\n    directory <var>input</var>. The results are written\n    to <var>output</var>, a single file in FPCore format.</dd>\n\n    <dt><code>herbie report <var>input</var> <var>output</var></code></dt>\n    <dd>Run Herbie on the expressions in the file or\n    directory <var>input</var>. The results are written\n    to <var>output</var>, a directory of\n    HTML <a href=\"report.html\">reports</a>. These pages can be viewed\n    in any browser (though with a <a href=\"faq.html\">quirk</a> for\n    Chrome).</dd>\n  </dl>\n\n  <p>We recommend using <code>web</code> and <code>report</code>,\n  which produce <a href=\"report.html\">reports</a> with lots of\n  information about floating-point accuracy, including graphs it of\n  error versus input values. This can help you understand whether\n  Herbie's improvements matter for your use case.</p>\n\n  <p>Use <code>herbie <var>tool</var> --help</code> to available\n  command-line options for a tool. This command also shows unsupported\n  options not listed on this page.</p>\n\n  <h2>General options</h2>\n\n  <p>\n    These options can be set on any tool. Pass them after the tool\n    name but before other arguments, like this:\n  </p>\n\n  <pre class=\"shell\">herbie report --timeout 60 in.fpcore out/</pre>\n\n  <p>Arguments cannot go before options.</p>\n\n  <dl>\n    <dt><code>--seed S</code></dt>\n    <dd>The random seed, which changes the randomly-selected points\n      that Herbie evaluates candidate expressions on. The seed is a\n      number between 0 and 2<sup>31</sup> (exclusive both ends). This\n      option can be used to make Herbie's results reproducible or to\n      compare two different runs. Seeds are not preserved across\n      runs.</dd>\n\n    <dt><code>--num-points N</code></dt>\n    <dd>The number of input points Herbie uses to evaluate candidate\n      expressions. The default, 256, is a good balance for most\n      programs. Increasing this option, say to 512 or 1024, will slow\n      Herbie down but may make its results more consistent.</dd>\n\n    <dt><code>--num-iters N</code></dt>\n    <dd>The number of times Herbie attempts to improve accuracy. The\n      default, 4, suffices for most programs and helps keep Herbie\n      fast; in practice iterations beyond the first few rarely lead to\n      lower error. Increase this option, say to 6, to check that there\n      aren't further improvements that Herbie could seek out.</dd>\n\n    <dt><code>--num-analysis N</code></dt>\n    <dd>The number of input subdivisions to use when searching for\n      valid input points. The default is 14. Increasing this option\n      will slow Herbie down, but may fix the\n      \"<a href=\"faq.html#sample-valid-points\">Cannot sample enough\n      valid points</a>\" error.\n    </dd>\n    \n    <dt><code>--timeout T</code></dt>\n    <dd>The timeout to use per-input, in seconds. A fractional number\n      of seconds can be given.</dd>\n\n    <dt><code>--threads N</code> (for the <code>improve</code> and <code>report</code> tools)</dt>\n    <dd>Enables multi-threaded operation. By default, no threads are\n      used. A number can be passed to this option to use that many\n      threads, or <code>yes</code> can be passed to tell Herbie to use\n      all of the hardware threads.</dd>\n  </dl>\n\n  <h2>Web shell options</h2>\n  \n  <p>The <code>web</code> tool runs Herbie and connects to it from\n  your browser. It has options to control the underlying web\n  server.</p>\n  \n  <dl>\n    <dt><code>--port N</code></dt>\n    <dd>The port the Herbie server runs on. The default port is 8000.</dd>\n\n    <dt><code>--save-session dir</code></dt>\n    <dd>Save all the reports to this directory. The directory also\n    caches of previously-computed expressions.</dd>\n\n    <dt><code>--log file</code></dt>\n    <dd>Write an access log to this file, formatted like an Apache\n    log. This log does <em>not</em> contain crash tracebacks.</dd>\n\n    <dt><code>--quiet</code></dt>\n    <dd>By default, but not when this option is set, a browser is\n    automatically started to show the Herbie page. This option also\n    shrinks the text printed on start up.</dd>\n\n    <dt><code>--public</code></dt>\n    <dd>When set, users on other computers can connect to the demo and\n    use it. (In other words, the server listens\n    on <code>0.0.0.0</code>.). Essential when Herbie is run\n    from <a href=\"docker.html\">Docker</a>.</dd>\n  </dl>\n\n  <h2>Rulesets</h2>\n\n  <p>\n    Herbie uses rewrite rules to change programs and improve accuracy.\n    The <code>--disable rules:<var>group</var></code>\n    and <code>--enable rules:<var>group</var></code> options turn rule\n    sets on and off. In general, turning a ruleset on makes Herbie\n    produce more accurate but more confusing programs.\n  </p>\n\n  <p>The full list of rule groups is:</p>\n\n  <table class=\"function-list\">\n    <thead><tr><th>Rule Group</th><th>Topic of rewrite rules</th></tr></thead>\n    <tr><td>arithmetic</td><td>Basic arithmetic facts</td></tr>\n    <tr><td>polynomials</td><td>Factoring and powers</td></tr>\n    <tr><td>fractions</td><td>Fraction arithmetic</td></tr>\n    <tr><td>exponents</td><td>Exponentiation identities</td></tr>\n    <tr><td>trigonometry</td><td>Trigonometric identities</td></tr>\n    <tr><td>hyperbolic</td><td>Hyperbolic trigonometric identities</td></tr>\n    <tr><td>bools</td><td>Boolean operator identities</td></tr>\n    <tr><td>branches</td><td><code>if</code> statement simplification</td></tr>\n    <tr><td>special</td><td>The gamma, Bessel, and error functions</td></tr>\n    <tr><td>numerics</td><td>Numerical compounds <code>expm1</code>, <code>log1p</code>, <code>fma</code>, and <code>hypot</code></td></tr>\n  </table>\n\n  <p>All groups except <code>numerics</code> are enabled by default.\n  We recommend turning <code>numerics</code> on if these functions are\n  available in your language.</p>\n\n  <h2>Search options</h2>\n\n  <p>\n    These options change the types of transformations that Herbie uses\n    to find candidate programs. We recommend sticking to the defaults.\n  </p>\n\n  <p>\n    Each option can be turned off with the <code>-o</code>\n    or <code>--disable</code> command-line flag and on with\n    <code>+o</code> or <code>--enable</code>. Turning an option off\n    typically results in less-accurate results, while turning a option\n    on typically results in more confusing output expressions.\n  </p>\n\n  <dl>\n    <dt><code>precision:fallback</code></dt>\n    <dd>This option, on by default, tells Herbie to use fallback\n    functions if a native implementation is not found for an operation\n    (and print a warning). If turned off, operations with no native\n    implementation will be disabled entirely. To our knowledge, this\n    option only affects the Bessel functions on Windows.</dd>\n\n    <dt><code>setup:simplify</code></dt>\n    <dd>This option, on by default, simplifies the expression before\n    passing it to Herbie. If turned off, Herbie will not simplify\n    input programs before improving them.</dd>\n\n    <dt><code>setup:early-exit</code></dt>\n    <dd>This option, off by default, causes Herbie to exit without\n    modifying the input program if it determines that the input\n    program has less than 0.1 bits of error. Turn this option on if\n    you are running Herbie on a large corpus of programs that you do\n    not believe to be inaccurate.</dd>\n\n    <dt><code>generate:rr</code></dt>\n    <dd>This option, on by default, uses Herbie's recursive rewriting\n    algorithm to generate candidate programs. If turned off, Herbie\n    will use a non-recursive rewriting algorithm, which will\n    substantially limit Herbie's creativity.</dd>\n\n    <dt><code>generate:taylor</code></dt>\n    <dd>This option, on by default, uses series expansion to produce\n    new candidates during the main improvement loop. If turned off,\n    Herbie will not use series expansion. Turn this option off if you\n    want to avoid series-expansion-based rewrites, such as if you need\n    to preserve the equivalence of the input and output expressions as\n    real-number formulas.</dd>\n\n    <dt><code>generate:simplify</code></dt>\n    <dd>This option, on by default, simplifies candidates during the\n    main improvement loop. If turned off, candidates will not be\n    simplified, which typically results in much less accurate\n    expressions.</dd>\n\n    <dt><code>reduce:regimes</code></dt>\n    <dd>This option, on by default, uses Herbie's regime inference\n    algorithm to branch between several program candidates. If turned\n    off, branches will not be inferred and the output program will be\n    straight-line code (if the input was). Turn this option off if\n    your programming environment makes branches very expensive, such\n    as on a GPU.</dd>\n\n    <dt><code>reduce:avg-error</code></dt>\n    <dd>This option, on by default, causes Herbie to output the\n    candidate with the best average error over the chosen inputs. If\n    turned off, Herbie will choose the candidate with the least\n    maximum error instead. This usually produces programs with worse\n    overall accuracy. Turn this option off if worst-case accuracy is\n    more important to you than overall accuracy.</dd>\n\n    <dt><code>reduce:binary-search</code></dt>\n    <dd>This option, on by default, uses binary search to refine the\n    values used in inferred branches. If turned off, different runs of\n    Herbie will be less consistent, and accuracy near branches will\n    suffer.</dd>\n\n    <dt><code>reduce:branch-expressions</code></dt>\n    <dd>This option, on by default, allows Herbie to branch on\n      expressions, not just variables. This slows Herbie down,\n      particularly for large programs. If turned off, Herbie will only\n      try to branch on variables.</dd>\n  </dl>\n\n  <h2>Upgrading from Herbie 1.0</h2>\n\n  <p>Herbie 1.0 used\n  a <a href=\"../1.0/using-herbie.html\">different</a> command line\n  syntax, without multiple tools. Translate like so:</p>\n\n  <ul>\n    <li><code>herbie-1.0</code> → <code>herbie-1.4 shell</code></li>\n    <li><code>herbie-1.0 file</code> → <code>herbie-1.4 improve file -</code></li>\n    <li><code>herbie-1.0 files ...</code> → <code>cat files ... | herbie-1.4 improve - -</code><br/>\n      Alternatively, collect the files into a directory and run <code>herbie-1.4 improve dir/ -</code></li>\n  </ul>\n\n  <p>The new syntax somewhat changes Herbie's behavior, such as by\n  using the input expression as the output if Herbie times out. It\n  also makes it easier to write Herbie's output to a file without\n  using command-line redirection.</p>\n\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.4/plugins.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Plugins</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Plugins</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p><a href=\"../../\">Herbie</a> plugins define new functions, add\n  rewrite rules, and even implement number representations.</p>\n\n  <p>Herbie plugins are installed separately. Herbie then\n  automatically loads and uses them.</p>\n  \n  <h2>Posit arithmetic</h2>\n\n  <p>The <kbd>softposit-herbie</kbd> plugin implements support\n  for <a href=\"https://posithub.org/\">posit</a> arithmetic. Install it\n  with:</p>\n\n  <pre class=\"shell\">raco pkg install --auto softposit-herbie</pre>\n\n  <p>This plugin uses the SoftPosit library, only supported on Linux.\n  Even then is reported to misbehave on some machines. The plugin\n  support arithmetic operations, <code>sqrt</code>, and quires.</p>\n\n  <p>Once <kbd>softposit-herbie</kbd> is installed,\n  specify <code>:precision posit16</code> to inform Herbie that it\n  should assume the core's inputs and outputs are posit numbers. Other\n  posit sizes (with 8 or 32 bits) and also quires (for 8, 16, and 32\n  bit posits) are available, but are poorly supported.</p>\n\n\n  <h2 id=\"complex\">Complex Numbers</h2>\n\n  <p>The <kbd>complex-herbie</kbd> plugin implements support for\n  complex numbers. Install it with:</p>\n\n  <pre class=\"shell\">raco pkg install --auto complex-herbie</pre>\n\n  <p>Herbie input parameters are always real numbers; complex\n  numbers must be constructed with <code>complex</code>. The\n  functions <code>re</code>, <code>im</code>, and <code>conj</code>\n  are available on complex numbers, along with the arithmetic\n  operators, <code>exp</code>, <code>log</code>, <code>pow</code>,\n  and <code>sqrt</code>. Complex and real operations use the same\n  syntax, but cannot be mixed: <code>(+ (complex 1 2) 1)</code> is not\n  valid. Herbie reports type errors in such situations.</p>\n\n  <p>Complex operations are implemented by\n  <a href=\"https://docs.racket-lang.org/reference/numbers.html#%28tech._complex._number%29\">Racket</a>,\n  so results may differ (slightly) from complex numbers in some other\n  language, especially for non-finite complex numbers. In the future,\n  we hope to support complex-number arguments and fully support all\n  complex-number operations.</p>\n\n  \n  <h2>Developing plugins</h2>\n\n  <p>The plugin functionality is currently highly experimental; if you\n  would like to develop your own plugins, please write to\n  the <a href=\"https://mailman.cs.washington.edu/mailman/listinfo/herbie\">mailing\n  list</a>.</p>\n  \n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.4/release-notes.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie 1.4 Release Notes</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <script src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML\"></script>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Herbie 1.4 Release Notes</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    The <a href=\"../..\">Herbie</a> developers are excited to announce\n    Herbie 1.4! This release continues a focus on speed and predictability.\n  </p>\n\n  <p>\n    Herbie automatically improves the accuracy of floating point\n    expressions. This avoids the bugs, errors, and surprises that so\n    often occur when working with floating point. Since\n    our <a href=\"../../papers.html\">PLDI'15 paper</a>, we've been hard\n    at work making Herbie more versatile and easier to use.\n  </p>\n\n  <img width=\"100%\" src=\"team.png\" style=\"display: block; margin: 4em 0; border-radius: 6px;\"\n       alt=\"The Herbie team, working over Zoom to bring you Herbie 1.4\" />\n\n  <h2>Major features of this release</h2>\n\n  <p><em>Faster simplification:</em> Herbie now uses\n    the <a href=\"https://github.com/mwillsey/egg\">Egg</a> library to\n    simplify expressions. Egg is roughly a hundred times faster than\n    Herbie's existing simplifier; Herbie with Egg is roughly twice as\n    fast overall. Egg is packaged for Windows, macOS, and Linux, so it\n    should be transparently usable on all platforms.\n  </p>\n\n  <p><em>Input search:</em> Herbie now uses interval arithmetic to\n  more efficiently sample valid inputs.\n  The \"<a href=\"faq.html#sample-valid-points\">Cannot sample enough\n  valid points</a>\" error message should now be rarer,\n    because Herbie should be much better at finding valid inputs,\n    whereever they are.\n  </p>\n  \n  <figure class=\"showcase\" style=\"background: white; border: 1px solid gray;\">\n    <img src=\"egg-graph.png\" style=\"display: block; width: 100%\"/>\n    <figcaption>Herbie 1.4 is substantially faster at simplifying\n    expressions than Herbie 1.3 and 1.2. With timeouts off, these two\n    releases have made simplification almost 4000× faster. Figure\n    from <a href=\"https://arxiv.org/abs/2004.03082\">our arXiv\n    submission</a>.</figcaption>\n  </figure>\n\n\n  <h2>Improvement to core algorithm</h2>\n  <ul>\n    <li>Simplification now uses\n    the <a href=\"https://github.com/mwillsey/egg\">Egg</a> library;\n    Herbie's existing e-graph library has been spun out as\n    <a href=\"https://pkgs.racket-lang.org/package/regraph\">regraph</a>,\n    which can be used by other Racket projects.</li>\n\n    <li>Herbie's input search pass now analyzes the input program and\n    its precondition and avoids sampling invalid inputs as much as\n    possible.</li>\n\n    <li>The interval arithmetic library has gained support\n    for <i>movability flags</i>, which allow Herbie to detect and skip\n    unsamplable input points.</li>\n\n    <li>The core program evaluator now operates in batch mode,\n    speeding Herbie when it generates thousands of program\n    candidates.</li>\n\n    <li>The interval arithmetic library has been spun out as \n    <a href=\"https://pkgs.racket-lang.org/package/rival\">rival</a>,\n    which other Racket projects can now use. Minor bugs in the\n    interval library have been fixed, and support has been extended to\n    more functions.</li>\n\n    <li>One form of exponential growth in the rewrite algorithm is\n    fixed by a cache, eliminating a common cause of timeouts.</li>\n\n    <li>Herbie's \"final simplify\" step no longer does constant\n    folding, eliminating a rare source of accuracy regression.</li>\n  </ul>\n\n  <h2>Usability improvements</h2>\n\n  <ul>\n    <li>Safari has been tested, and major bugs have been fixed.</li>\n\n    <li>The documentation is now a bit clearer and more\n    approachable.</li>\n\n    <li>Herbie now blames the correct variable when a precondition is\n    unsatisfiable.</li>\n\n    <li>The <code>:spec</code> property and <code>let*</code>\n    construct are now supported.</li>\n\n    <li>Herbie now tries a little hard to produce simpler expressions.\n    This change won't totally fix Herbie's weird output, but should\n    help a bit.</li>\n\n    <li>Herbie now aggregates profile information across a whole\n    report and presents it in an interactive, JavaScript-enabled form\n    on the \"Metrics\" page. This should help us keep speeding up\n    Herbie.</li>\n\n    <li>Some \"internal\" measures on the details page now show correct\n    data.</li>\n  </ul>\n\n  <h2>Code Cleanup</h2>\n\n  <ul>\n    <li>Several herbie dependencies have been spun out as libraries,\n    including the C and TeX translators\n    (<a href=\"https://pkgs.racket-lang.org/package/fpbench\">fpbench</a>),\n    the e-graph implementation\n    (<a href=\"https://pkgs.racket-lang.org/package/regraph\">regraph</a>),\n    and the interval library\n    (<a href=\"https://pkgs.racket-lang.org/package/rival\">rival</a>).\n    Other projects can now use these components.</li>\n\n    <li>Herbie's support for complex number arithmetic has been\n    extracted to a beta-quality\n    <a href=\"https://github.com/herbie-fp/complex-herbie\">external\n    library</a>. In the future we hope to provide a standard plugin\n    API not only for complex numbers but also vectors, matrices, and\n    other mathematical objects.</li>\n\n    <li>Herbie's support for multi- and mixed-precision operations\n    continues to improve, though there is more to do. We are targeting\n    Herbie 1.5 for this to be \"done\".</li>\n\n    <li>Many obsolete functions and data structures have been removed.\n    A new random-number algorithm means pre-1.4 seeds will produce\n    different results on Herbie 1.4.</li>\n\n    <li>The code base was reorganized to split the web code across\n    multiple files, with cleaner separation between\n    responsibilities.</li>\n\n    <li>Herbie now uses Github Actions, not Travis, as its continuous\n    integration service. This already means that single-precision and\n    posit support is better tested, and we hope to leverage Github\n    Actions more in the future.</li>\n  </ul>\n  \n  <h2>Try it out!</h2>\n\n  <p>\n    We're want Herbie to be more useful to scientists, engineers, and\n    programmers around the world. We've got a lot of features we're\n    excited to work on in the coming months. Please\n    <a href=\"https://github.com/uwplse/herbie/issues\">report bugs</a>,\n    join\n    <a href=\"https://mailman.cs.washington.edu/mailman/listinfo/herbie\">the\n    mailing list</a>,\n    or <a href=\"https://github.com/uw-plse/herbie\">contribute</a>.\n  </p>\n  \n  <p style=\"font-weight: bold; text-align: center;\">If you find Herbie\n  useful, <a href=\"mailto:herbie@cs.washington.edu\">let us know!</p>\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.4/report.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie reports</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Herbie reports</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  \n  <h1>The Herbie report</h1>\n\n  <p>When used <a href=\"using-web.html\">in the browser</a>, Herbie\n  generates HTML reports full of information about the accuracy of\n  your input and its output expressions.</p>\n\n  <h2 id=\"summary\">Summary numbers</h2>\n\n  <p>First, a brief summary of the results. For most uses, the\n    “Average Error” number, which describes how accurate the input and\n    output expressions are, is the most important statistic in this\n    section. The other numbers list time Herbie took to improve the\n    program and the <a href=\"input.html#precisions\">precision</a>\n    assumed for floating-point operations.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-large.png\" />\n    <figcaption>Summary numbers from a Herbie report. The \"binary64\"\n    precision refers to double-precision IEEE-754\n    arithmetic.</figcaption>\n  </figure>\n\n  <h2 id=\"programs\">Input and output programs</h2>\n\n  <p>Second, the input and output programs themselves, in standard\n  mathematical syntax. In the top-right corner, the drop-down can be\n  used to switch to C syntax or some other format.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-prog.png\" />\n    <figcaption>Input and output program from a Herbie report.</figcaption>\n  </figure>\n\n  <h2 id=\"graph\">Error graph</h2>\n\n  <p>\n    Third, under <em>Error</em>, a graph of floating-point error\n    versus input value. This is helpful for understanding the sorts of\n    inputs Herbie is improving accuracy on. Sometimes, Herbie improved\n    accuracy on some inputs at the cost of accuracy on other inputs\n    that you care more about. You can add\n    a <a href=\"input.html#preconditions\">precondition</a> to restrict\n    Herbie to certain inputs in those cases.\n  </p>\n\n  <p>\n    These graphs show the error of the input program with a red line,\n    and the error of the output program with a blue line. Both can be\n    toggled. If the expression has multiple variables, the variable\n    picker on the bottom left selects which variable is placed on the\n    horizontal axis. If Herbie decided to insert an <code>if</code>\n    statement into the program, the locations of those <code>if</code>\n    statements will be marked with vertical bars.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-error.png\" />\n    <figcaption>An error graph from a Herbie report. Note the variable\n    selector (<code>x</code> is selected) and the toggles for the\n    input and output program (both are toggled on).</figcaption>\n  </figure>\n\n  <h2 id=\"try-it\">Interactive inputs</h2>\n\n  <p>\n    Fourth, a interactive form where you can the output of both your\n    and Herbie's programs. on inputs of your choice Enter argument\n    values on the left, and the input and output programs will be\n    evaluated on those arguments and the results printed on the right.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-try-it.png\" />\n    <figcaption>\n      The interactive section of a Herbie report. \"In\" is your program,\n      \"Out\" is Herbie's.\n    </figcaption>\n  </figure>\n\n  <h2 id=\"derivation\">Derivation</h2>\n\n  <p>Fifth, Herbie's derivation of its output program. These can be\n    helpful in understanding how Herbie works. Each substantive step\n    in the derivation also lists the error, in bits, of that step's\n    output. Sometimes you can use that to pick a less-complex and\n    not-substantially-less-accurate program.</p>\n\n  <p>Derivations sometime name arithmetic laws used by Herbie, or they\n    might claim derivation steps are done by simplification, series\n    expansion, or other Herbie strategies. The derivation will also\n    call out any time the input is split into cases. When one part of\n    the program is colored blue, that is the part modified in that\n    derivation step.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-derivation.png\" />\n    <figcaption>A short derivation from a Herbie report. Note the\n    error, in gray, measured after each derivation step.</figcaption>\n  </figure>\n\n  <h2 id=\"reproduction\">Reproduction</h2>\n\n  <p>Sixth, a command to reproduce this Herbie result. If you find a\n  Herbie bug, include this code snippet when\n  <a href=\"https://github.com/uwplse/herbie/issues\">filing an\n  issue</a>.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-reproduce.png\" />\n    <figcaption>Reproduction information for a Herbie run. You can use\n    this when submitting bug reports.</figcaption>\n  </figure>\n\n  <h2 id=\"links\">Additional links</h2>\n  \n  <p>The top of the page has a right-hand menu bar with additional\n  links. “Report” returns you to Herbie's main page. “Log” and\n  “Metrics” give you detailed internal information about Herbie.</p>\n\n  <p>We expect the report to grow more informative with future\n  versions. Please <a href=\"mailto:herbie@cs.washington.edu\">get in\n  touch</a> if there is more information you'd like to see.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.4/toc.js",
    "content": "function make_toc() {\n    var headings = document.querySelectorAll(\"h2\");\n    var toc = document.createElement(\"nav\");\n    toc.classList.add(\"toc\")\n    var list = document.createElement(\"ul\");\n    for (var i = 0; i < headings.length; i++) {\n        var li = document.createElement(\"li\");\n        var a = document.createElement(\"a\");\n        var h = headings[i];\n        if (! h.id) {\n            h.setAttribute(\"id\", \"heading-\" + i);\n        }\n        a.setAttribute(\"href\", \"#\" + h.id);\n        a.innerHTML = h.innerHTML;\n        li.appendChild(a);\n        list.appendChild(li);\n    }\n    toc.appendChild(list);\n    headings[0].parentNode.insertBefore(toc, headings[0]);\n}\n\nwindow.addEventListener(\"load\", make_toc);\n"
  },
  {
    "path": "www/doc/1.4/tutorial.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Tutorial</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Herbie Tutorial</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> rewrites floating point expressions to\n      make them more accurate. Floating point arithmetic is\n      inaccurate; even 0.1 + 0.2 ≠ 0.3 for a computer. Herbie helps\n      find and fix these mysterious inaccuracies.\n  </p>\n\n  <p>\n    To get started, <a href=\"installing.html\">download and install</a>\n    Herbie. You're then ready to begin using Herbie.\n  </p>\n\n  <h2>Giving Herbie expressions</h2>\n\n  <p>Start Herbie with:</p>\n\n  <pre class=\"shell\">herbie web</pre>\n\n  <p>\n    After a brief wait, this will open your web browser and show you\n    Herbie's main window. The most important part of the page is this\n    bit:\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"web-input.png\" alt=\"The program input field in the Herbie web UI.\"/>\n  </figure>\n\n  <p>Type <kbd>(1 + x) - x</kbd> into this box and press enter. You\n  should see the entry box gray out, then some text appear on the\n  screen describing what Herbie is doing. After a few seconds, you'll\n  be redirected to a page with Herbie's results. The most important\n  part of that page is the large gray box in the middle:\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-prog.png\" alt=\"Input and output program from a Herbie report.\" />\n  </figure>\n\n  <p>\n    It shows the input, <code>(1 + x) - x</code>, and Herbie's more\n    accurate way to evaluate that expression: <code>1</code>. Herbie\n    did a good job, which you can see from the statistics at the top\n    of the page:\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-large.png\" alt=\"Statistics and error measures for this Herbie run.\" />\n  </figure>\n\n  <p>\n    The initial program had 29.4 bits of error (on average), while\n    Herbie's better version had 0 bits of error. That's because\n    <code>(1 + x) - x</code> should always be exactly equal\n    to <code>1</code>, but in floating-point arithmetic,\n    when <code>x</code> is really big, <code>1 + x</code> rounds down\n    to <code>x</code> and the expression returns <code>0</code>.\n  </p>\n\n  <p>\n    There's <a href=\"report.html\">lots more information</a> on this\n    results web page, which you can use explain more about the\n    expression's errors and how Herbie derived its result.\n  </p>\n\n  <h2>Programming with Herbie</h2>\n\n  <p>Now that you've run Herbie and know how to read its results,\n  let's apply Herbie to a realistic program.</p>\n\n  <p>\n    Herbie's input expressions can come from source code, mathematical\n    models, or even a debugging tool\n    like <a href=\"https://herbgrind.ucsd.edu\">Herbgrind</a>. But most\n    often, they come from your mind, while you're writing new\n    mathematical code.\n  </p>\n\n  <p>When you're writing a new numerical program, it's best to keep\n  Herbie open in a browser tab so you can run it easily. That way, you\n  can run Herbie on any complex floating-point expression and so\n  always use an accurate version of that expression. Herbie\n  has <a href=\"options.html\">options</a> to log all the expressions\n  you enter, so that you can refer to them later.</p>\n\n  <p>However, let's suppose you're instead tracking down a\n  floating-point bug in existing code. You'll need start by\n  identifying the problematic floating-point expression.</p>\n\n  <p>To demonstrate the workflow, let's walk through\n    <a href=\"https://github.com/josdejong/mathjs/pull/208\">bug 208</a>\n    in <a href=\"http://mathjs.org\">math.js</a>, an extensive math\n    library for JavaScript. The bug deals with an inaccuracy in the\n    implementation of square roots for complex numbers. (For a full\n    write-up of the bug itself, check out\n    a <a href=\"https://pavpanchekha.com/blog/casio-mathjs.html\">blog\n    post</a> by one of the Herbie authors.)\n  </p>\n\n  <h2>Finding the problematic expression</h2>\n\n  <p>\n    In most programs, there's a small core that does the mathematical\n    computations, while the rest of the program sets up parameters,\n    handles control flow, visualizes or print results, and so on. The\n    mathematical core is what Herbie will be interested in.\n  </p>\n\n  <p>\n    For our example, let's start\n    in <a href=\"https://github.com/josdejong/mathjs/tree/master/lib/function\"><code>lib/function/</code></a>.\n    This directory contains many subdirectories; each file in each\n    subdirectory defines a collection of mathematical functions. The\n    bug we're interested in is about complex square root, which is\n    defined in\n    <a href=\"https://github.com/josdejong/mathjs/blob/da306e26ed34272db44e35f07a3b015c0155d99a/lib/function/arithmetic/sqrt.js\"><code>arithmetic/sqrt.js</code></a>.\n  </p>\n\n  <p>\n    This file handles argument checks, five different number types,\n    and error handling, for both real and complex square roots. None\n    of that is of interest to Herbie; we want to extract just the\n    mathematical core. So skip down to the <code>isComplex(x)</code>\n    case:\n  </p>\n\n  <pre>var r = Math.sqrt(x.re * x.re + x.im * x.im);\nif (x.im &gt;= 0) {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}\nelse {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      -0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}</pre>\n\n  <p>This is the mathematical core that we want to send to Herbie.</p>\n\n  <h2>Converting problematic code to Herbie input</h2>\n\n  <p>\n    In this code, <code>x</code> is of type <code>Complex</code>, a\n    data structure with multiple fields. Herbie only deals with\n    floating-point numbers, not data structures, so we will treat the\n    input <code>x</code> as two separate inputs to\n    Herbie: <code>xre</code> and <code>xim</code>. We'll also pass\n    each field of the output to Herbie separately.\n  </p>\n\n  <p>\n    This code also branches between non-negative <code>x.im</code> and\n    negative <code>x.im</code>. It's usually better to send each\n    branch to Herbie separately. So in total this code turns into four\n    Herbie inputs: two output fields, for each of two branches.\n  </p>\n\n  <p>Let's focus on first field of the output for the case of\n  non-negative <code>x.im</code>.</p>\n\n  <p>The variable <code>r</code> is an intermediate variable in this\n  code block. Intermediate variables provide Herbie with crucial\n  information that Herbie can use to improve accuracy, so you want to\n  expand or inline them. The result looks like this:</p>\n\n  <pre>0.5 * sqrt(2.0 * (sqrt(xre * xre + xim * xim) + xre))</pre>\n\n  <p>Recall that this code is only run when <code>x.im</code> is\n  non-negative. So, before running Herbie on this expression, click\n  the “Additional options” link, and enter <kbd>xim &gt;= 0</kbd> for\n  the precondition. This asks Herbie to consider only non-negative\n  values of <code>xim</code> when improving the accuracy of this\n  expression.</p>\n  \n  <h2>Using Herbie's results</h2>\n\n  <p>Herbie will churn for a few seconds and produce an output,\n  perhaps something like this:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-prog2.png\" />\n    <figcaption>Herbie's version of the complex square root expression.</figcaption>\n  </figure>\n\n  <p>Herbie's algorithm is randomized, so you likely won't see the\n  exact same thing. For example, the branch expression <code>xre ≤\n  -4.780438341784697e-111</code> will probably have some other really\n  small number. And perhaps Herbie will choose slightly different\n  expressions. But the result should be recognizably similar. In this\n  case, Herbie reports that the initial expression had 38.7 bits of\n  error, and that the output has 29.4.</p>\n\n  <p>It's a little harder to describe what Herbie found wrong with the\n  original expression, and why its new version is better—it is due to\n  a floating-point phenomenon called “cancellation”. But you can get\n  some insight from the error plot just below the program block.\n  Select the <code>xim</code> variable just below the plot, and you\n  will see something like this:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-plot2.png\" />\n    <figcaption>Herbie's error plot for the complex square root expression.</figcaption>\n  </figure>\n\n  <p>There's a lot going on here. Along the horizontal axis, you have\n  the various values of <code>xim</code>. Note that the graph is\n  log-scale, and includes only non-negative values thanks to our\n  precondition. The value 1 is in the middle; to the left are values\n  with small exponents close to zero, and to the right you have values\n  with large exponents approaching infinity.</p>\n\n  <p>The vertical axis measures bits of error, from 0 to 64. Lower is\n  better. There are two lines drawn: a red one for your input and a\n  blue one for Herbie's output. You can see from the plot that\n  as <code>xim</code> gets smaller (toward the left, closer to zero),\n  Herbie's improvement becomes more and more significant. You can also\n  see that for very large values of <code>xim</code>, the original\n  program had maximal error (in fact, it overflows) but the replace\n  program is often better.</p>\n\n  <p>Of course, your exact output will differ a bit from the\n  screenshots and descriptions here, because Herbie is randomized.</p>\n\n  <p>Now that you have the more accurate version of this expression,\n    all you need to do is insert it back into the program:</p>\n\n  <pre>var r = Math.sqrt(x.re * x.re + x.im * x.im);\n// Herbie version of 0.5 * Math.sqrt(2.0 * (r + x.re))\nvar re;\nif (x.re &lt;= -4.780438341784697e-111) {\n    re = Math.abs(x.im) * Math.sqrt(0.5) / Math.sqrt(r - x.re);\n} else if (x.re &lt;= 1.857088496624289e-105) {\n    re = 0.5 * Math.sqrt(2.0 * (x.re + x.im));\n} else if (x.re &lt;= 117.16871373388169) {\n    re = 0.5 * Math.sqrt(2.0 * (r + x.re));\n} else if (x.re &lt;= 5.213930590364927e+88) {\n    re = 0.5 * Math.sqrt(2.0 * (x.re + x.im));\n} else {\n    re = 0.5 * Math.sqrt(2.0 * (x.re + x.re));\n}\nif (x.im &gt;= 0) {\n  return new Complex(\n      re,\n      0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}\nelse {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      -0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}</pre>\n\n  <p>Note that I've left the original code in place in a comment. As\n  Herbie gets better, you can re-run it on this original expression to\n  see if it comes up with improvements in accuracy.</p>\n\n  <p>By the way, for some languages, like C, you can use the drop-down\n  in the top-right corner of the gray program block to translate\n  Herbie's output to that language.</p>\n\n  <h2>Next steps</h2>\n\n  <p>With this change, we've made this part of the complex square root\n  function much more accurate, and we could repeat the same steps for\n  the other branches and other fields in this program. You now have a\n  pretty good understanding of Herbie and how to use it.\n  Please <a href=\"mailto:herbie@cs.washington.edu\">let us know</a> if\n  Herbie has helped you, and check out\n  the <a href=\"../../doc.html\">documentation</a> to learn more about\n  Herbie's various options and outputs.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.4/using-cli.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie from the Command Line</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Using Herbie from the Command Line</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>Herbie can be used from the command-line or\n  from <a href=\"using-web.html\">the browser</a>. This page covers\n  using Herbie from the command line.</p>\n\n  <h2 id=\"interactive\">The Herbie shell</h2>\n\n  <p>\n    The Herbie shell lets you interact with Herbie: you type in input\n    expressions and Herbie prints their more accurate versions. Run\n    the Herbie shell with this command:\n  </p>\n\n  <pre class=\"shell\">herbie shell\nHerbie 1.4 with seed 2098242187\nFind help on https://herbie.uwplse.org/, exit with Ctrl-D\n<strong>herbie&gt;</strong> </pre>\n\n\n  <p>\n    Herbie prints a seed, which you can <a href=\"options.html\">use to\n    reproduce</a> a Herbie run, and links you to documentation. Then,\n    it waits for inputs, which you can type directly into your\n    terminal in <a href=\"input.html\">FPCore format</a>:\n</p>\n\n  <pre><strong>herbie&gt;</strong> (FPCore (x) (- (+ 1 x) x))\n(FPCore\n  (x)\n  <var>...</var>\n  1.0)</pre>\n\n  <p>Herbie suggests that <code>1</code> is more accurate than the\n  original expression <code>(- (+ 1 x) x)</code>. The\n  the <var>...</var> elides \n  <a href=\"input.html#properties\">additional information</a> provided\n  by Herbie.</p>\n\n  <p>The Herbie shell makes it easy to play with different expressions\n  and try multiple variants, informed by Herbie's advice.</p>\n\n  <h2 id=\"batch\">Batch processing FPCores</h2>\n\n  <p>\n    Alternatively, you can run Herbie on a file with multiple\n    expressions in it, writing Herbie's versions of each to a file.\n    This mode is intended for use by scripts.\n  </p>\n\n  <pre class=\"shell\">herbie improve bench/tutorial.fpcore out.fpcore\nStarting Herbie on 3 problems (seed: 1809676410)...\n  1/3\t[   0.769s]   29→ 0\tCancel like terms\n  2/3\t[   1.392s]   39→ 0\tExpanding a square\n  3/3\t[   2.522s]    0→ 0\tCommute and associate</pre>\n\n  <p>\n    The output file <code>out.fpcore</code> contains more accurate\n    versions of each program:\n  </p>\n\n  <pre>;; seed: 1809676410\n\n(FPCore (x) <var>...</var> 1.0)\n(FPCore (x) <var>...</var> (* x (+ x 2.0)))\n(FPCore (x y z) <var>...</var> 0.0)</pre>\n\n  <p>\n    Note that output file is in the same order as the input file. For\n    more control over Herbie, see the documentation of\n    Herbie's <a href=\"options.html\">command-line options</a>.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.4/using-web.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie from the Browser</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Using Herbie from the Browser</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> rewrites floating point expressions to\n    make them more accurate. Herbie can be used\n    from <a href=\"using-cli.html\">the command-line</a> or from the\n    browser; this page is about using Herbie from the browser.</p>\n\n\n  <h2 id=\"interactive\">The Herbie web shell</h2>\n\n  <p>\n    The Herbie web shell lets you interact with Herbie through your\n    browser, featuring a convenient input format. The web shell is the\n    friendliest and easiest way to use Herbie. Run the Herbie web\n    shell with this command:\n  </p>\n\n  <pre class=\"shell\">herbie web</pre>\n\n  <p>After a few seconds, the web shell will rev up and direct your\n  browser to Herbie:</p>\n  \n  <pre class=\"shell\">herbie web\nHerbie 1.4 with seed 841489305\nFind help on https://herbie.uwplse.org/, exit with Ctrl-C\nYour Web application is running at http://localhost:8000/.\nStop this program at any time to terminate the Web Server.</pre>\n\n  <figure>\n    <img width=\"100%\" src=\"web-main.png\" alt=\"A screenshot of the Herbie web shell main page.\"/>\n  </figure>\n\n  <p>\n    Type expressions in standard mathematical syntax (parsed\n    by <a href=\"http://mathjs.org\">Math.js</a>) and\n    hit <kbd>Enter</kbd> to have Herbie attempt to improve them.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"web-progress.png\" />\n    <figcaption>Herbie shows improvement logs as it works.</figcaption>\n  </figure>\n\n  <p>\n    The web shell reports Herbie's progress and redirects to a\n    <a href=\"report.html\">report</a> once Herbie is done.\n  </p>\n\n  <p>\n    The web shell can also automatically save the generated reports,\n    and has <a href=\"options.html\">many other options</a> you might\n    want to explore.\n  </p>\n\n\n  <h2 id=\"batch\">Batch report generation</h2>\n\n  <p>A <a href=\"report.html\">report</a> can also be generated directly\n  from a file of <a href=\"input.html\">input expressions</a>:</p>\n  \n  <pre><strong>$</strong> herbie report input.fpcore output/\nStarting Herbie on 3 problems (seed: 1201949741)...\n  1/3\t[  22.014s]   39→ 0\tExpanding a square\n  2/3\t[   8.616s]    0→ 0\tCommute and associate\n  3/3\t[   1.715s]   29→ 0\tCancel like terms</pre>\n\n  <p>\n    This command asks Herbie to generate a report from the input\n    expressions in <code>input.fpcore</code> and to save the report in\n    the directory <code>output/</code>. It's best if that directory\n    doesn't exist before running this command.\n  </p>\n\n  <p>\n    Once generated, open <code>output/results.html</code> in your\n    favorite browser (but see <a href=\"faq.html\">the FAQ</a> if you're\n    using Chrome). That page summarizes Herbie's results for all\n    expression in your input file, and you can click on individual\n    expressions to see their report.\n  </p>\n\n  <p>Batch report generation is the most informative way to run Herbie\n  on a large collection of inputs. Like the web shell, it can be\n  customized through <a href=\"options.html\">command-line options</a>,\n  including parallelizing Herbie with multiple threads.</p>\n\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.5/diagrams.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Diagrams</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <script src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML\"></script>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Diagrams</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <figure>\n    <img width=\"100%\" src=\"system-1.5.png\" alt=\"System diagram of Herbie\" />\n  </figure>\n\n  <p>\n    High-level system diagram of Herbie. It highlights Herbie's core architecture,\n      external libraries, and user interactions.\n    Basic flow: Herbie passes user input (expression, precondition, etc.) to the\n      mainloop (scheduler) which alternates between generate and test phases multiple times,\n      maintaining and improving a set of accurate expressions at each iteration.\n    Once the generate-and-test phase is complete, Herbie extracts either\n      one or many output expressions using an algorithm called regime inference.\n      Regime inference chooses the \"best\" (usually most accurate)\n      generated candidate expression or combines multple candidates,\n      each \"best\" on a smaller part of the input range, with a branch condition.\n  </p>\n  \n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.5/docker.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie on Docker</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Installing with Docker</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> is available\n    through <a href=\"https://www.docker.com/\">Docker</a>, which is a\n    sort of like a virtual machine. This page describes how to install\n    the <a href=\"https://hub.docker.com/uwplse/herbie\">official Docker\n    image</a> for Herbie.\n  </p>\n  \n  <p>\n    Herbie can also be <a href=\"installing.html\">installed from\n    package or source</a>. Herbie via Docker is only recommended if\n    you already have Docker experience.\n  </p>\n  \n  <h2>Installing Herbie via Docker</h2>\n\n  <p>\n    First, <a href=\"https://docs.docker.com/installation/\">install\n    Docker</a>. Docker supports Windows, macOS, and Linux. Depending\n    on how you install Docker, you may need to prefix\n    the <code>docker</code> command with <code>sudo</code> or run them\n    as the administrative user.\n  </p>\n\n  <p>With Docker installed, download the Herbie image:</p>\n \n  <pre class=\"shell\">docker pull uwplse/herbie</pre>\n\n  <p>You can now run Herbie:</p>\n\n  <pre>docker run -it uwplse/herbie shell</pre>\n  \n  <p>This will run the <a href=\"using-cli.html\">Herbie shell</a>,\n  reading input from the standard input.</p>\n  \n  <p>Note that Herbie in Docker is more limited; for example, it will\n  not recognize plugins installed outside the Docker container.</p>\n\n  <h2>Running the web shell</h2>\n\n  <p>Running the web shell in Docker requires exposing the ports\n  inside the container. The Herbie Docker image binds to port 80 by\n  default; use the <code>-p &lt;hostport&gt;:80</code> option to\n  Docker to expose Herbie on whatever port you choose.\n  </p>\n\n  <pre class=\"shell\">docker run -it --rm -p 8000:80 uwplse/herbie</pre>\n\n  <p>\n    If you are using the <code>--log</code>\n    or <code>--save-session</code> flags for the web shell,\n    you will also need to mount the relevant directories into the\n    Docker container using the <code>-v</code> Docker option, as in\n    the examples below.\n  </p>\n\n  <h2>Generating files and reports</h2>\n\n  <p>\n    To use Herbie in <a href=\"using-cli.html\">batch mode</a>, you will\n    need to mount the input in the Docker container. Do that with:\n  </p>\n  \n  <pre class=\"shell\">docker run -it --rm \\\n    -v <var>in-dir</var>:/in \\\n    -v <var>out-dir</var>:/out \\\n    -u $USER \\\n    uwplse/herbie improve /in/<var>in-file</var> /out/<var>out-file</var></pre>\n\n  <p>\n    In this command, you are asking Herbie to read input\n    from <var>in-file</var> in <var>in-dir</var>, and write output\n    to <var>out-file</var> in <var>out-dir</var>. The command looks\n    the same if you want Herbie to read input from a directory;\n    just leave <var>in-file</var> blank.\n  </p>\n\n  <p>\n    To generate reports from Herbie, you can run:\n  </p>\n\n  <pre class=\"shell\">docker run -it --rm \\\n    -v <var>in-dir</var>:/in \\\n    -v <var>out-dir</var>:/out \\\n    -u $USER \\\n    uwplse/herbie report /in/<var>in-file</var> /out/</pre>\n\n  <p>\n    As before, the input and output directories must be mounted inside\n    the Docker container. Note that both here and above, the user is\n    set to the current user. This is to ensure that the files Herbie creates\n    have the correct permissions set.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.5/faq.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie FAQ</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Common Errors and Warnings</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p><a href=\"../../\">Herbie</a> automatically transforms floating\n  point expressions into more accurate forms. This page troubleshoots\n  common Herbie errors, warnings, and known issues.</p>\n\n\n  <h2>Common errors</h2>\n\n  <p>\n    Herbie error messages refer to this second for additional\n    information and debugging tips.\n  </p>\n\n  <h3 id=\"hangs\">Herbie hangs forever</h3>\n\n  <p>\n    Herbie 1.5 on Racket 8.0 through 8.2 sometimes hangs due to a bugs\n    in both Herbie and Racket. Please reinstall Herbie 1.5; we\n    re-released it with a fix for this bug.\n  </p>\n\n  <h3 id=\"invalid-syntax\">Invalid syntax</h3>\n\n  <p>\n    This error means you mis-formatted Herbie's input. Common errors\n    include misspelled function names and parenthesized expressions\n    that should not be parenthesized. For example, in\n    <code>(- (exp (x)) 1)</code>, the expression <code>x</code> is a\n    variable so shouldn't be parenthesized. <code>(- (exp x) 1)</code>\n    would be the correct way to write that expression.\n    The <a href=\"input.html\">input format</a> documentation has more\n    details on Herbie's syntax.\n  </p>\n\n  <h3 id=\"sample-valid-points\">Cannot sample enough valid points</h3>\n\n  <p>This error occurs when Herbie is unable to find enough valid\n  points. For example, the expression <code>(acos (+ 1000 x))</code>\n  is invalid unless <code>(&lt;= -1001 x -999)</code>, a rather narrow\n  range. The simplest fix is to increase\n  the <a href=\"options.html\"><code>--num-analysis</code> flag</a>.\n  Specifying the range of valid points as\n  a <a href=\"input.html#preconditions\">precondition</a> can also help.\n  </p>\n\n  <h3 id=\"no-valid-values\">No valid values</h3>\n\n  <p>This error indicates that your input has no valid inputs, usually\n  due to an overly restriction precondition. For example, the\n  precondition <code>(&lt 3 x 2)</code> excludes all inputs. The\n  solution is to fix the precondition or input program.</p>\n\n  <h3 id=\"mpfr-prec-limit\">Exceeded MPFR precision limit</h3>\n\n  <p>This rare error indicates that Herbie could not compute a \"ground\n  truth\" for your expression. For some expressions, like <code>(sin\n  (exp x))</code>, calculating a correct output for large input values\n  requires exponentially many bits. Herbie raises this error when more\n  than 10,000 bits are required.</p>\n\n\n  <h2>Common warnings</h2>\n\n  <p>Herbie warnings refer to this section for explanations and common\n  actions to take.</p>\n\n  <h3 id=\"ground-truth\">Could not determine a ground truth</h3>\n\n  <p>\n    Herbie raises this warning when some inputs require more than\n    10 000 bits to compute an exact ground truth. For example, to\n    compute <code>(/ (exp x) (exp x))</code> for very\n    large <code>x</code>, absurdly large exponents would be required.\n    Herbie discards such inputs and raises this warning. If you see\n    this warning, you should add a restrictive precondition, such\n    as <code>:pre (&lt; -100 x 100)</code>, to prevent large inputs.\n  </p>\n\n  <h3 id=\"deprecated-ops\">Operator <var>op</var> is deprecated</h3>\n\n  <p>\n    Herbie raises this warning when an operation is no longer supported.\n    Input expressions containing these operators may not be portable\n      across different platforms.\n    Consider creating a plugin to support them.\n  </p>\n\n  <h3 id=\"value-to-string\">Could uniquely print <var>val</var></h3>\n\n  <p>\n    Herbie will raise this warning when it needs more than 10,000 bits\n    to produce a string representation for a given value. This is\n    likely the result of a bug in a third-party plugin.\n  </p>\n\n  <h3 id=\"egg-herbie\">Falling back on regraph because egg-herbie package not installed</h3>\n\n  <p>\n    Herbie can use either the <code>egg-herbie</code>\n    or <code>regraph</code> package to simplify\n    expressions; <code>egg-herbie</code> is much faster, but uses\n    compiled binaries that cannot be installed on some systems. Herbie\n    will then fall back to <code>regraph</code>, and get similar\n    results but run roughly twice as long.\n    Install <code>egg-herbie</code> with <code>raco</code>.\n  </p>\n\n  <h3 id=\"unsound-rules\">Unsound rule application detected</h3>\n  \n  <p>\n    Herbie uses a set of algebraic rewrite rules in order to simplify expressions, but these\n    rules can sometimes lead to a contradiction.\n    Herbie will automatically compensate for this, and in most cases nothing needs to be done.\n    However, Herbie may have failed to simplify the output.\n  </p>\n\n\n  <h2>Known bugs</h2>\n\n  <p>Bugs that cannot be directly fixed are documented in this section.</p>\n\n  <h3>Missing reports chart on Chrome</h3>\n\n  <p>\n    When using Chrome to view web pages on your local machine, Herbie\n    reports cannot draw the arrow chart due to security restrictions.\n    <a href=\"http://www.chrome-allow-file-access-from-file.com/\">Run\n    Chrome with <code>--allow-file-access-from-files</code></a> to fix\n    this error.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.5/input.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Input Format</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>The Input Format</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> uses\n    the <a href=\"http://fpbench.org\">FPCore</a> format to specify an\n    input program, and has extensive options for precisely describing\n    its context.\n  </p>\n  \n  <h2 id=\"sec1\">General format</h2>\n\n  <p><a href=\"http://fpbench.org\">FPCore</a> format looks like this:</p>\n\n  <pre>(FPCore (<var>inputs ...</var>) <var>properties ...</var> <var>expression</var>)</pre>\n  <pre>(FPCore <var>name</var> (<var>inputs ...</var>) <var>properties ...</var> <var>expression</var>)</pre>\n\n  <p>\n    Each <var>input</var> is a variable name, like <code>x</code>,\n    used in the <var>expression</var>. Properties are used to specify\n    additional information about the <var>expression</var>'s context.\n    As of version 1.5, Herbie supports named functions.\n    If <var>name</var> is specified, the function can be inlined\n    within any subsequent FPCore in the file.\n  </p>\n\n  <p>\n    The expression is written in prefix form, with every function call\n    parenthesized, as in Lisp. For example, the formula for the\n    hypotenuse of a triangle with legs <i>a</i> and <i>b</i> is:\n  </p>\n\n  <pre>(FPCore (a b) (sqrt (+ (* a a) (* b b))))</pre>\n\n  <p>\n    The semicolon (<kbd>;</kbd>) character introduces a line comment.\n    We recommend the <code>.fpcore</code> file extension for Herbie input files.\n  </p>\n  \n  <h2>Supported functions</h2>\n  \n  <p>\n    Herbie supports all functions\n    from <a href=\"http://pubs.opengroup.org/onlinepubs/7908799/xsh/math.h.html\">math.h</a>\n    with floating-point-only inputs and outputs. The best supported\n    functions include:\n  </p>\n\n  <dl class=\"function-list\">\n    <dt><code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>, <code>fabs</code></dt>\n    <dd>The usual arithmetic functions</dd>\n    <dt><code>sqrt</code>, <code>cbrt</code></dt>\n    <dd>Square and cube roots</dd>\n    <dt><code>pow</code>, <code>exp</code>, <code>log</code></dt>\n    <dd>Various exponentiations and logarithms</dd>\n    <dt><code>sin</code>, <code>cos</code>, <code>tan</code></dt>\n    <dd>The trigonometric functions</dd>\n    <dt><code>asin</code>, <code>acos</code>, <code>atan</code>, <code>atan2</code></dt>\n    <dd>The inverse trigonometric functions</dd>\n    <dt><code>sinh</code>, <code>cosh</code>, <code>tanh</code></dt>\n    <dd>The hyperbolic functions</dd>\n    <dt><code>asinh</code>, <code>acosh</code>, <code>atanh</code></dt>\n    <dd>The inverse hyperbolic functions</dd>\n    <dt><code>fma</code>, <code>expm1</code>, <code>log1p</code>, <code>hypot</code></dt>\n    <dd>Specialized numeric functions</dd>\n  </dl>\n\n  <p>Herbie also supports the constants <code>PI</code>\n  and <code>E</code>. The arithmetic operators associate to the left,\n  and <code>-</code> is used for both subtraction and negation.</p>\n\n  <p>Herbie links against your computer's <code>libm</code> to\n  evaluate these functions. So, each function has the same behavior in\n  Herbie as in your code.</p>\n\n  <p>On Windows, the Bessel functions are not available in the\n  system <code>libm</code>, so Herbie will use a fallback\n  implementation and print a warning. Turn off the\n  the <kbd>precision:fallback</kbd> <a href=\"options.html\">option</a>\n  to disable those functions instead.</p>\n\n  <h2 id=\"conditionals\">Conditionals</h2>\n  \n  <p>FPCore uses <code>if</code> for conditional expressions:</p>\n\n  <pre>(if <var>cond</var> <var>if-true</var> <var>if-false</var>)</pre>\n\n  <p>\n    The conditional <code><var>cond</var></code> may use:\n  </p>\n  \n  <dl class=\"function-list\">\n    <dt><code>==</code>, <code>!=</code>, <code>&lt;</code>, <code>&gt;</code>, <code>&lt;=</code>, <code>&gt;=</code></dt>\n    <dd>The usual comparison operators</dd>\n    <dt><code>and</code>, <code>or</code>, <code>not</code></dt>\n    <dd>The usual logical operators</dd>\n    <dt><code>TRUE</code>, <code>FALSE</code></dt>\n    <dd>The two boolean values</dd>\n  </dl>\n\n  <p>The comparison functions implement chained comparisons with more than two arguments.</p>\n\n  <h2 id=\"intermediates\">Intermediate variables</h2>\n  \n  <p>Intermediate variables can be defined\n    using <code>let</code> and <code>let*</code>:</p>\n\n  <pre>(let ([<var>variable</var> <var>value</var>] <var>...</var>) <var>body</var>)</pre>\n\n  <p>In both <code>let</code> and <code>let*</code>,\n  each <var>variable</var> is bound to its <var>value</var> and can be\n  used in the <var>body</var>. The difference between <code>let</code>\n  and <code>let*</code> is what order the values are\n  evaluated in:</p>\n\n  <dl>\n    <dt><code>let</code> expressions</dt>\n    <dd>In a <code>let</code> expression, all the values are evaluated\n      in parallel, before they are bound to their variables. This\n      means that later values can't refer to earlier variables in the\n      same <code>let</code> block.</dd>\n\n    <dt><code>let*</code> expressions</dt>\n    <dd>A <code>let*</code> block looks the same as a <code>let</code>\n      block, except the values are evaluated one at a time, and later\n      values can refer to earlier variables.</dd>\n  </dl>\n\n  <p>Note that Herbie treats intermediate values only as a notational\n  convenience, and inlines their values before improving the formula's\n  accuracy. Using intermediate variables will not help Herbie improve\n  a formula's accuracy or speed up its run-time.</p>\n\n  <h2 id=\"preconditions\">Preconditions</h2>\n\n  <p>By default, the arguments to formulas are assumed to be\n  arbitrarily large or small floating-point numbers. However, in most\n  programs a smaller range of argument values is possible.\n  The <code>:pre</code> property (for “precondition”) describes this\n  smaller range.</p>\n\n  <p>Preconditions use comparison and boolean operators, just\n  like <a href=\"#conditionals\">conditional statements</a>:</p>\n\n  <pre>(FPCore (x) :pre (&lt; 1 x 10) (/ 1 (- x 1)))</pre>\n\n  <p>Herbie is particularly efficient when when the precondition is\n  an <code>and</code> of ranges for each variable, but more complex\n  preconditions also work.</p>\n\n  <h2 id=\"precisions\">Precisions</h2>\n\n  <p>Herbie supports both single- and double-precision values; you can\n  specify the precision with the <code>:precision</code> property:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>binary32</code></dt>\n    <dd>Single-precision IEEE-754 floating point</dd>\n    <dt><code>binary64</code></dt>\n    <dd>Double-precision IEEE-754 floating point</dd>\n  </dl>\n\n  <p>By default, <code>binary64</code> is assumed. Herbie also has\n  a <a href=\"plugins.html\">plugin system</a> to load additional\n  precisions.</p>\n\n  <h2 id=\"conversions\">Conversions</h2>\n\n  <p>Herbie supports conversions between different precisions.\n  All conversions are assumed to be bi-directional. You can\n  specify conversions with the <code>:herbie-conversions</code>\n  property.</p>\n\n  <dl class=\"function-list\">\n    <dt><code>:herbie-conversions<br/>([<var>prec1</var> <var>prec2</var>] ...)</code></dt>\n    <dd>If an expression is computed with precision <code>prec1</code>,\n    Herbie is allowed to rewrite all (or some) of the expression so it\n    is computed with precision <code>prec2</code>.</dd>\n  </dl>\n\n  <p>For example, to let Herbie introduce single-precision\n  code when <code>:precision</code> is set to <code>binary64</code> or vice versa,\n  specify <code>:herbie-conversions ((binary64 binary32))</code></p>\n\n  <h2 id=\"specs\">Specifications</h2>\n\n  <p>In some cases, your input program is an approximation of some\n  more complex mathematical expression. The <code>:spec</code> (for\n  “specification”) lets you specify the more complex ideal case.\n  Herbie will then try to modify the input program to make it more\n  accurately evaluate the specification.</p>\n\n  <p>For example, suppose you want to evaluate <code>sin(1/x)</code>\n  via a series expansion. Write:</p>\n\n  <pre>(FPCore (x)\n  :spec (sin (/ 1 x))\n  (+ (/ 1 x) (/ 1 (* 6 (pow x 3)))))</pre>\n\n  <p>Herbie will only use the <code>:spec</code> expression to\n  evaluate error, not to search for accurate expressions.</p>\n\n  <h2 id=\"properties\">Miscellaneous Properties</h2>\n\n  <p>Herbie uses the <code>:name</code> property to name FPCores in\n  its UI. Its value ought to be a string.</p>\n\n  <p>Herbie's output provide additional information in custom\n  properties:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>:herbie-status <var>status</var></code></dt>\n    <dd><var>status</var> describes whether Herbie worked: it is one\n    of <code>success</code>, <code>timeout</code>, <code>error</code>,\n    or <code>crash</code>.</dd>\n    <dt><code>:herbie-time <var>ms</var></code></dt>\n    <dd>The time, in milliseconds, used by Herbie to find a more accurate formula.</dd>\n    <dt><code>:herbie-error-input<br/>([<var>pts</var> <var>err</var>] ...)</code></dt>\n    <dd>The average <var>err</var>or of the input program at <var>pts</var> points. Multiple entries correspond to Herbie's training and test sets.</dd>\n    <dt><code>:herbie-error-output<br/>([<var>pts</var> <var>err</var>] ...)</code></dt>\n    <dd>The computed average error of the output program, similar to <code>:herbie-error-input</code>.</dd>\n  </dl>\n\n  <p>Herbie's benchmark suite also uses properties such\n  as <code>:herbie-target</code> for continuous integration, but these\n  are not supported and their use is discouraged.</p>\n  \n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.5/installing.html",
    "content": "<!doctype html>\n<html>\n\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Installing Herbie</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n\n<body>\n  <header>\n    <h1>Installing Herbie</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> supports Linux, macOS, and Windows. It\n    can be installed from a package or from source. To start, install\n    <a href=\"https://racket-lang.org\">Racket</a>, which Herbie is\n    written in. (Herbie is also available as\n    a <a href=\"docker.html\">Docker image</a>.)\n  </p>\n\n  <h2>Installing Racket</h2>\n\n  <p>\n    Install Racket either using\n    the <a href=\"http://download.racket-lang.org/racket-v8.1.html\">official\n    installer</a> or distro-provided packages. Versions as old as 8.0\n    are supported, but more recent versions are faster.\n  </p>\n\n  <p>\n    Test that Racket is installed correctly and has a correct version:\n  </p>\n\n  <pre class=\"shell\">racket\nWelcome to Racket v8.1 [cs].\n> (exit)</pre>\n\n<h2>Installing Herbie from source</h2>\n\n  <p>\n    Install Rust, using <a href=\"https://rustup.rs/\">rustup</a> or via some other means.\n    Versions as old as 1.46.0 are supported.\n    Also install Racket, version 8.0 or later, either using the\n    <a href=\"http://download.racket-lang.org/racket-v8.1.html\">official installer</a>\n    or distro-provided packages.\n  </p>\n  \n  <p>\n    Once Racket and Rust are installed, download the Herbie source\n  <a href=\"https://github.com/uwplse/herbie\">from GitHub</a> with:\n  </p>\n\n  <pre class=\"shell\">git clone https://github.com/uwplse/herbie</pre>\n\n  <p>\n    Change to the <code>herbie</code> directory;\n    you should see a <code>README.md</code> file, a directory named <code>src</code>,\n    a directory named <code>bench/</code>, and a few other directories.\n    Install Herbie on your system with:\n  </p>\n\n  <pre class=\"shell\">make install</pre>\n\n  <p>\n    This command installs Herbie and its dependencies, compiles it for\n    faster startup, and places the <code>herbie</code> executable in\n    your Racket user path (example paths for Racket 8.1):\n  </p>\n\n  <ul>\n    <li>On Windows, <code>AppData\\Roaming\\Racket\\8.1\\bin</code> in your user folder.</li>\n    <li>On macOS, <code>Library/Racket/8.1/bin</code> in your home folder.</li>\n    <li>On Linux, <code>.racket/8.1/bin</code> in your home directory.</li>\n  </ul>\n\n  <p>\n    You can run <code>herbie</code> from that directory, or add it to\n    your executable path. Once Herbie is installed and working\n    correctly, check out the <a href=\"tutorial.html\">tutorial</a>.\n  </p>\n\n  <h2>Installing Herbie from a package</h2>\n\n  <p>Once Racket is installed, install Herbie from a package with:</p>\n\n  <pre class=\"shell\">raco pkg install --auto herbie</pre>\n\n  <!-- This is a copy of the text above -->\n\n  <p>\n    This command installs Herbie and its dependencies, compiles it for\n    faster startup, and places the <code>herbie</code> executable in\n    your Racket user path:\n  </p>\n\n  <ul>\n    <li>On Windows, <code>AppData\\Roaming\\Racket\\8.1\\bin</code> in your user folder.</li>\n    <li>On macOS, <code>Library/Racket/8.1/bin</code> in your home folder.</li>\n    <li>On Linux, <code>.racket/8.1/bin</code> in your home directory.</li>\n  </ul>\n\n  <p>\n    You can run <code>herbie</code> from that directory, or add it to\n    your executable path. Once Herbie is installed and working\n    correctly, check out the <a href=\"tutorial.html\">tutorial</a>.\n  </p>\n\n  <!-- End of copy -->\n\n  <h2>Installing Herbie with Docker</h2>\n\n  <p>\n    <a href=\"https://docker.com\">Docker</a> is a container manager,\n    which is sort of like an easily-scriptable virtual machine. Herbie\n    in Docker is more limited; we do not recommend using Herbie\n    through Docker without prior Docker experience.\n  </p>\n\n  <p>\n    The <a href=\"docker.html\">Docker documentation</a> describes how\n    to install and run the official <code>uwplse/herbie</code> image.\n  </p>\n\n</body>\n\n</html>\n"
  },
  {
    "path": "www/doc/1.5/options.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Command-line Options</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Command-line Options</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>The <a href=\"../../\"><code>herbie</code></a> command has\n  subcommands and options that influence both its user interface and\n  the quality of its output.</p>\n\n  <h2>Herbie commands</h2>\n\n  <p>Herbie can be run both interactively and in batch mode, and can\n  generate output intended either for\n  the <a href=\"using-cli.html\">command line</a>\n  or <a href=\"using-web.html\">the web</a>. We call these different\n  ways of running Herbie different tools. Herbie provides four\n  tools:</p>\n\n  <dl>\n    <dt><code>herbie web</code></dt>\n    <dd>Use Herbie <a href=\"using-web.html\">through your browser</a>.\n    The <code>herbie web</code> command runs Herbie on your local\n    machine and opens your browser to its main page.</dd>\n\n    <dt><code>herbie shell</code></dt>\n    <dd>Use Herbie <a href=\"using-cli.html\">via a command-line shell</a>.\n    Enter an <a href=\"input.html\">FPCore expression</a> and Herbie\n    will print its more-accurate version.</dd>\n\n    <dt><code>herbie improve <var>input</var> <var>output</var></code></dt>\n    <dd>Run Herbie on the expressions in the file or\n    directory <var>input</var>. The results are written\n    to <var>output</var>, a single file in FPCore format.</dd>\n\n    <dt><code>herbie report <var>input</var> <var>output</var></code></dt>\n    <dd>Run Herbie on the expressions in the file or\n    directory <var>input</var>. The results are written\n    to <var>output</var>, a directory of\n    HTML <a href=\"report.html\">reports</a>. These pages can be viewed\n    in any browser (though with a <a href=\"faq.html\">quirk</a> for\n    Chrome).</dd>\n  </dl>\n\n  <p>We recommend using <code>web</code> and <code>report</code>,\n  which produce <a href=\"report.html\">reports</a> with lots of\n  information about floating-point accuracy, including graphs it of\n  error versus input values. This can help you understand whether\n  Herbie's improvements matter for your use case.</p>\n\n  <p>Use <code>herbie <var>tool</var> --help</code> to available\n  command-line options for a tool. This command also shows unsupported\n  options not listed on this page.</p>\n\n  <h2>General options</h2>\n\n  <p>\n    These options can be set on any tool. Pass them after the tool\n    name but before other arguments, like this:\n  </p>\n\n  <pre class=\"shell\">herbie report --timeout 60 in.fpcore out/</pre>\n\n  <p>Arguments cannot go before options.</p>\n\n  <dl>\n    <dt><code>--seed S</code></dt>\n    <dd>The random seed, which changes the randomly-selected points\n      that Herbie evaluates candidate expressions on. The seed is a\n      number between 0 and 2<sup>31</sup> (exclusive both ends). This\n      option can be used to make Herbie's results reproducible or to\n      compare two different runs. Seeds are not preserved across\n      runs.</dd>\n\n    <dt><code>--num-points N</code></dt>\n    <dd>The number of input points Herbie uses to evaluate candidate\n      expressions. The default, 256, is a good balance for most\n      programs. Increasing this option, say to 512 or 1024, will slow\n      Herbie down but may make its results more consistent.</dd>\n\n    <dt><code>--num-iters N</code></dt>\n    <dd>The number of times Herbie attempts to improve accuracy. The\n      default, 4, suffices for most programs and helps keep Herbie\n      fast; in practice iterations beyond the first few rarely lead to\n      lower error. Increase this option, say to 6, to check that there\n      aren't further improvements that Herbie could seek out.</dd>\n\n    <dt><code>--num-analysis N</code></dt>\n    <dd>The number of input subdivisions to use when searching for\n      valid input points. The default is 14. Increasing this option\n      will slow Herbie down, but may fix the\n      \"<a href=\"faq.html#sample-valid-points\">Cannot sample enough\n      valid points</a>\" error.\n    </dd>\n    \n    <dt><code>--timeout T</code></dt>\n    <dd>The timeout to use per-input, in seconds. A fractional number\n      of seconds can be given.</dd>\n\n    <dt><code>--threads N</code> (for the <code>improve</code> and <code>report</code> tools)</dt>\n    <dd>Enables multi-threaded operation. By default, no threads are\n      used. A number can be passed to this option to use that many\n      threads, or <code>yes</code> can be passed to tell Herbie to use\n      all of the hardware threads.</dd>\n\n    <dt><code>--pareto</code></dt>\n    <dd>Enables multi-objective improvement. Herbie will attempt to simultaneously\n    optimize for both accuracy and expression cost. Rather than generating\n    a single \"ideal\" output expression, Herbie will generate many output expressions.\n    This mode is still considered experimental. This <em>will</em> take a long time to run.\n    We recommend timeouts measured in hours.</dd>\n  </dl>\n\n  <h2>Web shell options</h2>\n  \n  <p>The <code>web</code> tool runs Herbie and connects to it from\n  your browser. It has options to control the underlying web\n  server.</p>\n  \n  <dl>\n    <dt><code>--port N</code></dt>\n    <dd>The port the Herbie server runs on. The default port is 8000.</dd>\n\n    <dt><code>--save-session dir</code></dt>\n    <dd>Save all the reports to this directory. The directory also\n    caches previously-computed expressions.</dd>\n\n    <dt><code>--log file</code></dt>\n    <dd>Write an access log to this file, formatted like an Apache\n    log. This log does <em>not</em> contain crash tracebacks.</dd>\n\n    <dt><code>--quiet</code></dt>\n    <dd>By default, but not when this option is set, a browser is\n    automatically started to show the Herbie page. This option also\n    shrinks the text printed on start up.</dd>\n\n    <dt><code>--public</code></dt>\n    <dd>When set, users on other computers can connect to the demo and\n    use it. (In other words, the server listens\n    on <code>0.0.0.0</code>.). Essential when Herbie is run\n    from <a href=\"docker.html\">Docker</a>.</dd>\n  </dl>\n\n  <h2>Rulesets</h2>\n\n  <p>\n    Herbie uses rewrite rules to change programs and improve accuracy.\n    The <code>--disable rules:<var>group</var></code>\n    and <code>--enable rules:<var>group</var></code> options turn rule\n    sets on and off. In general, turning a ruleset on makes Herbie\n    produce more accurate but more confusing programs.\n  </p>\n\n  <p>The full list of rule groups is:</p>\n\n  <table class=\"function-list\">\n    <thead><tr><th>Rule Group</th><th>Topic of rewrite rules</th></tr></thead>\n    <tr><td>arithmetic</td><td>Basic arithmetic facts</td></tr>\n    <tr><td>polynomials</td><td>Factoring and powers</td></tr>\n    <tr><td>fractions</td><td>Fraction arithmetic</td></tr>\n    <tr><td>exponents</td><td>Exponentiation identities</td></tr>\n    <tr><td>trigonometry</td><td>Trigonometric identities</td></tr>\n    <tr><td>hyperbolic</td><td>Hyperbolic trigonometric identities</td></tr>\n    <tr><td>bools</td><td>Boolean operator identities</td></tr>\n    <tr><td>branches</td><td><code>if</code> statement simplification</td></tr>\n    <tr><td>special</td><td>The gamma, Bessel, and error functions</td></tr>\n    <tr><td>numerics</td><td>Numerical compounds <code>expm1</code>, <code>log1p</code>, <code>fma</code>, and <code>hypot</code></td></tr>\n  </table>\n\n  <p>All groups except <code>numerics</code> are enabled by default.\n  We recommend turning <code>numerics</code> on if these functions are\n  available in your language.</p>\n\n  <h2>Search options</h2>\n\n  <p>\n    These options change the types of transformations that Herbie uses\n    to find candidate programs. We recommend sticking to the defaults.\n  </p>\n\n  <p>\n    Each option can be turned off with the <code>-o</code>\n    or <code>--disable</code> command-line flag and on with\n    <code>+o</code> or <code>--enable</code>. Turning an option off\n    typically results in less-accurate results, while turning a option\n    on typically results in more confusing output expressions.\n  </p>\n\n  <dl>\n    <dt><code>precision:fallback</code></dt>\n    <dd>This option, on by default, tells Herbie to use fallback\n    functions if a native implementation is not found for an operation\n    (and print a warning). If turned off, operations with no native\n    implementation will be disabled entirely. To our knowledge, this\n    option only affects the Bessel functions on Windows.</dd>\n\n    <dt><code>setup:simplify</code></dt>\n    <dd>This option, on by default, simplifies the expression before\n    passing it to Herbie. If turned off, Herbie will not simplify\n    input programs before improving them.</dd>\n\n    <dt><code>generate:rr</code></dt>\n    <dd>This option, on by default, uses Herbie's recursive rewriting\n    algorithm to generate candidate programs. If turned off, Herbie\n    will use a non-recursive rewriting algorithm, which will\n    substantially limit Herbie's creativity.</dd>\n\n    <dt><code>generate:taylor</code></dt>\n    <dd>This option, on by default, uses series expansion to produce\n    new candidates during the main improvement loop. If turned off,\n    Herbie will not use series expansion. Turn this option off if you\n    want to avoid series-expansion-based rewrites, such as if you need\n    to preserve the equivalence of the input and output expressions as\n    real-number formulas.</dd>\n\n    <dt><code>generate:simplify</code></dt>\n    <dd>This option, on by default, simplifies candidates during the\n    main improvement loop. If turned off, candidates will not be\n    simplified, which typically results in much less accurate\n    expressions.</dd>\n\n    <dt><code>reduce:regimes</code></dt>\n    <dd>This option, on by default, uses Herbie's regime inference\n    algorithm to branch between several program candidates. If turned\n    off, branches will not be inferred and the output program will be\n    straight-line code (if the input was). Turn this option off if\n    your programming environment makes branches very expensive, such\n    as on a GPU.</dd>\n\n    <dt><code>reduce:avg-error</code></dt>\n    <dd>This option, on by default, causes Herbie to output the\n    candidate with the best average error over the chosen inputs. If\n    turned off, Herbie will choose the candidate with the least\n    maximum error instead. This usually produces programs with worse\n    overall accuracy. Turn this option off if worst-case accuracy is\n    more important to you than overall accuracy.</dd>\n\n    <dt><code>reduce:binary-search</code></dt>\n    <dd>This option, on by default, uses binary search to refine the\n    values used in inferred branches. If turned off, different runs of\n    Herbie will be less consistent, and accuracy near branches will\n    suffer.</dd>\n\n    <dt><code>reduce:branch-expressions</code></dt>\n    <dd>This option, on by default, allows Herbie to branch on\n      expressions, not just variables. This slows Herbie down,\n      particularly for large programs. If turned off, Herbie will only\n      try to branch on variables.</dd>\n  </dl>\n\n  <h2>Upgrading from Herbie 1.0</h2>\n\n  <p>Herbie 1.0 used\n  a <a href=\"../1.0/using-herbie.html\">different</a> command line\n  syntax, without multiple tools. Translate like so:</p>\n\n  <ul>\n    <li><code>herbie-1.0</code> → <code>herbie-1.4 shell</code></li>\n    <li><code>herbie-1.0 file</code> → <code>herbie-1.4 improve file -</code></li>\n    <li><code>herbie-1.0 files ...</code> → <code>cat files ... | herbie-1.4 improve - -</code><br/>\n      Alternatively, collect the files into a directory and run <code>herbie-1.4 improve dir/ -</code></li>\n  </ul>\n\n  <p>The new syntax somewhat changes Herbie's behavior, such as by\n  using the input expression as the output if Herbie times out. It\n  also makes it easier to write Herbie's output to a file without\n  using command-line redirection.</p>\n\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.5/plugins.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Plugins</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Plugins</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p><a href=\"../../\">Herbie</a> plugins define new functions, add\n  rewrite rules, and even implement number representations.</p>\n\n  <p>Herbie plugins are installed separately. Herbie then\n  automatically loads and uses them.</p>\n  \n  <h2>Posit arithmetic</h2>\n\n  <p>The <kbd>softposit-herbie</kbd> plugin implements support\n  for <a href=\"https://posithub.org/\">posit</a> arithmetic. Install it\n  with:</p>\n\n  <pre class=\"shell\">raco pkg install --auto softposit-herbie</pre>\n\n  <p>This plugin uses the SoftPosit library, only supported on Linux.\n  Even then is reported to misbehave on some machines. The plugin\n  support arithmetic operations, <code>sqrt</code>, and quires.</p>\n\n  <p>Once <kbd>softposit-herbie</kbd> is installed,\n  specify <code>:precision posit16</code> to inform Herbie that it\n  should assume the core's inputs and outputs are posit numbers. Other\n  posit sizes (with 8 or 32 bits) and also quires (for 8, 16, and 32\n  bit posits) are available, but are poorly supported.</p>\n\n\n  <h2 id=\"complex\">Complex Numbers</h2>\n\n  <p>The <kbd>complex-herbie</kbd> plugin implements support for\n  complex numbers. Install it with:</p>\n\n  <pre class=\"shell\">raco pkg install --auto complex-herbie</pre>\n\n  <p>Herbie input parameters are always real numbers; complex\n  numbers must be constructed with <code>complex</code>. The\n  functions <code>re</code>, <code>im</code>, and <code>conj</code>\n  are available on complex numbers, along with the arithmetic\n  operators, <code>exp</code>, <code>log</code>, <code>pow</code>,\n  and <code>sqrt</code>. Complex and real operations use the same\n  syntax, but cannot be mixed: <code>(+ (complex 1 2) 1)</code> is not\n  valid. Herbie reports type errors in such situations.</p>\n\n  <p>Complex operations are implemented by\n  <a href=\"https://docs.racket-lang.org/reference/numbers.html#%28tech._complex._number%29\">Racket</a>,\n  so results may differ (slightly) from complex numbers in some other\n  language, especially for non-finite complex numbers. In the future,\n  we hope to support complex-number arguments and fully support all\n  complex-number operations.</p>\n\n  \n  <h2>Developing plugins</h2>\n\n  <p>The following is a guide to creating a Herbie plugin.\n  Plugins are considered experimental and may change considerably\n  between releases.\n  If you run into issues, please write to the\n  <a href=\"https://mailman.cs.washington.edu/mailman/listinfo/herbie\">\n  mailing list</a>.</p>\n\n  <p><b>First Steps</b><br>\n\n  All plugins are implemented as Racket packages. The easiest way to\n  initialize a new Racket package is to run\n\n  <pre class=\"shell\">raco pkg new <i>pkg-name</i></pre>\n\n  in a new folder. Make sure the folder name is the same as the package name!\n  This will initialize a Racket package with all the necessary files.\n  Read the official Racket documentation on the\n  <a href=\"https://docs.racket-lang.org/pkg/getting-started.html#%28part._how-to-create%29\">\n  raco</a> tool for more information.</p>\n\n  <p>A single entry needs to be added to the package manifest stored in <code>info.rkt</code>, and\n  Add the following line at the bottom of the file <code>(define herbie-plugin '<i>name</i>)</code>\n  where <i>name</i> is a unique symbol that doesn't conflict with other Herbie plugins.\n  As a suggestion, this should just be the package name.</p>\n\n  <p>Next, edit the <code>main.rkt</code> file by erasing everything except the\n  language specifier on the first line, and add the line <code>(require herbie/plugin)</code>.\n  This gives the package access to the Herbie plugin interface.\n  Optionally add the following for debugging purposes\n  <code>(eprintf \"Loading <i>pkg-name</i> support...\\n\")</code>.</p>\n\n  <p>Finally, run the following in the folder containing <code>info.rkt</code>\n  and <code>main.rkt</code>:\n\n  <pre class=\"shell\">raco pkg install</pre>\n\n  This should install your package and check for errors.\n  Now everything is set up!\n  Of course, your plugin is empty and doesn't add any useful features.\n  If you added the debugging line in <code>main.rkt</code>, you should see the string\n  when you run Herbie.\n  </p>\n\n  <p><b>Adding Features</b><br>\n  \n  Now that you have an empty plugin, you can begin adding new functions, rewrite\n  rules, and number representatons.\n  The procedures exported by the Herbie plugin interface can be roughly divided into\n  two categories: unique and parameterized.\n  Whether or not you use the unique or parameterized half of the interface\n  (or maybe both!) depends entirely on the number representation a feature is being\n  implemented for.\n  First, identify if your number representation is unique or parameterized.\n  For example, if you are adding features for <code>double</code> precision\n  (or rather <code>binary64</code>), the representation is unique.\n  If you are adding features for a generic floating point format, say\n  <code>(float <i>ebits</i> <i>nbits</i>)</code>, then the representation is parameterized.</p>\n\n  <p><b>Plugin Interface (Unique)</b><br>\n  The following are the signatures and descriptions of the\n  plugin procedures for unique representations.\n  These procedures should be called from the top-level of <code>main.rkt</code>\n  rather than inside a function.</p>\n\n  <dl>\n    <dt>\n      <code>(<b>define-type</b> <i>name</i> (<i>exact?</i> <i>inexact?</i>)\n                         <i>exact->inexact</i> <i>inexact->exact</i>)</code>\n    </dt>\n    <dd>Adds a new type with the unique identifier <code><i>name</i></code>.\n      The arguments <code><i>exact?</i></code> and <code><i>inexact?</i></code>\n      return true if a value is an exact or high-precision approximate representation.\n      For Herbie's <code>real</code> type, <code><i>exact?</i></code> is implemented\n      with <code>real?</code> and <code><i>inexact?</i></code> is implemented\n      with <code>bigfloat?</code>. The procedures <code><i>exact->inexact</i></code> and\n      <code><i>inexact->exact</i></code> convert between <code><i>exact?</i></code>\n      and <code><i>inexact?</i></code> values.\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-representation</b> (<i>name</i> <i>type</i> <i>repr?</i>)</td>\n                     <td><i>bigfloat->repr</i></td></tr>\n        <tr><td></td><td><i>repr->bigfloat</i></td></tr>\n        <tr><td></td><td><i>ordinal->repr</i></td></tr>\n        <tr><td></td><td><i>repr->ordinal</i></td></tr>\n        <tr><td></td><td><i>width</i></td></tr>\n        <tr><td></td><td><i>special?</i>)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Adds a new representation with the unique identifier <code><i>name</i></code>.\n      The representation will inherit all rewrite rules defined for <code><i>type</i></code>.\n      By default, Herbie defines two types: <code>real</code> and <code>bool</code>.\n      Your representation will most likely inherit from <code>real</code>.\n      The <code><i>width</i></code> argument should be the bitwidth of the representation,\n      e.g. 64 for <code>binary64</code>.\n      The argument <code><i>repr?</i></code> is a procedure that accepts any argument and returns\n      true if the argument is a value in the representation, e.g. an integer representation\n      should use Racket's <code>integer?</code>, while <code><i>special?</i></code> takes a\n      value in the representation and returns true if it is not finite, e.g. NaN or infinity.<br><br>\n\n      The other four arguments are single-argument procedures that implement different conversions.\n      The first two convert between a value in your representation and a Racket\n      <a href=\"https://docs.racket-lang.org/math/bigfloat.html\">bigfloat</a>\n      (you need to import <code>math/bigfloat</code>).\n      The last two convert between a value in your representation and its corresponding ordinal value.\n      Ordinal values for any representation must be within the interval [0, 2<sup><i>width</i></sup> - 1].\n      Check Racket's definition of\n      <a href=\"https://docs.racket-lang.org/math/flonum.html?q=ordinal#%28def._%28%28lib._math%2Fflonum..rkt%29._flonum-~3eordinal%29%29\">\n      ordinals</a> for floats.\n      Note that those ordinal values can be negative.\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-operator</b> (<i>name</i> <i>itypes ...</i>)</td><td> otype</td></tr>\n        <tr><td></td><td>[bf <i>bf-fn</i>]</td></tr>\n        <tr><td></td><td>[ival <i>ival-fn</i>]</td></tr>\n        <tr><td></td><td>[nonffi <i>nonffi-fn</i>]</td></tr>\n        <tr><td></td><td>...)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Adds a new operator. Operators describe pure mathematical functions,\n      i.e. <code>+</code> or <code>sin</code>.\n      The parameters <code><i>itypes</i></code> and <code><i>otype</i></code> are the input\n      type(s) and output type.\n      For example, <code>+</code> takes two <code>real</code> inputs and produces\n      one <code>real</code> output.\n      The <code><i>bf-fn</i></code> argument is the\n      <a href=\"https://docs.racket-lang.org/math/bigfloat.html\">bigfloat</a> implementation of your operator.\n      The <code><i>ival-fn</i></code> argument is the <a href=\"https://github.com/herbie-fp/rival\">Rival</a>\n      implementation of your operator. This is optional but improves the quality of Herbie's output.\n      If you don't want to implement this, set <code><i>ival-fn</i></code> to <code>false</code>.\n      The <code><i>nonffi-fn</i></code> argument is the exact implementation of your operator\n      (see <code>define-type</code> for a description of exact).\n      To define operators with an unknown number of arguments, e.g. comparators,\n      add the attribute <code>[itype <i>itype</i>]</code>.\n      This will override the input types defined by <code><i>itypes</i></code>.\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-operator-impl</b> (<i>op</i> <i>name</i> <i>ireprs ...</i>)</td><td><i>orepr</i></td></tr>\n        <tr><td></td><td>[fl <i>fl-fn</i>]</td></tr>\n        <tr><td></td><td>...)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Implements <code><i>op</i></code> with input representation(s) <code><i>ireprs</i></code>\n      and output representation <code><i>orepr</i></code>.\n      The field <code><i>name</i></code> must be unique.\n      For example, Herbie implements <code>+.f64</code> and <code>+.f32</code>\n      for double- and single-precision floats.\n      The argument <code><i>fl-fn</i></code> is the actual procedure that does the computation.\n      Like <code>define-operator</code>, the input representations can be\n      overridden with <code>[itype <i>irepr</i>]</code>.\n      By default, the attributes <code>bf</code>, <code>ival</code>, and <code>nonffi</code>\n      are inherited from <code><i>op</i></code> but can be overridden as previously\n      described.\n    </dd>\n\n    <dt><code>(<b>define-constant</b> <i>name</i> [bf <i>bf-thunk</i>] [ival <i>ival-thunk</i>])</code>\n    </dt>\n    <dd>Adds a new constant. Constants describe pure mathematical values.\n      i.e. <code>π</code> or <code>e</code>.\n      The <code><i>bf-fn</i></code> argument is a thunk that\n      returns the <a href=\"https://docs.racket-lang.org/math/bigfloat.html\">bigfloat</a>\n      value of the constant.\n      The <code><i>ival-fn</i></code> argument is a thunk\n      that returns the <a href=\"https://github.com/herbie-fp/rival\">Rival</a>\n      interval value of the constant.\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-constant-impl</b> (<i>const</i> <i>name</i>)</td><td><i>repr</i></td></tr>\n        <tr><td></td><td>[fl <i>fl-thunk</i>]</td></tr>\n        <tr><td></td><td>...)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Implements <code>const</code> for the representation <code><i>repr</i></code>.\n      The argument <code><i>fl-thunk</i></code> is a thunk that returns the approximate\n      value of the constant in the representation <code><i>repr</i></code>.\n      By default, the attributes <code>bf</code> and <code>ival</code> are inherited\n      from <code><i>const</i></code> but can be overridden (see <code>define-operator</code>\n      or <code>define-operator-impl</code> for overriding attributes).\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-ruleset</b> <i>name</i> (<i>groups ...</i>)</td>\n            <td>#:type ([<i>var</i> <i>repr</i>] ...)</td></tr>\n        <tr><td></td><td>[<i>rule-name</i> <i>match</i> <i>replace</i>]</td></tr>\n        <tr><td></td><td>...)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Defines a set of rewrite rules.\n      The <code><i>name</i></code> of the ruleset as well as each <code><i>rule-name</i></code>\n      must be a unique symbol.\n      Each ruleset must be marked with a set of <code><i>groups</i></code>\n      (read <a href=\"options.html#heading-3\">here</a> on ruleset groups).\n      Each rewrite rule takes the form <code>match ⇝ replace</code> where Herbie's rewriter\n      will replace <code>match</code> with <code>replace</code> (not vice-versa).\n      Each <code><i>match</i></code> and <code><i>replace</i></code> is an expression whose operators are\n      the names of operator implementations rather than pure mathematical operators.\n      Any variable must be listed in the type information with its associated representation.\n      See the <code>softposit-herbie</code> plugin for a more concrete example.\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-ruleset*</b> <i>name</i> (<i>groups ...</i>)</td>\n            <td>#:type ([<i>var</i> <i>type</i>] ...)</td></tr>\n        <tr><td></td><td>[<i>rule-name</i> <i>match</i> <i>replace</i>]</td></tr>\n        <tr><td></td><td>...)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Like <code>define-ruleset</code>, but it defines a ruleset for every representation that\n      inherits from <code><i>type</i></code>.\n      Currently, every <code><i>type</i></code> must be the same, e.g.\n      all <code>real</code>, for this procedure to function correctly.\n      Unlike <code>define-ruleset</code>, <code><i>match</i></code> and <code><i>replace</i></code>\n      contain the names of operators rather than operator implementations.\n    </dd>\n  </dl>\n\n  <p><b>Plugin Interface (Parameterized)</b><br>\n    Defining operators, constants, and representations for parameterized functions requires\n    a <i>generator</i> procedure for just-in-time loading of features for a particular\n    representation.\n    When Herbie encounters a representation it does not recognize (not explicitly defined\n    using <code>define-representation</code>) it queries a list of generators in case the\n    representation requires just-in-time loading.\n  </p>\n\n  <p>The following procedure handles generators:</p>\n\n  <dl>\n    <dt><code>(<b>register-generator!</b> gen)</code></dt>\n    <dd>Adds a generator procedure to Herbie's set of generators.\n      Generator procedures take the name of a representation and return whether\n      it successfully created the operators, constants, and rules associated\n      with a particular representation.\n      In the case that your plugin does not define the requested representation,\n      the generator procedure(s) need not do anything and should just return\n      <code>false</code>.\n    </dd>\n  </dl>\n\n  <p>\n    To actually add representations, operators, etc. within a generator procedure,\n    you must use a set of alternate procedures.\n  </p>\n\n  <dl>\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>register-representation!</b> </td><td> <i>name</i></td></tr>\n        <tr><td></td><td><i>type</i></td></tr>\n        <tr><td></td><td><i>repr?</i></td></tr>\n        <tr><td></td><td><i>bigfloat->repr</i></td></tr>\n        <tr><td></td><td><i>repr->bigfloat</i></td></tr>\n        <tr><td></td><td><i>ordinal->repr</i></td></tr>\n        <tr><td></td><td><i>repr->ordinal</i></td></tr>\n        <tr><td></td><td><i>width</i></td></tr>\n        <tr><td></td><td><i>special?</i>)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Like <code>define-representation</code>, but used within generators.</dd>\n\n    <dt>\n      <code>(<b>register-operator!</b> <i>op</i> <i>name</i> <i>itypes</i>\n        <i>otype</i> <i>attribs</i>)</code>\n    </dt>\n    <dd>Like <code>define-operator</code>, but used within generators.\n      The argument <code><i>itypes</i></code> is a list of the input types\n      while the argument <code><i>attribs</i></code> are the same attributes for\n      <code>define-operator</code>, e.g. <code>bf</code>.\n      In this case, <code><i>attribs</i></code> is an association:\n      <code>(list (cons 'bf <i>bf-fn</i>) ...)</code>.\n    </dd>\n\n    <dt>\n      <code>(<b>register-operator-impl!</b> <i>op</i> <i>name</i> <i>ireprs</i>\n        <i>orepr</i> <i>attribs</i>)</code>\n    </dt>\n    <dd>Like <code>define-operator-impl</code>, but used within generators.\n      See <code>register-operator!</code> for a description of <code><i>ireprs</i></code>\n      and <code><i>attribs</i></code>.\n    </dd>\n\n    <dt><code>(<b>register-constant!</b> <i>name</i> <i>attribs</i>)</code></dt>\n    <dd>Like <code>define-constant</code>, but used within generators.\n      The argument <code><i>attribs</i></code> are the same attributes for\n      <code>define-constant</code>.\n      In this case, <code><i>attribs</i></code> is an association:\n      <code>(list (cons 'bf <i>bf-thunk</i>) ...)</code>.\n    </dd>\n\n    <dt><code>(<b>register-constant-impl!</b> <i>const</i> <i>name</i> <i>type</i> <i>attribs</i>)</code></dt>\n    <dd>Like <code>define-constant-impl</code>, but used within generators.\n      See <code>register-constant!</code> for a description of <code><i>attribs</i></code>.\n    </dd>\n\n    <dt><code>(<b>register-ruleset!</b> <i>name</i> <i>groups</i> <i>var-reprs</i> <i>rules</i>)</code></dt>\n    <dd>Like <code>define-ruleset</code>, but used within generators.\n      In this case, <code><i>groups</i></code> is a list of rule groups;\n        <code><i>var-reprs</i></code> is an association\n        pairing each variable in the ruleset with its representation, e.g.\n        <code>(list (cons 'x '(float 5 16)) ...)</code>;\n        and <code><i>rules</i></code> is a list of rules of the following\n        form <code>(list (list <i>rule-name</i> <i>match</i> <i>replace</i>) ...)</code>.\n    </dd>\n\n  </dl>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.5/release-notes.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie 1.5 Release Notes</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <script src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML\"></script>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Herbie 1.5 Release Notes</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>The <a href=\"../..\">Herbie</a> developers are excited to announce\n  Herbie 1.5! This release focuses on multiple precisions, new syntax,\n  and higher accuracy. Our favorite features are below.</p>\n\n  <img width=\"100%\" src=\"team.png\" style=\"display: block; margin: 4em 0; border-radius: 6px;\"\n       alt=\"The Herbie team, working over Zoom to bring you Herbie 1.5\" />\n\n  <p><b>What is Herbie?</b> Herbie automatically improves the accuracy\n  of floating point expressions. This avoids the bugs, errors, and\n  surprises that so often occur with floating point arithmetic.</p>\n\n  <p><b>Join us!</b> Join the Herbie developers on the\n  <a href=\"https://fpbench.org\">FPBench</a> Slack, at the monthly\n  FPBench community meetings, and at\n  <a href=\"https://fpbench.org/talks/fptalks21.html\">FPTalks 2021</a>,\n  where <a href=\"https://bsaiki.com\">Brett</a> will be talking about\n  Herbie 1.5.</p>\n  \n  <figure class=\"showcase\">\n    <img src=\"pareto-screenshot.png\" style=\"width: 100%;\" />\n    <figcaption>A screenshot of Herbie with Pareto mode enabled.</figcaption>\n  </figure>\n\n  <h2>New Pareto mode</h2>\n\n  <p>Traditionally, Herbie has been all about giving you the most\n  accurate way possible to evaluate some mathematical expression.\n  But many of our users need to balance accuracy with speed.</p>\n  \n  <p>So Herbie 1.5 has an experimental new <a>pareto mode</a>. When\n  the pareto mode is turned on, Herbie produces multiple outputs\n  that trade off speed for accuracy. Run Herbie with <kbd>--pareto</kbd>\n  to try it out, and if you're interested in more details of how it works,\n  check out our paper at <a href=\"../../paper.html\">ARITH'21</a>.</p>\n\n  <figure class=\"showcase\">\n    <div class=\"program math\" style=\"text-align: center;\">\n      \\(\n      \\begin{array}{l}\n      [a, b] = \\mathsf{sort}([a, b]) \\\\\n      b \\cdot \\sqrt{\\frac{a}{b}\\cdot\\frac{a}{b} + 1}\n      \\end{array}\n      \\)\n    </div>\n    <figcaption>Herbie using sorting to improve accuracy.</figcaption>\n  </figure>\n\n  <h2>Symmetric expressions</h2>\n\n  <p>We've been working hard improving Herbie's results on its\n  traditional task: finding the most accurate way to evaluate\n  a mathematical expression. In Herbie 1.5, several improvements\n  landed, but the most exciting is the symmetric expressions mode.</p>\n\n  <p>Simply put, it's pretty common for Herbie to be asked to\n  improve the accuracy of an expression where reordering the variables\n  leaves the expression unchanged&mdash;something like\n  <code>log(exp(x) + exp(y))</code>.\n  Often the best way to evaluate that expression requires determining\n  which of <code>x</code> and <code>y</code> is larger.</p>\n\n  <p>With symmetric expressions, Herbie can detect when variable order\n  doesn't matter and sort the variables up front. That often lets\n  Herbie's other components find a clever way to improve accuracy.</p>\n\n  <figure class=\"showcase\">\n    <pre>\n(FPCore dist2 (x y)\n  (+ (* x x) (* y y)))\n\n(FPCore (x y)\n  (/ (sqrt (+ (dist2 x y) x)) (sqrt 2)))\n    </pre>\n    <figcaption>Using a function definition in FPCore. The first\n    FPCore block defines the <code>dist2</code> function, and the\n    second uses that definition. The result is shorter and more\n    readable.</figcaption>\n  </figure>\n\n  <h2>Function definitions</h2>\n\n  <p>While most people use Herbie via the web interface,\n  Herbie also supports the standard <a href=\"input.html\">FPCore</a>\n  format. FPCore offers more control over Herbie, and it's also\n  a good output format for other tools. In this release, we extended\n  Herbie to support function definitions.</p>\n\n  <p>In short, an FPCore can now include a function name between\n  the <code>FPCore</code> keyword and the list of variables. That core\n  can then be referenced by other cores in the same file. Herbie will\n  automatically expand those calls before improving the expression.</p>\n\n  <h2>Other improvements</h2>\n  <ul>\n    <li>Herbie now supports more pluggable number representations,\n    including arbitrary-precision floating-point numbers and also\n    fixed-point numbers. We're still working on better-exposing this\n    to users.</li>\n    <li>Herbie will now introduce some temporary variables to make its\n    output more readable.</li>\n    <li>The series expansion engine was substantially improved, which\n    both reduces timeouts and improves results substantially.</li>\n    <li>A new \"retirement community\" data structure allows Herbie to\n    consider more candidate programs, and thus produces better,\n    simpler results.</li>\n    <li>You can now give Herbie FPCore input in the web interface.</li>\n    <li>The Herbie timeline data structure (which powers \"Metrics\"\n    pages) has been dramatically improved, making it easier to add\n    more metrics in the future.</li>\n  </ul>\n\n  <h2>Deprecations and removals</h2>\n  <ul>\n    <li>Support for the Racket 7-series is deprecated and will be\n    removed in the next release. Please upgrade.</li>\n    <li>The <code>egg-herbie</code> support package has been merged\n    into Herbie proper. This means that if you want to install Herbie\n    from source, you will now need a Rust compiler.</li>\n    <li>Support for complex numbers has been deprecated and will be\n    removed in the next release.\n    Please <a href=\"mailto:herbie@cs.washington.edu\">let us know</a>\n    if you are using it. We hope to reimplement this eventually,\n    but with a better architecture.</li>\n    <li>The <kbd>precision:double</kbd> flag has been deprecated, and no\n    longer does anything. Use the <code>:precision</code> flag instead.</li>\n    <li>The <kbd>setup:early-exit</kbd> flag has been deprecated, and no\n    longer does anything. Herbie is fast enough now that it's not that\n    important any more!</li>\n  </ul>\n  \n  <h2>Try it out!</h2>\n\n  <p>\n    We want Herbie to be more useful to scientists, engineers, and\n    programmers around the world. We've got a lot of features we're\n    excited to work on in the coming months. Please\n    <a href=\"https://github.com/uwplse/herbie/issues\">report bugs</a>,\n    join\n    <a href=\"https://mailman.cs.washington.edu/mailman/listinfo/herbie\">the\n    mailing list</a>,\n    or <a href=\"https://github.com/uw-plse/herbie\">contribute</a>.\n  </p>\n  \n  <p style=\"font-weight: bold; text-align: center;\">If you find Herbie\n  useful, <a href=\"mailto:herbie@cs.washington.edu\">let us know!</p>\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.5/report.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie reports</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Herbie reports</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  \n  <h1>The Herbie report</h1>\n\n  <p>When used <a href=\"using-web.html\">in the browser</a>, Herbie\n  generates HTML reports full of information about the accuracy of\n  your input and its output expressions.</p>\n\n  <h2 id=\"summary\">Summary numbers</h2>\n\n  <p>First, a brief summary of the results. For most uses, the\n    “Average Error” number, which describes how accurate the input and\n    output expressions are, is the most important statistic in this\n    section. The other numbers list time Herbie took to improve the\n    program and the <a href=\"input.html#precisions\">precision</a>\n    assumed for floating-point operations.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-large.png\" />\n    <figcaption>Summary numbers from a Herbie report. The \"binary64\"\n    precision refers to double-precision IEEE-754\n    arithmetic.</figcaption>\n  </figure>\n\n  <h2 id=\"programs\">Input and output programs</h2>\n\n  <p>Second, the input and output programs themselves, in standard\n  mathematical syntax. In the top-right corner, the drop-down can be\n  used to switch to C syntax or some other format.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-prog.png\" />\n    <figcaption>Input and output program from a Herbie report.</figcaption>\n  </figure>\n\n  <h2 id=\"graph\">Error graph</h2>\n\n  <p>\n    Third, under <em>Error</em>, a graph of floating-point error\n    versus input value. This is helpful for understanding the sorts of\n    inputs Herbie is improving accuracy on. Sometimes, Herbie improved\n    accuracy on some inputs at the cost of accuracy on other inputs\n    that you care more about. You can add\n    a <a href=\"input.html#preconditions\">precondition</a> to restrict\n    Herbie to certain inputs in those cases.\n  </p>\n\n  <p>\n    These graphs show the error of the input program with a red line,\n    and the error of the output program with a blue line. Both can be\n    toggled. If the expression has multiple variables, the variable\n    picker on the bottom left selects which variable is placed on the\n    horizontal axis. If Herbie decided to insert an <code>if</code>\n    statement into the program, the locations of those <code>if</code>\n    statements will be marked with vertical bars.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-error.png\" />\n    <figcaption>An error graph from a Herbie report. Note the variable\n    selector (<code>x</code> is selected) and the toggles for the\n    input and output program (both are toggled on).</figcaption>\n  </figure>\n\n  <h2 id=\"try-it\">Interactive inputs</h2>\n\n  <p>\n    Fourth, a interactive form where you can the output of both your\n    and Herbie's programs. on inputs of your choice Enter argument\n    values on the left, and the input and output programs will be\n    evaluated on those arguments and the results printed on the right.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-try-it.png\" />\n    <figcaption>\n      The interactive section of a Herbie report. \"In\" is your program,\n      \"Out\" is Herbie's.\n    </figcaption>\n  </figure>\n\n  <h2 id=\"derivation\">Derivation</h2>\n\n  <p>Fifth, Herbie's derivation of its output program. These can be\n    helpful in understanding how Herbie works. Each substantive step\n    in the derivation also lists the error, in bits, of that step's\n    output. Sometimes you can use that to pick a less-complex and\n    not-substantially-less-accurate program.</p>\n\n  <p>Derivations sometime name arithmetic laws used by Herbie, or they\n    might claim derivation steps are done by simplification, series\n    expansion, or other Herbie strategies. The derivation will also\n    call out any time the input is split into cases. When one part of\n    the program is colored blue, that is the part modified in that\n    derivation step.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-derivation.png\" />\n    <figcaption>A short derivation from a Herbie report. Note the\n    error, in gray, measured after each derivation step.</figcaption>\n  </figure>\n\n  <h2 id=\"reproduction\">Reproduction</h2>\n\n  <p>Sixth, a command to reproduce this Herbie result. If you find a\n  Herbie bug, include this code snippet when\n  <a href=\"https://github.com/uwplse/herbie/issues\">filing an\n  issue</a>.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-reproduce.png\" />\n    <figcaption>Reproduction information for a Herbie run. You can use\n    this when submitting bug reports.</figcaption>\n  </figure>\n\n  <h2 id=\"links\">Additional links</h2>\n  \n  <p>The top of the page has a right-hand menu bar with additional\n  links. “Report” returns you to Herbie's main page. “Log” and\n  “Metrics” give you detailed internal information about Herbie.</p>\n\n  <p>We expect the report to grow more informative with future\n  versions. Please <a href=\"mailto:herbie@cs.washington.edu\">get in\n  touch</a> if there is more information you'd like to see.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.5/toc.js",
    "content": "function make_toc() {\n    var headings = document.querySelectorAll(\"h2\");\n    var toc = document.createElement(\"nav\");\n    toc.classList.add(\"toc\")\n    var list = document.createElement(\"ul\");\n    for (var i = 0; i < headings.length; i++) {\n        var li = document.createElement(\"li\");\n        var a = document.createElement(\"a\");\n        var h = headings[i];\n        if (! h.id) {\n            h.setAttribute(\"id\", \"heading-\" + i);\n        }\n        a.setAttribute(\"href\", \"#\" + h.id);\n        a.innerHTML = h.innerHTML;\n        li.appendChild(a);\n        list.appendChild(li);\n    }\n    toc.appendChild(list);\n    headings[0].parentNode.insertBefore(toc, headings[0]);\n}\n\nwindow.addEventListener(\"load\", make_toc);\n"
  },
  {
    "path": "www/doc/1.5/tutorial.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Tutorial</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Herbie Tutorial</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> rewrites floating point expressions to\n      make them more accurate. Floating point arithmetic is\n      inaccurate; even 0.1 + 0.2 ≠ 0.3 for a computer. Herbie helps\n      find and fix these mysterious inaccuracies.\n  </p>\n\n  <p>\n    To get started, <a href=\"installing.html\">download and install</a>\n    Herbie. You're then ready to begin using Herbie.\n  </p>\n\n  <h2>Giving Herbie expressions</h2>\n\n  <p>Start Herbie with:</p>\n\n  <pre class=\"shell\">herbie web</pre>\n\n  <p>\n    After a brief wait, this will open your web browser and show you\n    Herbie's main window. The most important part of the page is this\n    bit:\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"web-input.png\" alt=\"The program input field in the Herbie web UI.\"/>\n  </figure>\n\n  <p>Type <kbd>(1 + x) - x</kbd> into this box and press enter. You\n  should see the entry box gray out, then some text appear on the\n  screen describing what Herbie is doing. After a few seconds, you'll\n  be redirected to a page with Herbie's results. The most important\n  part of that page is the large gray box in the middle:\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-prog.png\" alt=\"Input and output program from a Herbie report.\" />\n  </figure>\n\n  <p>\n    It shows the input, <code>(1 + x) - x</code>, and Herbie's more\n    accurate way to evaluate that expression: <code>1</code>. Herbie\n    did a good job, which you can see from the statistics at the top\n    of the page:\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-large.png\" alt=\"Statistics and error measures for this Herbie run.\" />\n  </figure>\n\n  <p>\n    The initial program had 29.4 bits of error (on average), while\n    Herbie's better version had 0 bits of error. That's because\n    <code>(1 + x) - x</code> should always be exactly equal\n    to <code>1</code>, but in floating-point arithmetic,\n    when <code>x</code> is really big, <code>1 + x</code> rounds down\n    to <code>x</code> and the expression returns <code>0</code>.\n  </p>\n\n  <p>\n    There's <a href=\"report.html\">lots more information</a> on this\n    results web page, which you can use explain more about the\n    expression's errors and how Herbie derived its result.\n  </p>\n\n  <h2>Programming with Herbie</h2>\n\n  <p>Now that you've run Herbie and know how to read its results,\n  let's apply Herbie to a realistic program.</p>\n\n  <p>\n    Herbie's input expressions can come from source code, mathematical\n    models, or even a debugging tool\n    like <a href=\"https://herbgrind.ucsd.edu\">Herbgrind</a>. But most\n    often, they come from your mind, while you're writing new\n    mathematical code.\n  </p>\n\n  <p>When you're writing a new numerical program, it's best to keep\n  Herbie open in a browser tab so you can run it easily. That way, you\n  can run Herbie on any complex floating-point expression you're\n  coding up and so always use an accurate version of that expression.\n  Herbie has <a href=\"options.html\">options</a> to log all the\n  expressions you enter, so that you can refer to them later.</p>\n\n  <p>However, let's suppose you're instead tracking down a\n  floating-point bug in existing code. Then you'll need start by\n  identifying the problematic floating-point expression.</p>\n\n  <p>To demonstrate the workflow, let's walk through\n    <a href=\"https://github.com/josdejong/mathjs/pull/208\">bug 208</a>\n    in <a href=\"http://mathjs.org\">math.js</a>, a math library for\n    JavaScript. The bug deals with inaccurate square roots for complex\n    numbers. (For a full write-up of the bug itself, check out\n    a <a href=\"https://pavpanchekha.com/blog/casio-mathjs.html\">blog\n    post</a> by one of the Herbie authors.)\n  </p>\n\n  <h2>Finding the problematic expression</h2>\n\n  <p>\n    In most programs, there's a small core that does the mathematical\n    computations, while the rest of the program sets up parameters,\n    handles control flow, visualizes or print results, and so on. The\n    mathematical core is what Herbie will be interested in.\n  </p>\n\n  <p>\n    For our example, let's start\n    in <a href=\"https://github.com/josdejong/mathjs/tree/master/lib/function\"><code>lib/function/</code></a>.\n    This directory contains many subdirectories; each file in each\n    subdirectory defines a collection of mathematical functions. The\n    bug we're interested in is about complex square root, which is\n    defined in\n    <a href=\"https://github.com/josdejong/mathjs/blob/da306e26ed34272db44e35f07a3b015c0155d99a/lib/function/arithmetic/sqrt.js\"><code>arithmetic/sqrt.js</code></a>.\n  </p>\n\n  <p>\n    This file handles argument checks, five different number types,\n    and error handling, for both real and complex square roots. None\n    of that is of interest to Herbie; we want to extract just the\n    mathematical core. So skip down to the <code>isComplex(x)</code>\n    case:\n  </p>\n\n  <pre>var r = Math.sqrt(x.re * x.re + x.im * x.im);\nif (x.im &gt;= 0) {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}\nelse {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      -0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}</pre>\n\n  <p>This is the mathematical core that we want to send to Herbie.</p>\n\n  <h2>Converting problematic code to Herbie input</h2>\n\n  <p>\n    In this code, <code>x</code> is of type <code>Complex</code>, a\n    data structure with multiple fields. Herbie only deals with\n    floating-point numbers, not data structures, so we will treat the\n    input <code>x</code> as two separate inputs to\n    Herbie: <code>xre</code> and <code>xim</code>. We'll also pass\n    each field of the output to Herbie separately.\n  </p>\n\n  <p>\n    This code also branches between non-negative <code>x.im</code> and\n    negative <code>x.im</code>. It's usually better to send each\n    branch to Herbie separately. So in total this code turns into four\n    Herbie inputs: two output fields, for each of two branches.\n  </p>\n\n  <p>Let's focus on first field of the output for the case of\n  non-negative <code>x.im</code>.</p>\n\n  <p>The variable <code>r</code> is an intermediate variable in this\n  code block. Intermediate variables provide Herbie with crucial\n  information that Herbie can use to improve accuracy, so you want to\n  expand or inline them. The result looks like this:</p>\n\n  <pre>0.5 * sqrt(2.0 * (sqrt(xre * xre + xim * xim) + xre))</pre>\n\n  <p>Recall that this code is only run when <code>x.im</code> is\n  non-negative. So, before running Herbie on this expression, click\n  the “Additional options” link, and enter <kbd>xim &gt;= 0</kbd> for\n  the precondition. This asks Herbie to consider only non-negative\n  values of <code>xim</code> when improving the accuracy of this\n  expression.</p>\n  \n  <h2>Using Herbie's results</h2>\n\n  <p>Herbie will churn for a few seconds and produce an output,\n  perhaps something like this:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-prog2.png\" />\n    <figcaption>Herbie's version of the complex square root expression.</figcaption>\n  </figure>\n\n  <p>Herbie's algorithm is randomized, so you likely won't see the\n  exact same thing. For example, the branch expression <code>xre ≤\n  -4.780438341784697e-111</code> will probably have some other really\n  small number. And perhaps Herbie will choose slightly different\n  expressions. But the result should be recognizably similar. In this\n  case, Herbie reports that the initial expression had 38.7 bits of\n  error, and that the output has 29.4.</p>\n\n  <p>It's a little harder to describe what Herbie found wrong with the\n  original expression, and why its new version is better—it is due to\n  a floating-point phenomenon called “cancellation”. But you can get\n  some insight from the error plot just below the program block.\n  Select the <code>xim</code> variable just below the plot, and you\n  will see something like this:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-plot2.png\" />\n    <figcaption>Herbie's error plot for the complex square root expression.</figcaption>\n  </figure>\n\n  <p>There's a lot going on here. Along the horizontal axis, you have\n  the various values of <code>xim</code>. Note that the graph is\n  log-scale, and includes only non-negative values thanks to our\n  precondition. The value 1 is in the middle; to the left are values\n  with small exponents close to zero, and to the right you have values\n  with large exponents approaching infinity.</p>\n\n  <p>The vertical axis measures bits of error, from 0 to 64. Lower is\n  better. There are two lines drawn: a red one for the original\n  expression and a blue one for Herbie's version. You can see from the\n  plot that as <code>xim</code> gets smaller (toward the left, closer\n  to zero), Herbie's improvement becomes more and more significant.\n  You can also see that for very large values of <code>xim</code>, the\n  original program had maximal error (in fact, it overflows) but the\n  Herbie's version is better, though not great.</p>\n\n  <p>Of course, your exact output will differ a bit from the\n  screenshots and descriptions here, because Herbie is randomized.</p>\n\n  <p>Now that you have the more accurate version of this expression,\n    all you need to do is insert it back into the program:</p>\n\n  <pre>var r = Math.sqrt(x.re * x.re + x.im * x.im);\n// Herbie version of 0.5 * Math.sqrt(2.0 * (r + x.re))\nvar re;\nif (x.re &lt;= -4.780438341784697e-111) {\n    re = Math.abs(x.im) * Math.sqrt(0.5) / Math.sqrt(r - x.re);\n} else if (x.re &lt;= 1.857088496624289e-105) {\n    re = 0.5 * Math.sqrt(2.0 * (x.re + x.im));\n} else if (x.re &lt;= 117.16871373388169) {\n    re = 0.5 * Math.sqrt(2.0 * (r + x.re));\n} else if (x.re &lt;= 5.213930590364927e+88) {\n    re = 0.5 * Math.sqrt(2.0 * (x.re + x.im));\n} else {\n    re = 0.5 * Math.sqrt(2.0 * (x.re + x.re));\n}\nif (x.im &gt;= 0) {\n  return new Complex(\n      re,\n      0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}\nelse {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      -0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}</pre>\n\n  <p>Note that I've left the original code in place in a comment. As\n  Herbie gets better, you can re-run it on this original expression to\n  see if it comes up with improvements in accuracy.</p>\n\n  <p>By the way, for some languages, like C, you can use the drop-down\n  in the top-right corner of the gray program block to translate\n  Herbie's output to that language.</p>\n\n  <h2>Next steps</h2>\n\n  <p>With this change, we've made this part of the complex square root\n  function much more accurate, and we could repeat the same steps for\n  the other branches and other fields in this program. You now have a\n  pretty good understanding of Herbie and how to use it.\n  Please <a href=\"mailto:herbie@cs.washington.edu\">let us know</a> if\n  Herbie has helped you, and check out\n  the <a href=\"../../doc.html\">documentation</a> to learn more about\n  Herbie's various options and outputs.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.5/using-cli.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie from the Command Line</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Using Herbie from the Command Line</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>Herbie can be used from the command-line or\n  from <a href=\"using-web.html\">the browser</a>. This page covers\n  using Herbie from the command line.</p>\n\n  <h2 id=\"interactive\">The Herbie shell</h2>\n\n  <p>\n    The Herbie shell lets you interact with Herbie: you type in input\n    expressions and Herbie prints their more accurate versions. Run\n    the Herbie shell with this command:\n  </p>\n\n  <pre class=\"shell\">herbie shell\nHerbie 1.4 with seed 2098242187\nFind help on https://herbie.uwplse.org/, exit with Ctrl-D\n<strong>herbie&gt;</strong> </pre>\n\n\n  <p>\n    Herbie prints a seed, which you can <a href=\"options.html\">use to\n    reproduce</a> a Herbie run, and links you to documentation. Then,\n    it waits for inputs, which you can type directly into your\n    terminal in <a href=\"input.html\">FPCore format</a>:\n</p>\n\n  <pre><strong>herbie&gt;</strong> (FPCore (x) (- (+ 1 x) x))\n(FPCore\n  (x)\n  <var>...</var>\n  1.0)</pre>\n\n  <p>Herbie suggests that <code>1</code> is more accurate than the\n  original expression <code>(- (+ 1 x) x)</code>. The\n  the <var>...</var> elides \n  <a href=\"input.html#properties\">additional information</a> provided\n  by Herbie.</p>\n\n  <p>The Herbie shell makes it easy to play with different expressions\n  and try multiple variants, informed by Herbie's advice.</p>\n\n  <h2 id=\"batch\">Batch processing FPCores</h2>\n\n  <p>\n    Alternatively, you can run Herbie on a file with multiple\n    expressions in it, writing Herbie's versions of each to a file.\n    This mode is intended for use by scripts.\n  </p>\n\n  <pre class=\"shell\">herbie improve bench/tutorial.fpcore out.fpcore\nStarting Herbie on 3 problems (seed: 1809676410)...\n  1/3\t[   0.769s]   29→ 0\tCancel like terms\n  2/3\t[   1.392s]   39→ 0\tExpanding a square\n  3/3\t[   2.522s]    0→ 0\tCommute and associate</pre>\n\n  <p>\n    The output file <code>out.fpcore</code> contains more accurate\n    versions of each program:\n  </p>\n\n  <pre>;; seed: 1809676410\n\n(FPCore (x) <var>...</var> 1.0)\n(FPCore (x) <var>...</var> (* x (+ x 2.0)))\n(FPCore (x y z) <var>...</var> 0.0)</pre>\n\n  <p>\n    Note that output file is in the same order as the input file. For\n    more control over Herbie, see the documentation of\n    Herbie's <a href=\"options.html\">command-line options</a>.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.5/using-web.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie from the Browser</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Using Herbie from the Browser</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> rewrites floating point expressions to\n    make them more accurate. Herbie can be used\n    from <a href=\"using-cli.html\">the command-line</a> or from the\n    browser; this page is about using Herbie from the browser.</p>\n\n\n  <h2 id=\"interactive\">The Herbie web shell</h2>\n\n  <p>\n    The Herbie web shell lets you interact with Herbie through your\n    browser, featuring a convenient input format. The web shell is the\n    friendliest and easiest way to use Herbie. Run the Herbie web\n    shell with this command:\n  </p>\n\n  <pre class=\"shell\">herbie web</pre>\n\n  <p>After a few seconds, the web shell will rev up and direct your\n  browser to Herbie:</p>\n  \n  <pre class=\"shell\">herbie web\nHerbie 1.4 with seed 841489305\nFind help on https://herbie.uwplse.org/, exit with Ctrl-C\nYour Web application is running at http://localhost:8000/.\nStop this program at any time to terminate the Web Server.</pre>\n\n  <figure>\n    <img width=\"100%\" src=\"web-main.png\" alt=\"A screenshot of the Herbie web shell main page.\"/>\n  </figure>\n\n  <p>\n    Type expressions in standard mathematical syntax (parsed\n    by <a href=\"http://mathjs.org\">Math.js</a>) and\n    hit <kbd>Enter</kbd> to have Herbie attempt to improve them.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"web-progress.png\" />\n    <figcaption>Herbie shows improvement logs as it works.</figcaption>\n  </figure>\n\n  <p>\n    The web shell reports Herbie's progress and redirects to a\n    <a href=\"report.html\">report</a> once Herbie is done.\n  </p>\n\n  <p>\n    The web shell can also automatically save the generated reports,\n    and has <a href=\"options.html\">many other options</a> you might\n    want to explore.\n  </p>\n\n\n  <h2 id=\"batch\">Batch report generation</h2>\n\n  <p>A <a href=\"report.html\">report</a> can also be generated directly\n  from a file of <a href=\"input.html\">input expressions</a>:</p>\n  \n  <pre><strong>$</strong> herbie report input.fpcore output/\nStarting Herbie on 3 problems (seed: 1201949741)...\n  1/3\t[  22.014s]   39→ 0\tExpanding a square\n  2/3\t[   8.616s]    0→ 0\tCommute and associate\n  3/3\t[   1.715s]   29→ 0\tCancel like terms</pre>\n\n  <p>\n    This command asks Herbie to generate a report from the input\n    expressions in <code>input.fpcore</code> and to save the report in\n    the directory <code>output/</code>. It's best if that directory\n    doesn't exist before running this command.\n  </p>\n\n  <p>\n    Once generated, open <code>output/results.html</code> in your\n    favorite browser (but see <a href=\"faq.html\">the FAQ</a> if you're\n    using Chrome). That page summarizes Herbie's results for all\n    expression in your input file, and you can click on individual\n    expressions to see their report.\n  </p>\n\n  <p>Batch report generation is the most informative way to run Herbie\n  on a large collection of inputs. Like the web shell, it can be\n  customized through <a href=\"options.html\">command-line options</a>,\n  including parallelizing Herbie with multiple threads.</p>\n\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.6/diagrams.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Diagrams</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <script src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML\"></script>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Diagrams</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <figure>\n    <img width=\"100%\" src=\"system-1.6.png\" alt=\"System diagram of Herbie\" />\n  </figure>\n\n  <p>\n    High-level system diagram of Herbie. It highlights Herbie's core architecture,\n      external libraries, and user interactions.\n    Basic flow: Herbie passes user input (expression, precondition, etc.) to the\n      mainloop (scheduler) which alternates between generate and test phases multiple times,\n      maintaining and improving a set of accurate expressions at each iteration.\n    Once the generate-and-test phase is complete, Herbie extracts either\n      one or many output expressions using an algorithm called regime inference.\n    Regime inference chooses the \"best\" (usually most accurate)\n      generated candidate expression or combines multple candidates,\n      each \"best\" on a smaller part of the input range, with a branch condition.\n  </p>\n  \n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.6/docker.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie on Docker</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Installing with Docker</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> is available\n    through <a href=\"https://www.docker.com/\">Docker</a>, which is\n    sort of like a virtual machine. This page describes how to install\n    the <a href=\"https://hub.docker.com/r/uwplse/herbie\">official Docker\n    image</a> for Herbie.\n  </p>\n  \n  <p>\n    Herbie can also be <a href=\"installing.html\">installed from\n    package or source</a>. Herbie via Docker is only recommended if\n    you already have Docker experience.\n  </p>\n  \n  <h2>Installing Herbie via Docker</h2>\n\n  <p>\n    First, <a href=\"https://docs.docker.com/installation/\">install\n    Docker</a>. Docker supports Windows, macOS, and Linux. Depending\n    on how you install Docker, you may need to prefix\n    the <code>docker</code> commands with <code>sudo</code> or run them\n    as the administrative user.\n  </p>\n\n  <p>With Docker installed, you can run the <a href=\"using-cli.html\">Herbie \n    shell</a> with:</p>\n\n  <pre>docker run -it uwplse/herbie shell</pre>\n  \n  <p>This will read input from the standard input.</p>\n  \n  <p>Note that Herbie in Docker is more limited; for example, it will\n  not recognize plugins installed outside the Docker container.</p>\n\n  <h2>Running the web interface</h2>\n\n  <p>\n    You can run the Herbie web server locally with\n\n  <pre class=\"shell\">docker run -it --rm -p 8000:80 uwplse/herbie</pre>\n\n    and access the server at \n    <a href=\"http://localhost:8000\">http://localhost:8000</a>.\n    </p>\n    <p>\n      (Herbie's Docker image binds to port 80 by\n    default; this command uses the <code>-p &lt;hostport&gt;:80</code> \n    option to expose Herbie on port 8000.)\n  </p>\n\n  <p>\n    If you are using the <code>--log</code>\n    or <code>--save-session</code> flags for the web shell,\n    you will also need to mount the relevant directories into the\n    Docker container using the <code>-v</code> Docker option, as in\n    the examples below.\n  </p>\n\n  <h2>Generating files and reports</h2>\n\n  <p>\n    To use Herbie in <a href=\"using-cli.html\">batch mode</a>, you will\n    need to mount the input in the Docker container. Do that with:\n  </p>\n  \n  <pre class=\"shell\">docker run -it --rm \\\n    -v <var>in-dir</var>:/in \\\n    -v <var>out-dir</var>:/out \\\n    -u $USER \\\n    uwplse/herbie improve /in/<var>in-file</var> /out/<var>out-file</var></pre>\n\n  <p>\n    In this command, you are asking Herbie to read input\n    from <var>in-file</var> in <var>in-dir</var>, and write output\n    to <var>out-file</var> in <var>out-dir</var>. The command looks\n    the same if you want Herbie to read input from a directory;\n    just leave <var>in-file</var> blank.\n  </p>\n\n  <p>\n    To generate reports from Herbie, you can run:\n  </p>\n\n  <pre class=\"shell\">docker run -it --rm \\\n    -v <var>in-dir</var>:/in \\\n    -v <var>out-dir</var>:/out \\\n    -u $USER \\\n    uwplse/herbie report /in/<var>in-file</var> /out/</pre>\n\n  <p>\n    As before, the input and output directories must be mounted inside\n    the Docker container. Note that both here and above, the user is\n    set to the current user. This is to ensure that the files Herbie creates\n    have the correct permissions set.\n  </p>\n\n  <h2>For developers: using Docker</h2>\n  <h3>Updating the Docker image + Dockerfile</h3>\n\n  <p>\n    For building and testing, first clone the repo and confirm that Herbie \n    builds correctly with <code>make install</code>.\n  </p>\n  <p>\n    Next, examine the Dockerfile and Makefile together. The Dockerfile \n    syntax is described \n    <a href=\"https://docs.docker.com/engine/reference/builder/\">here</a>. \n    The Dockerfile should follow a process exactly like the Makefile, \n    except a clean initial environment is assumed. The build may be split \n    into 2 or more stages to limit the size of the resulting image. Each \n    stage consists of a <code>FROM</code> command and a series of further \n    commands to build up the desired environment, and later stages can \n    refer to earlier stages by name--for example, \n    <code>COPY --from=earlier-stage ...</code> can copy files compiled in \n    earlier images. You may need to do things like bumping the version of \n    Rust used for binary compilation or the version of Racket used in \n    production, or adjusting paths to match the newest version of the repo.\n  </p>\n    <p>\n    Once you are ready to build:\n    <pre class=\"shell\">docker build -t herbie-testbuild .</pre>\n    from the repo's main directory will build a new test image with the \n    tag <code>herbie-testbuild</code>. You can run this image with\n    <pre class=\"shell\">docker run -p 8000:80 -it herbie-testbuild</pre>\n    and see the web demo in the host machine's browser at \n    <a href=\"http://localhost:8000\">http://localhost:8000</a>.\n  </p>\n  \n  <p>\n  To open a shell in a running container for testing, first get the \n  container ID with\n  <pre class=\"shell\">docker ps</pre>\n  and then open a shell in the container as root with\n  <pre class=\"shell\">docker exec -it &lt;CONTAINER ID&gt; sh</pre>\n  \n  The code and egg-herbie binaries should be under <code>/src</code>.\n  </p>\n\n  <h3>\n    Deploying the image\n  </h3>\n  <p>\n    First, make sure you have access to the docker repo you would \n    like to push the image to (e.g. <code>uwplse/herbie</code>).\n  </p>\n  <p>\n    Then, give the image a name and a tag like this:\n    <pre class=\"shell\">docker tag herbie-testbuild uwplse/herbie:tagname</pre>\n    Once this is done, the tagged image can be pushed to the repo with\n    <pre class=\"shell\">docker push uwplse/herbie:tagname</pre>\n  </p>\n  <p>\n    If you are pushing a new version, make sure to also update the \n    <code>latest</code> tag:\n    <pre class=\"shell\">docker push uwplse/herbie:latest</pre>\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.6/faq.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie FAQ</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Common Errors and Warnings</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p><a href=\"../../\">Herbie</a> automatically transforms floating\n  point expressions into more accurate forms. This page troubleshoots\n  common Herbie errors, warnings, and known issues.</p>\n\n\n  <h2>Common errors</h2>\n\n  <p>\n    Herbie error messages refer to this second for additional\n    information and debugging tips.\n  </p>\n\n  <h3 id=\"invalid-syntax\">Invalid syntax</h3>\n\n  <p>\n    This error means you mis-formatted Herbie's input. Common errors\n    include misspelled function names and parenthesized expressions\n    that should not be parenthesized. For example, in\n    <code>(- (exp (x)) 1)</code>, the expression <code>x</code> is a\n    variable so shouldn't be parenthesized. <code>(- (exp x) 1)</code>\n    would be the correct way to write that expression.\n    The <a href=\"input.html\">input format</a> documentation has more\n    details on Herbie's syntax.\n  </p>\n\n  <h3 id=\"sample-valid-points\">Cannot sample enough valid points</h3>\n\n  <p>This error occurs when Herbie is unable to find enough valid\n  points. For example, the expression <code>(acos (+ 1000 x))</code>\n  is invalid unless <code>(&lt;= -1001 x -999)</code>, a rather narrow\n  range. The simplest fix is to increase\n  the <a href=\"options.html\"><code>--num-analysis</code> flag</a>.\n  Specifying the range of valid points as\n  a <a href=\"input.html#preconditions\">precondition</a> can also help.\n  </p>\n\n  <h3 id=\"no-valid-values\">No valid values</h3>\n\n  <p>This error indicates that your input has no valid inputs, usually\n  due to an overly restriction precondition. For example, the\n  precondition <code>(&lt 3 x 2)</code> excludes all inputs. The\n  solution is to fix the precondition or input program.</p>\n\n\n  <h2>Common warnings</h2>\n\n  <p>Herbie warnings refer to this section for explanations and common\n  actions to take.</p>\n\n  <h3 id=\"ground-truth\">Could not determine a ground truth</h3>\n\n  <p>\n    Herbie raises this warning when some inputs require more than\n    10,000 bits to compute an exact ground truth. For example, to\n    compute <code>(/ (exp x) (exp x))</code> for very\n    large <code>x</code>, absurdly large exponents would be required.\n    Herbie discards such inputs and raises this warning. If you see\n    this warning, you should add a restrictive precondition, such\n    as <code>:pre (&lt; -100 x 100)</code>, to prevent large inputs.\n  </p>\n\n  <h3 id=\"no-ival-operator\">Using unsound ground truth evaluation</h3>\n\n  <p>\n    Herbie's ground truth evaluation does not directly support the\n    Gamma and Bessel functions. Thus, any input containing these\n    operators triggers this warning and causes Herbie to fall back to\n    a slower and unsound ground truth evaluation strategy. There is\n    currently no workaround.\n  </p>\n\n  <h3 id=\"deprecated-ops\">Operator <var>op</var> is deprecated</h3>\n\n  <p>\n    Herbie raises this warning when an operation is no longer supported.\n    Input expressions containing these operators may not be portable\n      across different platforms.\n    Consider creating a plugin to support them.\n  </p>\n\n  <h3 id=\"value-to-string\">Could not uniquely print <var>val</var></h3>\n\n  <p>\n    Herbie will raise this warning when it needs more than 10,000 bits\n    to produce a string representation for a given value. This is\n    likely the result of a bug in a third-party plugin.\n  </p>\n\n  <h3 id=\"unsound-rules\">Unsound rule application detected</h3>\n  \n  <p>\n    Herbie uses a set of algebraic rewrite rules in order to simplify\n    expressions, but these rules can sometimes lead to a\n    contradiction. Herbie will automatically compensate for this, and\n    in most cases nothing needs to be done. However, Herbie may have\n    failed to simplify the output.\n  </p>\n\n  <h3 id=\"unused-variable\">Unused variable <var>var</var></h3>\n  \n  <p>\n    The input FPCore contains a variable that is not\n      used in the body expression.\n  </p>\n\n  <h3 id=\"strange-variable\">Strange variable <var>var</var></h3>\n  \n  <p>\n    The input expression contains a variable that is similar in name\n      to named constants, e.g. <var>e</var> instead of <var>E</var>.\n  </p>\n\n  <h2>Known bugs</h2>\n\n  <p>Bugs that cannot be directly fixed are documented in this section.</p>\n\n  <h3>Missing reports chart on Chrome</h3>\n\n  <p>\n    When using Chrome to view web pages on your local machine, Herbie\n    reports cannot draw the arrow chart due to security restrictions.\n    <a href=\"http://www.chrome-allow-file-access-from-file.com/\">Run\n    Chrome with <code>--allow-file-access-from-files</code></a> to fix\n    this error.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.6/input.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Input Format</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>The Input Format</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> uses\n    the <a href=\"http://fpbench.org\">FPCore</a> format to specify an\n    input program, and has extensive options for precisely describing\n    its context.\n  </p>\n  \n  <h2 id=\"sec1\">General format</h2>\n\n  <p><a href=\"http://fpbench.org\">FPCore</a> format looks like this:</p>\n\n  <pre>(FPCore (<var>inputs ...</var>) <var>properties ...</var> <var>expression</var>)</pre>\n  <pre>(FPCore <var>name</var> (<var>inputs ...</var>) <var>properties ...</var> <var>expression</var>)</pre>\n\n  <p>\n    Each <var>input</var> is a variable name, like <code>x</code>,\n    used in the <var>expression</var>. Properties are used to specify\n    additional information about the <var>expression</var>'s context.\n    As of version 1.5, Herbie supports named functions.\n    If <var>name</var> is specified, the function can be inlined\n    within any subsequent FPCore in the file.\n  </p>\n\n  <p>\n    The expression is written in prefix form, with every function call\n    parenthesized, as in Lisp. For example, the formula for the\n    hypotenuse of a triangle with legs <i>a</i> and <i>b</i> is:\n  </p>\n\n  <pre>(FPCore (a b) (sqrt (+ (* a a) (* b b))))</pre>\n\n  <p>\n    The semicolon (<kbd>;</kbd>) character introduces a line comment.\n    We recommend the <code>.fpcore</code> file extension for Herbie input files.\n  </p>\n  \n  <h2>Supported functions</h2>\n  \n  <p>\n    Herbie supports all functions\n    from <a href=\"http://pubs.opengroup.org/onlinepubs/7908799/xsh/math.h.html\">math.h</a>\n    with floating-point-only inputs and outputs. The best supported\n    functions include:\n  </p>\n\n  <dl class=\"function-list\">\n    <dt><code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>, <code>fabs</code></dt>\n    <dd>The usual arithmetic functions</dd>\n    <dt><code>sqrt</code>, <code>cbrt</code></dt>\n    <dd>Square and cube roots</dd>\n    <dt><code>pow</code>, <code>exp</code>, <code>log</code></dt>\n    <dd>Various exponentiations and logarithms</dd>\n    <dt><code>sin</code>, <code>cos</code>, <code>tan</code></dt>\n    <dd>The trigonometric functions</dd>\n    <dt><code>asin</code>, <code>acos</code>, <code>atan</code>, <code>atan2</code></dt>\n    <dd>The inverse trigonometric functions</dd>\n    <dt><code>sinh</code>, <code>cosh</code>, <code>tanh</code></dt>\n    <dd>The hyperbolic functions</dd>\n    <dt><code>asinh</code>, <code>acosh</code>, <code>atanh</code></dt>\n    <dd>The inverse hyperbolic functions</dd>\n    <dt><code>fma</code>, <code>expm1</code>, <code>log1p</code>, <code>hypot</code></dt>\n    <dd>Specialized numeric functions</dd>\n  </dl>\n\n  <p>Herbie also supports the constants <code>PI</code>\n  and <code>E</code>. The arithmetic operators associate to the left,\n  and <code>-</code> is used for both subtraction and negation.</p>\n\n  <p>Herbie links against your computer's <code>libm</code> to\n  evaluate these functions. So, each function has the same behavior in\n  Herbie as in your code.</p>\n\n  <p>On Windows, the Bessel functions are not available in the\n  system <code>libm</code>, so Herbie will use a fallback\n  implementation and print a warning. Turn off the\n  the <kbd>precision:fallback</kbd> <a href=\"options.html\">option</a>\n  to disable those functions instead.</p>\n\n  <h2 id=\"conditionals\">Conditionals</h2>\n  \n  <p>FPCore uses <code>if</code> for conditional expressions:</p>\n\n  <pre>(if <var>cond</var> <var>if-true</var> <var>if-false</var>)</pre>\n\n  <p>\n    The conditional <code><var>cond</var></code> may use:\n  </p>\n  \n  <dl class=\"function-list\">\n    <dt><code>==</code>, <code>!=</code>, <code>&lt;</code>, <code>&gt;</code>, <code>&lt;=</code>, <code>&gt;=</code></dt>\n    <dd>The usual comparison operators</dd>\n    <dt><code>and</code>, <code>or</code>, <code>not</code></dt>\n    <dd>The usual logical operators</dd>\n    <dt><code>TRUE</code>, <code>FALSE</code></dt>\n    <dd>The two boolean values</dd>\n  </dl>\n\n  <p>The comparison functions implement chained comparisons with more than two arguments.</p>\n\n  <h2 id=\"intermediates\">Intermediate variables</h2>\n  \n  <p>Intermediate variables can be defined\n    using <code>let</code> and <code>let*</code>:</p>\n\n  <pre>(let ([<var>variable</var> <var>value</var>] <var>...</var>) <var>body</var>)</pre>\n\n  <p>In both <code>let</code> and <code>let*</code>,\n  each <var>variable</var> is bound to its <var>value</var> and can be\n  used in the <var>body</var>. The difference between <code>let</code>\n  and <code>let*</code> is what order the values are\n  evaluated in:</p>\n\n  <dl>\n    <dt><code>let</code> expressions</dt>\n    <dd>In a <code>let</code> expression, all the values are evaluated\n      in parallel, before they are bound to their variables. This\n      means that later values can't refer to earlier variables in the\n      same <code>let</code> block.</dd>\n\n    <dt><code>let*</code> expressions</dt>\n    <dd>A <code>let*</code> block looks the same as a <code>let</code>\n      block, except the values are evaluated one at a time, and later\n      values can refer to earlier variables.</dd>\n  </dl>\n\n  <p>Note that Herbie treats intermediate values only as a notational\n  convenience, and inlines their values before improving the formula's\n  accuracy. Using intermediate variables will not help Herbie improve\n  a formula's accuracy or speed up its run-time.</p>\n\n  <h2 id=\"preconditions\">Preconditions</h2>\n\n  <p>By default, the arguments to formulas are assumed to be\n  arbitrarily large or small floating-point numbers. However, in most\n  programs a smaller range of argument values is possible.\n  The <code>:pre</code> property (for “precondition”) describes this\n  smaller range.</p>\n\n  <p>Preconditions use comparison and boolean operators, just\n  like <a href=\"#conditionals\">conditional statements</a>:</p>\n\n  <pre>(FPCore (x) :pre (&lt; 1 x 10) (/ 1 (- x 1)))</pre>\n\n  <p>Herbie is particularly efficient when when the precondition is\n  an <code>and</code> of ranges for each variable, but more complex\n  preconditions also work.</p>\n\n  <h2 id=\"precisions\">Precisions</h2>\n\n  <p>Herbie supports both single- and double-precision values; you can\n  specify the precision with the <code>:precision</code> property:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>binary32</code></dt>\n    <dd>Single-precision IEEE-754 floating point</dd>\n    <dt><code>binary64</code></dt>\n    <dd>Double-precision IEEE-754 floating point</dd>\n    <dt><code>racket</code></dt>\n    <dd>Like <code>binary64</code>, but using Racket math functions\n      rather than your computer's <code>libm</code>.</dd>\n  </dl>\n\n  <p>By default, <code>binary64</code> is assumed. Herbie also has\n  a <a href=\"plugins.html\">plugin system</a> to load additional\n  precisions.</p>\n\n  <h2 id=\"conversions\">Conversions</h2>\n\n  <p>Herbie supports conversions between different precisions.\n  All conversions are assumed to be bi-directional. You can\n  specify conversions with the <code>:herbie-conversions</code>\n  property.</p>\n\n  <dl class=\"function-list\">\n    <dt><code>:herbie-conversions<br/>([<var>prec1</var> <var>prec2</var>] ...)</code></dt>\n    <dd>If an expression is computed with precision <code>prec1</code>,\n    Herbie is allowed to rewrite all (or some) of the expression so it\n    is computed with precision <code>prec2</code> and vice versa.</dd>\n  </dl>\n\n  <p>For example, to let Herbie introduce single-precision\n  code when <code>:precision</code> is set to <code>binary64</code> or vice versa,\n  specify <code>:herbie-conversions ((binary64 binary32))</code></p>\n\n  <h2 id=\"specs\">Specifications</h2>\n\n  <p>In some cases, your input program is an approximation of some\n  more complex mathematical expression. The <code>:spec</code> (for\n  “specification”) lets you specify the more complex ideal case.\n  Herbie will then try to modify the input program to make it more\n  accurately evaluate the specification.</p>\n\n  <p>For example, suppose you want to evaluate <code>sin(1/x)</code>\n  via a series expansion. Write:</p>\n\n  <pre>(FPCore (x)\n  :spec (sin (/ 1 x))\n  (+ (/ 1 x) (/ 1 (* 6 (pow x 3)))))</pre>\n\n  <p>Herbie will only use the <code>:spec</code> expression to\n  evaluate error, not to search for accurate expressions.</p>\n\n  <h2 id=\"properties\">Miscellaneous Properties</h2>\n\n  <p>Herbie uses the <code>:name</code> property to name FPCores in\n  its UI. Its value ought to be a string.</p>\n\n  <p>Herbie's output provide additional information in custom\n  properties:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>:herbie-status <var>status</var></code></dt>\n    <dd><var>status</var> describes whether Herbie worked: it is one\n    of <code>success</code>, <code>timeout</code>, <code>error</code>,\n    or <code>crash</code>.</dd>\n    <dt><code>:herbie-time <var>ms</var></code></dt>\n    <dd>The time, in milliseconds, used by Herbie to find a more accurate formula.</dd>\n    <dt><code>:herbie-error-input<br/>([<var>pts</var> <var>err</var>] ...)</code></dt>\n    <dd>The average <var>err</var>or of the input program at <var>pts</var> points. Multiple entries correspond to Herbie's training and test sets.</dd>\n    <dt><code>:herbie-error-output<br/>([<var>pts</var> <var>err</var>] ...)</code></dt>\n    <dd>The computed average error of the output program, similar to <code>:herbie-error-input</code>.</dd>\n  </dl>\n\n  <p>Herbie's benchmark suite also uses properties such\n  as <code>:herbie-target</code> for continuous integration, but these\n  are not supported and their use is discouraged.</p>\n  \n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.6/installing.html",
    "content": "<!doctype html>\n<html>\n\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Installing Herbie</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n\n<body>\n  <header>\n    <h1>Installing Herbie</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> supports Linux, macOS, and Windows. It\n    can be installed from a package or from source. To start, install\n    <a href=\"https://racket-lang.org\">Racket</a>, which Herbie is\n    written in. Install <a href=\"https://www.rust-lang.org/\">Rust</a>\n    when building from source. (Herbie is also available as\n    a <a href=\"docker.html\">Docker image</a>.)\n  </p>\n\n  <h2>Installing Racket</h2>\n\n  <p>\n    Install Racket either using\n    the <a href=\"http://download.racket-lang.org/racket-v8.5.html\">official\n    installer</a> or distro-provided packages. Versions as old as 8.0\n    are supported, but more recent versions are faster.\n  </p>\n\n  <p>\n    Test that Racket is installed correctly and has a correct version:\n  </p>\n\n  <pre class=\"shell\">racket\nWelcome to Racket v8.5 [cs].\n> (exit)</pre>\n\n<h2>Installing Herbie from source</h2>\n\n  <p>\n    Install Rust, using <a href=\"https://rustup.rs/\">rustup</a> or via some other means.\n    Versions as old as 1.60.0 are supported.\n    This installation method supports Windows, macOS, and Linux for various architectures.\n  </p>\n    \n  <p>\n    Once Racket and Rust are installed, download the Herbie source\n    <a href=\"https://github.com/uwplse/herbie\">from GitHub</a> with:\n  </p>\n\n  <pre class=\"shell\">git clone https://github.com/uwplse/herbie</pre>\n\n  <p>\n    Change to the <code>herbie</code> directory;\n    you should see a <code>README.md</code> file, a directory named <code>src</code>,\n    a directory named <code>bench/</code>, and a few other directories.\n    Install Herbie on your system with:\n  </p>\n\n  <pre class=\"shell\">make install</pre>\n\n  <p>\n    This command installs Herbie and its dependencies, compiles it for\n    faster startup, and places the <code>herbie</code> executable in\n    your Racket user path (example paths for Racket 8.5):\n  </p>\n\n  <ul>\n    <li>On Windows, <code>AppData\\Roaming\\Racket\\8.5\\bin</code> in your user folder.</li>\n    <li>On macOS, <code>Library/Racket/8.5/bin</code> in your home folder.</li>\n    <li>On Linux, <code>.local/share/racket/8.5/bin</code> in your home directory.</li>\n  </ul>\n\n  <p>\n    You can run <code>herbie</code> from that directory, or add it to\n    your executable path. Once Herbie is installed and working\n    correctly, check out the <a href=\"tutorial.html\">tutorial</a>.\n  </p>\n\n  <h2>Installing Herbie from a package</h2>\n\n  <p>\n    This installation method supports Windows, macOS, and Linux for x86-64.\n    This method of installation will fail for Apple M1 systems and other ARM architectures.\n    Once Racket is installed, install Herbie from a package with:\n  </p>\n\n  <pre class=\"shell\">raco pkg install --auto herbie</pre>  \n\n  <!-- This is a copy of the text above -->\n\n  <p>\n    This command installs Herbie and its dependencies, compiles it for\n    faster startup, and places the <code>herbie</code> executable in\n    your Racket user path (example paths for Racket 8.1):\n  </p>\n\n  <ul>\n    <li>On Windows, <code>AppData\\Roaming\\Racket\\8.5\\bin</code> in your user folder.</li>\n    <li>On macOS, <code>Library/Racket/8.5/bin</code> in your home folder.</li>\n    <li>On Linux, <code>.local/share/racket/8.5/bin</code> in your home directory.</li>\n  </ul>\n\n  <p>\n    You can run <code>herbie</code> from that directory, or add it to\n    your executable path. Once Herbie is installed and working\n    correctly, check out the <a href=\"tutorial.html\">tutorial</a>.\n  </p>\n\n  <!-- End of copy -->\n\n  <h2>Installing Herbie with Docker</h2>\n\n  <p>\n    <a href=\"https://docker.com\">Docker</a> is a container manager,\n    which is sort of like an easily-scriptable virtual machine. Herbie\n    in Docker is more limited; we do not recommend using Herbie\n    through Docker without prior Docker experience.\n  </p>\n\n  <p>\n    The <a href=\"docker.html\">Docker documentation</a> describes how\n    to install and run the official <code>uwplse/herbie</code> image.\n  </p>\n\n</body>\n\n</html>\n"
  },
  {
    "path": "www/doc/1.6/options.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Command-line Options</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Command-line Options</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>The <a href=\"../../\"><code>herbie</code></a> command has\n  subcommands and options that influence both its user interface and\n  the quality of its output.</p>\n\n  <h2>Herbie commands</h2>\n\n  <p>Herbie can be run both interactively and in batch mode, and can\n  generate output intended either for\n  the <a href=\"using-cli.html\">command line</a>\n  or <a href=\"using-web.html\">the web</a>. We call these different\n  ways of running Herbie different tools. Herbie provides four\n  tools:</p>\n\n  <dl>\n    <dt><code>herbie web</code></dt>\n    <dd>Use Herbie <a href=\"using-web.html\">through your browser</a>.\n    The <code>herbie web</code> command runs Herbie on your local\n    machine and opens your browser to its main page.</dd>\n\n    <dt><code>herbie shell</code></dt>\n    <dd>Use Herbie <a href=\"using-cli.html\">via a command-line shell</a>.\n    Enter an <a href=\"input.html\">FPCore expression</a> and Herbie\n    will print its more-accurate version.</dd>\n\n    <dt><code>herbie improve <var>input</var> <var>output</var></code></dt>\n    <dd>Run Herbie on the expressions in the file or\n    directory <var>input</var>. The results are written\n    to <var>output</var>, a single file in FPCore format.</dd>\n\n    <dt><code>herbie report <var>input</var> <var>output</var></code></dt>\n    <dd>Run Herbie on the expressions in the file or\n    directory <var>input</var>. The results are written\n    to <var>output</var>, a directory of\n    HTML <a href=\"report.html\">reports</a>. These pages can be viewed\n    in any browser (though with a <a href=\"faq.html\">quirk</a> for\n    Chrome).</dd>\n  </dl>\n\n  <p>We recommend using <code>web</code> and <code>report</code>,\n  which produce <a href=\"report.html\">reports</a> with lots of\n  information about floating-point accuracy, including graphs it of\n  error versus input values. This can help you understand whether\n  Herbie's improvements matter for your use case.</p>\n\n  <p>Use <code>herbie <var>tool</var> --help</code> to available\n  command-line options for a tool. This command also shows unsupported\n  options not listed on this page.</p>\n\n  <h2>General options</h2>\n\n  <p>\n    These options can be set on any tool. Pass them after the tool\n    name but before other arguments, like this:\n  </p>\n\n  <pre class=\"shell\">herbie report --timeout 60 in.fpcore out/</pre>\n\n  <p>Arguments cannot go before options.</p>\n\n  <dl>\n    <dt><code>--seed S</code></dt>\n    <dd>The random seed, which changes the randomly-selected points\n      that Herbie evaluates candidate expressions on. The seed is a\n      number between 0 and 2<sup>31</sup> (exclusive both ends). This\n      option can be used to make Herbie's results reproducible or to\n      compare two different runs. Seeds are not preserved across\n      runs.</dd>\n\n    <dt><code>--num-points N</code></dt>\n    <dd>The number of input points Herbie uses to evaluate candidate\n      expressions. The default, 256, is a good balance for most\n      programs. Increasing this option, say to 512 or 1024, will slow\n      Herbie down but may make its results more consistent.</dd>\n\n    <dt><code>--num-iters N</code></dt>\n    <dd>The number of times Herbie attempts to improve accuracy. The\n      default, 4, suffices for most programs and helps keep Herbie\n      fast; in practice iterations beyond the first few rarely lead to\n      lower error. Increase this option, say to 6, to check that there\n      aren't further improvements that Herbie could seek out.</dd>\n\n    <dt><code>--num-analysis N</code></dt>\n    <dd>The number of input subdivisions to use when searching for\n      valid input points. The default is 14. Increasing this option\n      will slow Herbie down, but may fix the\n      \"<a href=\"faq.html#sample-valid-points\">Cannot sample enough\n      valid points</a>\" error.\n    </dd>\n    \n    <dt><code>--timeout T</code></dt>\n    <dd>The timeout to use per-input, in seconds. A fractional number\n      of seconds can be given.</dd>\n\n    <dt><code>--threads N</code> (for the <code>improve</code> and <code>report</code> tools)</dt>\n    <dd>Enables multi-threaded operation. By default, no threads are\n      used. A number can be passed to this option to use that many\n      threads, or <code>yes</code> can be passed to tell Herbie to use\n      all of the hardware threads.</dd>\n\n    <dt><code>--pareto</code></dt>\n    <dd>Enables multi-objective improvement. Herbie will attempt to simultaneously\n    optimize for both accuracy and expression cost. Rather than generating\n    a single \"ideal\" output expression, Herbie will generate many output expressions.\n    This mode is still considered experimental. With this option, Herbie will\n    take a <em>long</em> time to run. We recommend timeouts measured in hours.</dd>\n  </dl>\n\n  <h2>Web shell options</h2>\n  \n  <p>The <code>web</code> tool runs Herbie and connects to it from\n  your browser. It has options to control the underlying web\n  server.</p>\n  \n  <dl>\n    <dt><code>--port N</code></dt>\n    <dd>The port the Herbie server runs on. The default port is 8000.</dd>\n\n    <dt><code>--save-session dir</code></dt>\n    <dd>Save all the reports to this directory. The directory also\n    caches previously-computed expressions.</dd>\n\n    <dt><code>--log file</code></dt>\n    <dd>Write an access log to this file, formatted like an Apache\n    log. This log does <em>not</em> contain crash tracebacks.</dd>\n\n    <dt><code>--quiet</code></dt>\n    <dd>By default, but not when this option is set, a browser is\n    automatically started to show the Herbie page. This option also\n    shrinks the text printed on start up.</dd>\n\n    <dt><code>--public</code></dt>\n    <dd>When set, users on other computers can connect to the demo and\n    use it. (In other words, the server listens\n    on <code>0.0.0.0</code>.). Essential when Herbie is run\n    from <a href=\"docker.html\">Docker</a>.</dd>\n  </dl>\n\n  <h2>Rulesets</h2>\n\n  <p>\n    Herbie uses rewrite rules to change programs and improve accuracy.\n    The <code>--disable rules:<var>group</var></code>\n    and <code>--enable rules:<var>group</var></code> options turn rule\n    sets on and off. In general, turning a ruleset on makes Herbie\n    produce more accurate but more confusing programs.\n  </p>\n\n  <p>The full list of rule groups is:</p>\n\n  <table class=\"function-list\">\n    <thead><tr><th>Rule Group</th><th>Topic of rewrite rules</th></tr></thead>\n    <tr><td>arithmetic</td><td>Basic arithmetic facts</td></tr>\n    <tr><td>polynomials</td><td>Factoring and powers</td></tr>\n    <tr><td>fractions</td><td>Fraction arithmetic</td></tr>\n    <tr><td>exponents</td><td>Exponentiation identities</td></tr>\n    <tr><td>trigonometry</td><td>Trigonometric identities</td></tr>\n    <tr><td>hyperbolic</td><td>Hyperbolic trigonometric identities</td></tr>\n    <tr><td>bools</td><td>Boolean operator identities</td></tr>\n    <tr><td>branches</td><td><code>if</code> statement simplification</td></tr>\n    <tr><td>special</td><td>The gamma, Bessel, and error functions</td></tr>\n    <tr><td>numerics</td><td>Numerical compounds <code>expm1</code>, <code>log1p</code>, <code>fma</code>, and <code>hypot</code></td></tr>\n  </table>\n\n  <h2>Search options</h2>\n\n  <p>\n    These options change the types of transformations that Herbie uses\n    to find candidate programs. We recommend sticking to the defaults.\n  </p>\n\n  <p>\n    Each option can be turned off with the <code>-o</code>\n    or <code>--disable</code> command-line flag and on with\n    <code>+o</code> or <code>--enable</code>. Turning an option off\n    typically results in less-accurate results, while turning a option\n    on typically results in more confusing output expressions.\n  </p>\n\n  <dl>\n    <dt><code>precision:fallback</code></dt>\n    <dd>This option, on by default, tells Herbie to use fallback\n    functions if a native implementation is not found for an operation\n    (and print a warning). If turned off, operations with no native\n    implementation will be disabled entirely. To our knowledge, this\n    option only affects the Bessel functions on Windows.</dd>\n\n    <dt><code>setup:simplify</code></dt>\n    <dd>This option, on by default, simplifies the expression before\n    passing it to Herbie. If turned off, Herbie will not simplify\n    input programs before improving them.</dd>\n\n    <dt><code>generate:rr</code></dt>\n    <dd>This option, on by default, uses Herbie's recursive rewriting\n    algorithm to generate candidate programs. If turned off, Herbie\n    will use a non-recursive rewriting algorithm, which will\n    substantially limit Herbie's creativity.</dd>\n\n    <dt><code>generate:taylor</code></dt>\n    <dd>This option, on by default, uses series expansion to produce\n    new candidates during the main improvement loop. If turned off,\n    Herbie will not use series expansion. Turn this option off if you\n    want to avoid series-expansion-based rewrites, such as if you need\n    to preserve the equivalence of the input and output expressions as\n    real-number formulas.</dd>\n\n    <dt><code>generate:simplify</code></dt>\n    <dd>This option, on by default, simplifies candidates during the\n    main improvement loop. If turned off, candidates will not be\n    simplified, which typically results in much less accurate\n    expressions.</dd>\n\n    <dt><code>reduce:regimes</code></dt>\n    <dd>This option, on by default, uses Herbie's regime inference\n    algorithm to branch between several program candidates. If turned\n    off, branches will not be inferred and the output program will be\n    straight-line code (if the input was). Turn this option off if\n    your programming environment makes branches very expensive, such\n    as on a GPU.</dd>\n\n    <dt><code>reduce:avg-error</code></dt>\n    <dd>This option, on by default, causes Herbie to output the\n    candidate with the best average error over the chosen inputs. If\n    turned off, Herbie will choose the candidate with the least\n    maximum error instead. This usually produces programs with worse\n    overall accuracy. Turn this option off if worst-case accuracy is\n    more important to you than overall accuracy.</dd>\n\n    <dt><code>reduce:binary-search</code></dt>\n    <dd>This option, on by default, uses binary search to refine the\n    values used in inferred branches. If turned off, different runs of\n    Herbie will be less consistent, and accuracy near branches will\n    suffer.</dd>\n\n    <dt><code>reduce:branch-expressions</code></dt>\n    <dd>This option, on by default, allows Herbie to branch on\n      expressions, not just variables. This slows Herbie down,\n      particularly for large programs. If turned off, Herbie will only\n      try to branch on variables.</dd>\n  </dl>\n\n  <h2>Upgrading from Herbie 1.0</h2>\n\n  <p>Herbie 1.0 used\n  a <a href=\"../1.0/using-herbie.html\">different</a> command line\n  syntax, without multiple tools. Translate like so:</p>\n\n  <ul>\n    <li><code>herbie-1.0</code> → <code>herbie-1.4 shell</code></li>\n    <li><code>herbie-1.0 file</code> → <code>herbie-1.4 improve file -</code></li>\n    <li><code>herbie-1.0 files ...</code> → <code>cat files ... | herbie-1.4 improve - -</code><br/>\n      Alternatively, collect the files into a directory and run <code>herbie-1.4 improve dir/ -</code></li>\n  </ul>\n\n  <p>The new syntax somewhat changes Herbie's behavior, such as by\n  using the input expression as the output if Herbie times out. It\n  also makes it easier to write Herbie's output to a file without\n  using command-line redirection.</p>\n\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.6/plugins.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Plugins</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Plugins</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p><a href=\"../../\">Herbie</a> plugins define new functions, add\n  rewrite rules, and even implement number representations.</p>\n\n  <p>Herbie plugins are installed separately. Herbie then\n  automatically loads and uses them.</p>\n  \n  <h2>Posit arithmetic</h2>\n\n  <p>The <kbd>softposit-herbie</kbd> plugin implements support\n  for <a href=\"https://posithub.org/\">posit</a> arithmetic. Install it\n  with:</p>\n\n  <pre class=\"shell\">raco pkg install --auto softposit-herbie</pre>\n\n  <p>This plugin uses the SoftPosit library, only supported on Linux.\n  Even then is reported to misbehave on some machines. The plugin\n  support arithmetic operations, <code>sqrt</code>, and quires.</p>\n\n  <p>Once <kbd>softposit-herbie</kbd> is installed,\n  specify <code>:precision posit16</code> to inform Herbie that it\n  should assume the core's inputs and outputs are posit numbers. Other\n  posit sizes (with 8 or 32 bits) and also quires (for 8, 16, and 32\n  bit posits) are available, but are poorly supported.</p>\n\n\n  <h2 id=\"complex\">Complex numbers</h2>\n\n  <p>The <kbd>complex-herbie</kbd> plugin has been removed as of Herbie 1.6.\n    This plugin may be brought back in the future.\n\n  <h2 id=\"complex\">Generic floating-point numbers</h2>\n\n  <p>The <kbd>float-herbie</kbd> plugin implements support for any IEEE-754\n    binary floating-point number. To install, check out the\n    <a href=\"https://github.com/bksaiki/float-herbie\">source code</a>\n    and run\n  </p>\n\n  <pre class=\"shell\">raco pkg install</pre>\n\n  <p>\n    at the top-level directory of the repository.\n    Once <kbd>float-herbie</kbd> is installed,\n    specify <code>:precision (float <i>ex</i> <i>nb</i>)</code>\n    to inform Herbie that it should assume the core's inputs and outputs are\n    floating-point numbers with <i>ex</i> exponent bits and <i>nb</i> total bits\n    (sign bit + mantissa bits + exponent bits).\n  </p>\n\n  <h2 id=\"complex\">Generic fixed-point numbers</h2>\n\n  <p>The <kbd>fixedpoint-herbie</kbd> plugin implements support for any fixed-point number.\n    To install, check out the\n    <a href=\"https://github.com/bksaiki/fixedpoint-herbie\">source code</a>\n    and run\n  </p>\n\n  <pre class=\"shell\">raco pkg install</pre>\n\n  <p>\n    at the top-level directory of the repository.\n    Once <kbd>fixedpoint-herbie</kbd> is installed,\n    specify <code>:precision (fixed <i>nb</i> <i>sc</i>)</code>\n    to inform Herbie that it should assume the core's inputs and outputs are\n    signed fixed-point numbers with <i>nb</i> total bits and a scaling factor of\n    2<sup><i>sc</i></sup> (integer formats have a scaling factor of 2<sup>0</sup>).\n    This plugin also supports unsigned fixed-point numbers specified by\n    <code>:precision (ufixed <i>nb</i> <i>sc</i>)</code> and provides\n    simpler aliases for integer formats with <code>:precision (integer <i>nb</i>)</code>\n    and <code>:precision (uinteger <i>nb</i>)</code>.\n  </p>\n  \n  <h2>Developing plugins</h2>\n\n  <p>The following is a guide to creating a Herbie plugin.\n  Plugins are considered experimental and may change considerably\n  between releases.\n  If you run into issues, please write to the\n  <a href=\"https://mailman.cs.washington.edu/mailman/listinfo/herbie\">\n  mailing list</a>.\n  Be sure to check out the <a href=\"https://github.com/herbie-fp/herbie/tree/main/src/reprs\">\n  built-in plugins</a> in the Herbie repository before getting started.</p>\n\n  <p><b>First Steps</b><br>\n\n  All plugins are implemented as Racket packages. The easiest way to\n  initialize a new Racket package is to run\n\n  <pre class=\"shell\">raco pkg new <i>pkg-name</i></pre>\n\n  in a new folder. Make sure the folder name is the same as the package name!\n  This will initialize a Racket package with all the necessary files.\n  Read the official Racket documentation on the\n  <a href=\"https://docs.racket-lang.org/pkg/getting-started.html#%28part._how-to-create%29\">\n  raco</a> tool for more information.</p>\n\n  <p>A single entry needs to be added to the package manifest stored in <code>info.rkt</code>,\n  and add <code>(define herbie-plugin '<i>name</i>)</code> to the bottom of the file\n  where <i>name</i> is a unique symbol that doesn't conflict with other Herbie plugins.\n  As a suggestion, this should just be the package name.</p>\n\n  <p>Next, edit the <code>main.rkt</code> file by erasing everything except the\n  language specifier on the first line, and add the line <code>(require herbie/plugin)</code>.\n  This gives the package access to the Herbie plugin interface.\n  Optionally add the following for debugging purposes\n  <code>(eprintf \"Loading <i>pkg-name</i> support...\\n\")</code>\n  directly after the <i>require</i> statement.</p>\n\n  <p>Finally, run the following in the folder containing <code>info.rkt</code>\n  and <code>main.rkt</code>:\n\n  <pre class=\"shell\">raco pkg install</pre>\n\n  This should install your package and check for errors.\n  Now everything is set up!\n  Of course, your plugin is empty and doesn't add any useful features.\n  If you added the debugging line in <code>main.rkt</code>, you should see the string\n  when you run Herbie.\n  </p>\n\n  <p><b>Adding Features</b><br>\n  \n  Now that you have an empty plugin, you can begin adding new functions, rewrite\n  rules, and number representatons.\n  The procedures exported by the Herbie plugin interface can be roughly divided into\n  two categories: unique and parameterized.\n  Whether or not you use the unique or parameterized half of the interface\n  (or maybe both!) depends entirely on the number representation a feature is being\n  implemented for.\n  First, identify if your number representation is unique or parameterized.\n  For example, if you are adding features for <code>double</code> precision\n  (or rather <code>binary64</code>), the representation is unique.\n  If you are adding features for a generic floating point format, say\n  <code>(float <i>ebits</i> <i>nbits</i>)</code>, then the representation is parameterized.</p>\n\n  <p><b>Plugin Interface (Unique)</b><br>\n\n  The following are the signatures and descriptions of the\n  plugin procedures for unique representations.\n  These procedures are required to be at the top-level of\n  <code>main.rkt</code> rather than inside a function.</p>\n\n  <dl>\n    <dt>\n      <code>(<b>define-type</b> <i>name</i> (<i>exact?</i> <i>inexact?</i>)\n                         <i>exact->inexact</i> <i>inexact->exact</i>)</code>\n    </dt>\n    <dd>Adds a new type with the unique identifier <code><i>name</i></code>.\n      The arguments <code><i>exact?</i></code> and <code><i>inexact?</i></code>\n      return true if a value is an exact or high-precision approximate representation.\n      For Herbie's <code>real</code> type, <code><i>exact?</i></code> is implemented\n      with <code>real?</code> and <code><i>inexact?</i></code> is implemented\n      with <code>bigfloat?</code>. The procedures <code><i>exact->inexact</i></code> and\n      <code><i>inexact->exact</i></code> convert between <code><i>exact?</i></code>\n      and <code><i>inexact?</i></code> values.\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-representation</b> (<i>name</i> <i>type</i> <i>repr?</i>)</td>\n                     <td><i>bigfloat->repr</i></td></tr>\n        <tr><td></td><td><i>repr->bigfloat</i></td></tr>\n        <tr><td></td><td><i>ordinal->repr</i></td></tr>\n        <tr><td></td><td><i>repr->ordinal</i></td></tr>\n        <tr><td></td><td><i>width</i></td></tr>\n        <tr><td></td><td><i>special?</i>)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Adds a new representation with the unique identifier <code><i>name</i></code>.\n      The representation will inherit all rewrite rules defined for <code><i>type</i></code>.\n      By default, Herbie defines two types: <code>real</code> and <code>bool</code>.\n      Your representation will most likely inherit from <code>real</code>.\n      The <code><i>width</i></code> argument should be the bitwidth of the representation,\n      e.g. 64 for <code>binary64</code>.\n      The argument <code><i>repr?</i></code> is a procedure that accepts any argument and returns\n      true if the argument is a value in the representation, e.g. an integer representation\n      should use Racket's <code>integer?</code>, while <code><i>special?</i></code> takes a\n      value in the representation and returns true if it is not finite, e.g. NaN or infinity.<br><br>\n\n      The other four arguments are single-argument procedures that implement different conversions.\n      The first two convert between a value in your representation and a Racket\n      <a href=\"https://docs.racket-lang.org/math/bigfloat.html\">bigfloat</a>\n      (you need to import <code>math/bigfloat</code>).\n      The last two convert between a value in your representation and its corresponding ordinal value.\n      Ordinal values for any representation must be within the interval [0, 2<sup><i>width</i></sup> - 1].\n      Check Racket's definition of\n      <a href=\"https://docs.racket-lang.org/math/flonum.html?q=ordinal#%28def._%28%28lib._math%2Fflonum..rkt%29._flonum-~3eordinal%29%29\">\n      ordinals</a> for floats.\n      Note that those ordinal values can be negative.\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-operator</b> (<i>name</i> <i>itype-names ...</i>)</td><td> otype-name</td></tr>\n        <tr><td></td><td>[bf <i>bf-fn</i>]</td></tr>\n        <tr><td></td><td>[ival <i>ival-fn</i>])\n      </table>\n      </code>\n    </dt>\n    <dd>Adds a new operator. Operators describe pure mathematical functions,\n      i.e. <code>+</code> or <code>sin</code>.\n      The parameters <code><i>itype-names</i></code> and <code><i>otype-name</i></code>\n      are the input type(s) and output type names.\n      For example, <code>+</code> takes two <code>real</code> inputs and produces\n      one <code>real</code> output.\n      The <code><i>bf-fn</i></code> argument is the\n      <a href=\"https://docs.racket-lang.org/math/bigfloat.html\">bigfloat</a> implementation of your operator.\n      The <code><i>ival-fn</i></code> argument is the <a href=\"https://github.com/herbie-fp/rival\">Rival</a>\n      implementation of your operator. This is optional but improves the quality of Herbie's output.\n      If you don't want to implement this, set <code><i>ival-fn</i></code> to <code>false</code>.\n      To define operators with an unknown number of arguments, e.g. comparators,\n      add the attribute <code>[itype <i>itype</i>]</code>.\n      This will override the input type names defined by <code><i>itype-names</i></code>.\n      See the bottom of this section for support for constants.\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-operator-impl</b> (<i>op</i> <i>name</i> <i>irepr-names ...</i>)</td><td><i>orepr-name</i></td></tr>\n        <tr><td></td><td>[fl <i>fl-fn</i>]</td></tr>\n        <tr><td></td><td>...)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Implements <code><i>op</i></code> with input representation(s) <code><i>irepr-names</i></code>\n      and output representation <code><i>orepr-name</i></code>.\n      The field <code><i>name</i></code> must be unique.\n      For example, Herbie implements <code>+.f64</code> and <code>+.f32</code>\n      for double- and single-precision floats.\n      The argument <code><i>fl-fn</i></code> is the actual procedure that does the computation.\n      Like <code>define-operator</code>, the input representations can be\n      overridden with <code>[itype <i>irepr</i>]</code>.\n      By default, the attributes <code>bf</code> and <code>ival</code>\n      are inherited from <code><i>op</i></code> but can be overridden as previously\n      described.\n      See the bottom of this section for support for constant implementations.\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-ruleset</b> <i>name</i> (<i>groups ...</i>)</td>\n            <td>#:type ([<i>var</i> <i>repr</i>] ...)</td></tr>\n        <tr><td></td><td>[<i>rule-name</i> <i>match</i> <i>replace</i>]</td></tr>\n        <tr><td></td><td>...)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Defines a set of rewrite rules.\n      The <code><i>name</i></code> of the ruleset as well as each <code><i>rule-name</i></code>\n      must be a unique symbol.\n      Each ruleset must be marked with a set of <code><i>groups</i></code>\n      (read <a href=\"options.html#heading-3\">here</a> on ruleset groups).\n      Each rewrite rule takes the form <code>match ⇝ replace</code> where Herbie's rewriter\n      will replace <code>match</code> with <code>replace</code> (not vice-versa).\n      Each <code><i>match</i></code> and <code><i>replace</i></code> is an expression whose operators are\n      the names of operator implementations rather than pure mathematical operators.\n      Any variable must be listed in the type information with its associated representation.\n      See the <code>softposit-herbie</code> plugin for a more concrete example.\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-ruleset*</b> <i>name</i> (<i>groups ...</i>)</td>\n            <td>#:type ([<i>var</i> <i>type</i>] ...)</td></tr>\n        <tr><td></td><td>[<i>rule-name</i> <i>match</i> <i>replace</i>]</td></tr>\n        <tr><td></td><td>...)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Like <code>define-ruleset</code>, but it defines a ruleset for every representation that\n      inherits from <code><i>type</i></code>.\n      Currently, every <code><i>type</i></code> must be the same, e.g.\n      all <code>real</code>, for this procedure to function correctly.\n      Unlike <code>define-ruleset</code>, <code><i>match</i></code> and <code><i>replace</i></code>\n      contain the names of operators rather than operator implementations.\n    </dd>\n  </dl>\n\n  <p>Procedures for declaring constants are not a part of the plugin interface.\n    Instead, constants and constant implementations are defined as\n      zero-argument operators and operator implementations.\n    The fields <code><i>fl-fn</i></code>, <code><i>bf-fn</i></code>,\n      and <code><i>ival-fn</i></code> should be implemented with zero-argument\n      procedures (thunks).\n    Similar to operator and operator implementations, constants describe pure\n      mathematical values like <code>π</code> or <code>e</code> while constant\n      implementations define an approximation of those constants in a particular\n      representation.\n  </p>\n\n  <p><b>Plugin Interface (Parameterized)</b><br>\n\n  Defining operators, constants, and representations for parameterized functions requires\n  a <i>generator</i> procedure for just-in-time loading of features for a particular\n  representation.\n  When Herbie encounters a representation it does not recognize (not explicitly defined\n  using <code>define-representation</code>) it queries a list of generators in case the\n  representation requires just-in-time loading.\n  </p>\n\n  <p>The following procedure handles represention objects:</p>\n\n  <dl>\n    <dt><code>(<b>get-representation</b> name)</code></dt>\n    <dd>Takes a representation name and returns a representation object.\n      Do not call this function before the associated representation has been registered!\n    </dd>\n  </dl>\n\n  <p>The following procedures handle generators:</p>\n\n  <dl>\n    <dt><code>(<b>register-generator!</b> gen)</code></dt>\n    <dd>Adds a representation generator procedure to Herbie's set of generators.\n      Representation generator procedures take the name of a representation and\n      return the associated representation object if it successfully created the\n      operators, constants, and rules for that representation.\n      In the case that your plugin does not register the requested representation,\n      the generator procedure need not do anything and should just return\n      <code>false</code>.\n    </dd>\n  </dl>\n\n  <dl>\n    <dt><code>(<b>register-conversion-generator!</b> gen)</code></dt>\n    <dd>Adds a conversion generator procedure to Herbie's set of generators.\n      Conversion generator procedures take the names of two representations\n      and returns <code>true</code> if it successfully registered conversion(s)\n      between the two representations.\n      Conversions are one-argument operator implementations of the <code>cast</code>\n        operator that have one representation as an input representation and\n        a different representation as an output representation.\n      User-defined conversions are <i>OPTIONAL</i> for multi-precision optimization,\n        since Herbie can synthesize these by default.\n      However Herbie's implementations are often slow since they are\n        representation-agnostic and work for any two representations.\n      In the case that your plugin does not register the requested conversion(s),\n      the generator procedure need not do anything and should just return\n      <code>false</code>.\n    </dd>\n  </dl>\n\n  <p>\n    To actually add representations, operators, etc. within a generator procedure,\n    you must use a set of alternate procedures.\n  </p>\n\n  <dl>\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>register-representation!</b> </td><td> <i>name</i></td></tr>\n        <tr><td></td><td><i>type</i></td></tr>\n        <tr><td></td><td><i>repr?</i></td></tr>\n        <tr><td></td><td><i>bigfloat->repr</i></td></tr>\n        <tr><td></td><td><i>repr->bigfloat</i></td></tr>\n        <tr><td></td><td><i>ordinal->repr</i></td></tr>\n        <tr><td></td><td><i>repr->ordinal</i></td></tr>\n        <tr><td></td><td><i>width</i></td></tr>\n        <tr><td></td><td><i>special?</i>)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Like <code>define-representation</code>, but used within generators.</dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>register-representation-alias!</b> </td><td> <i>name</i> <i>repr</i>)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Adds an alias <i>name</i> for an existing representation <i>repr</i>.\n      If two representations are equivalent, e.g. <i>(float 8 32)</i> and <i>binary32</i>,\n      this procedure can be used to declare the two representations equivalent.\n    </dd>\n\n    <dt>\n      <code>(<b>register-operator!</b> <i>op</i> <i>name</i> <i>itype-names</i>\n        <i>otype-name</i> <i>attribs</i>)</code>\n    </dt>\n    <dd>Like <code>define-operator</code>, but used within generators.\n      The argument <code><i>itype-names</i></code> is a list of the input types\n      while the argument <code><i>attribs</i></code> are the same attributes for\n      <code>define-operator</code>, e.g. <code>bf</code>.\n      In this case, <code><i>attribs</i></code> is an association:\n      <code>(list (cons 'bf <i>bf-fn</i>) ...)</code>.\n    </dd>\n\n    <dt>\n      <code>(<b>register-operator-impl!</b> <i>op</i> <i>name</i> <i>ireprs</i>\n        <i>orepr</i> <i>attribs</i>)</code>\n    </dt>\n    <dd>Like <code>define-operator-impl</code>, but used within generators.\n      Unlike <code>define-operator-impl</code>, this procedure takes representation\n        objects rather than representation names for <code><i>ireprs</i></code>\n        and <code><i>orepr</i></code>.\n      Use <code>get-representation</code> to produce these objects.\n      See <code>register-operator!</code> for a description of <code><i>attribs</i></code>.\n    </dd>\n\n    <dt><code>(<b>register-ruleset!</b> <i>name</i> <i>groups</i>\n        <i>var-repr-names</i> <i>rules</i>)</code>\n    </dt>    \n    <dd>Like <code>define-ruleset</code>, but used within generators.\n      In this case, <code><i>groups</i></code> is a list of rule groups;\n        <code><i>var-repr-names</i></code> is an association\n        pairing each variable in the ruleset with its representation, e.g.\n        <code>(list (cons 'x '(float 5 16)) ...)</code>;\n        and <code><i>rules</i></code> is a list of rules of the following\n        form <code>(list (list <i>rule-name</i> <i>match</i> <i>replace</i>) ...)</code>.\n    </dd>\n\n  </dl>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.6/release-notes.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie 1.6 Release Notes</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <script src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML\"></script>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <style>\n    .showcase {\n      margin: 4em 0 0em 0;\n    }\n    h2 {\n      margin: 1.5em 0 .5em;\n    }\n  </style>\n</head>\n<body>\n  <header>\n    <h1>Herbie 1.6 Release Notes</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>The <a href=\"../..\">Herbie</a> developers are excited to announce\n  Herbie 1.6! This release focuses on further integration of <a href=\"https://github.com/egraphs-good/egg\">egg</a>, improved reliability,\n  and a better web interface. Our favorite features are below.</p>\n\n  <img width=\"100%\" src=\"team.png\" style=\"display: block; margin: 4em 0; border-radius: 6px;\"\n       alt=\"The Herbie team, working over Zoom to bring you Herbie 1.6\" />\n\n  <p><b>What is Herbie?</b> Herbie automatically improves the accuracy\n  of floating point expressions. This avoids the bugs, errors, and\n  surprises that so often occur with floating point arithmetic.</p>\n\n  <p><b>Join us!</b> Join the Herbie developers on the\n  <a href=\"https://fpbench.org\">FPBench</a> Slack, at the monthly\n  FPBench community meetings, and at\n  <a href=\"https://fpbench.org/talks/fptalks22.html\">FPTalks 2022</a>.\n\n  <figure class=\"showcase\">\n    <img src=\"old-rr-seed-variance.png\" style=\"width: 100%;\" />\n    <img src=\"egg-rr-seed-variance.png\" style=\"width: 100%;\" />\n    <figcaption>\n      Comparison of Herbie's total output error (bits) across 100 seeds with\n        the old recursive rewriter (top) versus the egg-based implementation (bottom).\n      The egg-based implementation has lower variability.\n    </figcaption>\n  </figure>\n\n  <h2>Recursive Rewriting with egg</h2>\n\n  Two releases ago, Herbie 1.4 featured a new simplifier that used the\n    <a href=\"https://github.com/egraphs-good/egg\">egg</a> library\n    for a substantial increase in speed.\n  This release further incorporates the egg library into Herbie by replacing\n    the recursive rewriter with an egg-based implementation.\n  Herbie's output is now more stable across seeds compared\n    to the previous implementation, maintains a similar level\n    of performance, and increases accuracy gains overall.\n  This change also makes it easier to add new rewrite rules, \n  since the egg-based rewriter's behavior is more predictable \n  than the old recursive rewriter was.\n  \n  <figure class=\"showcase\">\n    <img src=\"interactive-preconditions.png\" style=\"width: 100%;\" />\n    <figcaption>\n      Preconditions in the new web interface. For each input, \n      users are asked to provide a range of values for Herbie \n      to focus on optimizing over. Input ranges vary depending\n      on the user's application and should always be \n      supplied to maximize accuracy.\n    </figcaption>\n  </figure>\n\n  <h2>Interactive Herbie</h2>\n\n  <p>\n  Despite the fact that most users interact with Herbie via \n  the <a href=\"https://herbie.uwplse.org/demo/\">demo page</a>,\n    the web interface has historically had a minimal design,\n    with important features like preconditions hidden behind \n    advanced configuration dialogs.\n  As part of an ongoing push to make Herbie more user-friendly, \n    we have added support for preconditions to the main interface, \n    and have improved the display of warnings and errors.\n  We expect the demo page to change further in the coming year \n    to provide users with more support in analyzing Herbie's output\n    and testing their own ideas for rewritings.\n  </p>\n\n  <figure class=\"showcase\">\n    <table style=\"border:1px solid black;\">\n      <tr>\n        <td><img src=\"quadp-old-branch.png\" style=\"width: 100%;\" /></td>\n        <td><img src=\"quadp-short-branch.png\" style=\"width: 100%;\" /></td>\n      </tr>\n    </table>\n    <figcaption>\n      Comparison of the midpoint (left) vs. shortest number (right) methods for\n        selecting branch conditions.\n    </figcaption>\n  </figure>\n\n  <h2>Shorter Branch Conditions</h2>\n\n  <p>\n    Herbie now synthesizes branch conditions with shorter split values.\n    Before, Herbie's binary search algorithm would narrow down the set of\n      possible split values to a small interval from which Herbie took the midpoint.\n    Often the midpoint had a long string representation which made it seem\n      like it was chosen with high precision.\n    Now Herbie will choose a value on that same interval with a short string representation.\n    This change makes output programs more readable and highlights the\n      low precision in the result of binary search.\n      \n  </p>\n\n  <figure class=\"showcase\">\n    <img src=\"system-1.6-changes.png\" style=\"width: 100%;\" />\n    <figcaption>\n      System diagram for Herbie 1.6, with key changes in red dotted boxes.\n      From top to bottom: double-precision (binary64) and single-precision (binary32) types\n        are loaded through plugins instead of being embedded in Herbie's core;\n        a new patching subsystem bundles together the various\n        rewriting methods behind a simple interface;\n        recursive rewrite uses egg.\n      Compare Herbie 1.5 and 1.6 system diagrams <a href=\"../1.5/diagrams.html\">here</a>\n        and <a href=\"../1.6/diagrams.html\">here</a>.\n    </figcaption>\n  </figure>\n\n  <h2>Patching and Plugins</h2>\n  \n  <p>Herbie has undergone a significant architectural change since the previous release.\n  Although this change may not be visible to users, we hope that it\n    makes future Herbie development more streamlined and provides a clearer\n    answer to the question: what is Herbie?\n  In particular, two major improvements include adding the \"patch table\"\n    and moving number system specifics out of Herbie's\n    core architecture.\n  </p>\n  \n  <p>The patch table manages most rewriting capabilities, provides a\n    minimal interface to generate variants from a set of expressions,\n    and caches variants in case of duplicate input expressions.\n  Creating this subsystem to handle variant generation more cleanly\n    separates the \"generate\" and \"test\" parts within Herbie.\n  </p>\n  \n  <p>Herbie's double-precision and single-precision representations\n    are now implemented as plugins that automatically ship\n    with Herbie.\n  Representation-specific operators and definitions are\n    no longer present in Herbie's core architecure.\n  This change makes Herbie representation-agnostic and loads\n    double- and single-precision representations through the plugin interface.\n  Not only is this design cleaner, but these plugins now\n    serve as examples for plugin developers.\n  In the future, we hope to move additional definitions\n    out of core Herbie and into plugins such as error metrics\n    and cost models (Pherbie).\n  </p>\n  <br>\n  <h2>Other improvements</h2>\n  <ul>\n    <li>Precondition analysis and point sampling are unified under a single function.\n      Sampling multiple functions is now supported.\n    </li>\n    <li>The backup sampler now just computes with MPFR floats\n        at high-precision rather than the old \"halfpoints\" sampler.\n    </li>\n    <li> Constants are now represented internally as operators.\n      This simplifies the plugin interface as well as Herbie's internals.\n    </li>\n    <li>Support for variary operators has been removed.\n      Relational operators are now expanded when parsed.</li>\n    <li>Constants are always read as exact rational numbers.\n      This enables additional optimizations through constant folding.\n    </li>\n    <li>More output languages are supported in the reports including\n      Fortran, Java, Python, Julia, MatLab, and Wolfram.\n    </li>\n    <li>egg has been updated to 0.8.1 which has led to a performance increase.\n      Make sure to have at least Rust 1.60 when installing from source.\n    </li>\n  </ul>\n\n  <h2>Deprecations and removals</h2>\n  <ul>\n    <li>The Bessel functions <code>j0</code>, <code>j1</code>, <code>y0</code>, and <code>y1</code>\n      have been deprecated and will be removed in the next release.</li>\n    <li>Support for the Racket 7.x has been removed. Please upgrade.</li>\n    <li>Support for complex numbers has been removed.\n    Please <a href=\"mailto:herbie@cs.washington.edu\">let us know</a>\n    if you are using it. We hope to reimplement this eventually,\n    but with a better architecture.</li>\n    <li>The <kbd>precision:fallback</kbd> flag has been deprecated, and no\n    longer does anything. Use the <code>:precision racket</code> flag instead.</li>\n    <li>Support for <a href=\"https://github.com/herbie-fp/regraph\">regraph</a> has been removed.</li>\n  </ul>\n  <br>\n  <h2>Try it out!</h2>\n\n  <p>\n    We want Herbie to be more useful to scientists, engineers, and\n    programmers around the world. We've got a lot of features we're\n    excited to work on in the coming months. Please\n    <a href=\"https://github.com/uwplse/herbie/issues\">report bugs</a>,\n    join\n    <a href=\"https://mailman.cs.washington.edu/mailman/listinfo/herbie\">the\n    mailing list</a>,\n    or <a href=\"https://github.com/uw-plse/herbie\">contribute</a>.\n  </p>\n  <br>\n  <p style=\"font-weight: bold; text-align: center;\">If you find Herbie\n  useful, <a href=\"mailto:herbie@cs.washington.edu\">let us know!</p>\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.6/report.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie reports</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Herbie reports</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  \n  <h1>The Herbie report</h1>\n\n  <p>When used <a href=\"using-web.html\">in the browser</a>, Herbie\n  generates HTML reports full of information about the accuracy of\n  your input and its output expressions.</p>\n\n  <h2 id=\"summary\">Summary numbers</h2>\n\n  <p>First, a brief summary of the results. For most uses, the\n    “Average Error” number, which describes how accurate the input and\n    output expressions are, is the most important statistic in this\n    section. The other numbers list time Herbie took to improve the\n    program and the <a href=\"input.html#precisions\">precision</a>\n    assumed for floating-point operations.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-large.png\" />\n    <figcaption>Summary numbers from a Herbie report. The \"binary64\"\n    precision refers to double-precision IEEE-754\n    arithmetic.</figcaption>\n  </figure>\n\n  <h2 id=\"programs\">Input and output programs</h2>\n\n  <p>Second, the input and output programs themselves, in standard\n  mathematical syntax. In the top-right corner, the drop-down can be\n  used to switch to C syntax or some other format.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-prog.png\" />\n    <figcaption>Input and output program from a Herbie report.</figcaption>\n  </figure>\n\n  <h2 id=\"graph\">Error graph</h2>\n\n  <p>\n    Third, under <em>Error</em>, a graph of floating-point error\n    versus input value. This is helpful for understanding the sorts of\n    inputs Herbie is improving accuracy on. Sometimes, Herbie improved\n    accuracy on some inputs at the cost of accuracy on other inputs\n    that you care more about. You can add\n    a <a href=\"input.html#preconditions\">precondition</a> to restrict\n    Herbie to certain inputs in those cases.\n  </p>\n\n  <p>\n    These graphs show the error of the input program with a red line,\n    and the error of the output program with a blue line. Both can be\n    toggled. If the expression has multiple variables, the variable\n    picker on the bottom left selects which variable is placed on the\n    horizontal axis. If Herbie decided to insert an <code>if</code>\n    statement into the program, the locations of those <code>if</code>\n    statements will be marked with vertical bars.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-error.png\" />\n    <figcaption>An error graph from a Herbie report. Note the variable\n    selector (<code>x</code> is selected) and the toggles for the\n    input and output program (both are toggled on).</figcaption>\n  </figure>\n\n  <h2 id=\"try-it\">Interactive inputs</h2>\n\n  <p>\n    Fourth, a interactive form where you can the output of both your\n    and Herbie's programs. on inputs of your choice Enter argument\n    values on the left, and the input and output programs will be\n    evaluated on those arguments and the results printed on the right.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-try-it.png\" />\n    <figcaption>\n      The interactive section of a Herbie report. \"In\" is your program,\n      \"Out\" is Herbie's.\n    </figcaption>\n  </figure>\n\n  <h2 id=\"derivation\">Derivation</h2>\n\n  <p>Fifth, Herbie's derivation of its output program. These can be\n    helpful in understanding how Herbie works. Each substantive step\n    in the derivation also lists the error, in bits, of that step's\n    output. Sometimes you can use that to pick a less-complex and\n    not-substantially-less-accurate program.</p>\n\n  <p>Derivations sometime name arithmetic laws used by Herbie, or they\n    might claim derivation steps are done by simplification, series\n    expansion, or other Herbie strategies. The derivation will also\n    call out any time the input is split into cases. When one part of\n    the program is colored blue, that is the part modified in that\n    derivation step.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-derivation.png\" />\n    <figcaption>A short derivation from a Herbie report. Note the\n    error, in gray, measured after each derivation step.</figcaption>\n  </figure>\n\n  <h2 id=\"reproduction\">Reproduction</h2>\n\n  <p>Sixth, a command to reproduce this Herbie result. If you find a\n  Herbie bug, include this code snippet when\n  <a href=\"https://github.com/uwplse/herbie/issues\">filing an\n  issue</a>.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-reproduce.png\" />\n    <figcaption>Reproduction information for a Herbie run. You can use\n    this when submitting bug reports.</figcaption>\n  </figure>\n\n  <h2 id=\"links\">Additional links</h2>\n  \n  <p>The top of the page has a right-hand menu bar with additional\n  links. “Report” returns you to Herbie's main page. “Log” and\n  “Metrics” give you detailed internal information about Herbie.</p>\n\n  <p>We expect the report to grow more informative with future\n  versions. Please <a href=\"mailto:herbie@cs.washington.edu\">get in\n  touch</a> if there is more information you'd like to see.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.6/toc.js",
    "content": "function make_toc() {\n    var headings = document.querySelectorAll(\"h2\");\n    var toc = document.createElement(\"nav\");\n    toc.classList.add(\"toc\")\n    var list = document.createElement(\"ul\");\n    for (var i = 0; i < headings.length; i++) {\n        var li = document.createElement(\"li\");\n        var a = document.createElement(\"a\");\n        var h = headings[i];\n        if (! h.id) {\n            h.setAttribute(\"id\", \"heading-\" + i);\n        }\n        a.setAttribute(\"href\", \"#\" + h.id);\n        a.innerHTML = h.innerHTML;\n        li.appendChild(a);\n        list.appendChild(li);\n    }\n    toc.appendChild(list);\n    headings[0].parentNode.insertBefore(toc, headings[0]);\n}\n\nwindow.addEventListener(\"load\", make_toc);\n"
  },
  {
    "path": "www/doc/1.6/tutorial.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Tutorial</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Herbie Tutorial</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> rewrites floating point expressions to\n      make them more accurate. Floating point arithmetic is\n      inaccurate; even 0.1 + 0.2 ≠ 0.3 for a computer. Herbie helps\n      find and fix these mysterious inaccuracies.\n  </p>\n\n  <p>\n    To get started, <a href=\"installing.html\">download and install</a>\n    Herbie. You're then ready to begin using Herbie.\n  </p>\n\n  <h2>Giving Herbie expressions</h2>\n\n  <p>Start Herbie with:</p>\n\n  <pre class=\"shell\">herbie web</pre>\n\n  <p>\n    After a brief wait, this will open your web browser and show you\n    Herbie's main window. The most important part of the page is this\n    bit:\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"web-input.png\" alt=\"The program input field in the Herbie web UI.\"/>\n  </figure>\n\n  <p>Type <kbd>(1 + x) - x</kbd> into this box. You should see two \n  boxes appear for entering the lower and upper bound on the range\n  of values for x. Select the lowest and highest options, like this:\n  <figure>\n    <img width=\"100%\" src=\"range-input.png\" alt=\"The input range field in the Herbie web UI.\"/>\n  </figure>\n  Finally, hit the \"Improve with Herbie\" button. You should see the \n  entry box gray out, then some text will appear on the\n  screen describing what Herbie is doing. After a few seconds, you'll\n  be redirected to a page with Herbie's results. The most important\n  part of that page is the large gray box in the middle:\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-prog.png\" alt=\"Input and output program from a Herbie report.\" />\n  </figure>\n\n  <p>\n    It shows the input, <code>(1 + x) - x</code>, and Herbie's more\n    accurate way to evaluate that expression: <code>1</code>. Herbie\n    did a good job, which you can see from the statistics at the top\n    of the page:\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-large.png\" alt=\"Statistics and error measures for this Herbie run.\" />\n  </figure>\n\n  <p>\n    The initial program had 29.0 bits of error (on average), while\n    Herbie's better version had 0 bits of error. That's because\n    <code>(1 + x) - x</code> should always be exactly equal\n    to <code>1</code>, but in floating-point arithmetic,\n    when <code>x</code> is really big, <code>1 + x</code> rounds down\n    to <code>x</code> and the expression returns <code>0</code>.\n  </p>\n\n  <p>\n    There is <a href=\"report.html\"> more information</a> on this\n    results web page, which you can use explain more about the\n    expression's errors and how Herbie derived its result.\n  </p>\n\n  <h2>Programming with Herbie</h2>\n\n  <p>Now that you've run Herbie and know how to read its results,\n  let's apply Herbie to a realistic program.</p>\n\n  <p>\n    Herbie's input expressions can come from source code, mathematical\n    models, or even a debugging tool\n    like <a href=\"http://herbgrind.ucsd.edu\">Herbgrind</a>. But most\n    often, they come from your mind, while you're writing new\n    mathematical code.\n  </p>\n\n  <p>When you're writing a new numerical program, it's best to keep\n  Herbie open in a browser tab so you can run it easily. That way, you\n  can run Herbie on any complex floating-point expression you're\n  coding up and so always use an accurate version of that expression.\n  Herbie has <a href=\"options.html\">options</a> to log all the\n  expressions you enter, so that you can refer to them later.</p>\n\n  <p>However, let's suppose you're instead tracking down a\n  floating-point bug in existing code. Then you'll need start by\n  identifying the problematic floating-point expression.</p>\n\n  <p>To demonstrate the workflow, let's walk through\n    <a href=\"https://github.com/josdejong/mathjs/pull/208\">bug 208</a>\n    in <a href=\"http://mathjs.org\">math.js</a>, a math library for\n    JavaScript. The bug deals with inaccurate square roots for complex\n    numbers. (For a full write-up of the bug itself, check out\n    a <a href=\"https://pavpanchekha.com/blog/casio-mathjs.html\">blog\n    post</a> by one of the Herbie authors.)\n  </p>\n\n  <h2>Finding the problematic expression</h2>\n\n  <p>\n    In most programs, there's a small core that does the mathematical\n    computations, while the rest of the program sets up parameters,\n    handles control flow, visualizes or print results, and so on. The\n    mathematical core is what Herbie will be interested in.\n  </p>\n\n  <p>\n    For our example, let's start\n    in <a href=\"https://github.com/josdejong/mathjs/tree/master/lib/function\"><code>lib/function/</code></a>.\n    This directory contains many subdirectories; each file in each\n    subdirectory defines a collection of mathematical functions. The\n    bug we're interested in is about complex square root, which is\n    defined in\n    <a href=\"https://github.com/josdejong/mathjs/blob/da306e26ed34272db44e35f07a3b015c0155d99a/lib/function/arithmetic/sqrt.js\"><code>arithmetic/sqrt.js</code></a>.\n  </p>\n\n  <p>\n    This file handles argument checks, five different number types,\n    and error handling, for both real and complex square roots. None\n    of that is of interest to Herbie; we want to extract just the\n    mathematical core. So skip down to the <code>isComplex(x)</code>\n    case:\n  </p>\n\n  <pre>var r = Math.sqrt(x.re * x.re + x.im * x.im);\nif (x.im &gt;= 0) {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}\nelse {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      -0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}</pre>\n\n  <p>This is the mathematical core that we want to send to Herbie.</p>\n\n  <h2>Converting problematic code to Herbie input</h2>\n\n  <p>\n    In this code, <code>x</code> is of type <code>Complex</code>, a\n    data structure with multiple fields. Herbie only deals with\n    floating-point numbers, not data structures, so we will treat the\n    input <code>x</code> as two separate inputs to\n    Herbie: <code>xre</code> and <code>xim</code>. We'll also pass\n    each field of the output to Herbie separately.\n  </p>\n\n  <p>\n    This code also branches between non-negative <code>x.im</code> and\n    negative <code>x.im</code>. It's usually better to send each\n    branch to Herbie separately. So in total this code turns into four\n    Herbie inputs: two output fields, for each of two branches.\n  </p>\n\n  <p>Let's focus on first field of the output for the case of\n  non-negative <code>x.im</code>.</p>\n\n  <p>The variable <code>r</code> is an intermediate variable in this\n  code block. Intermediate variables provide Herbie with crucial\n  information that Herbie can use to improve accuracy, so you want to\n  expand or inline them. The result looks like this:</p>\n\n  <pre>0.5 * sqrt(2.0 * (sqrt(xre * xre + xim * xim) + xre))</pre>\n\n  <p>Recall that this code is only run when <code>x.im</code> is\n  non-negative (but it runs for all values of <code>x.re</code>). So, \n  select the full range of values for <code>x.re</code>, but restrict\n  the range of <code>x.im</code>, like this: \n  \n  <figure>\n    <img width=\"100%\" src=\"range-input-2.png\" alt=\"Restricting the input range to xim >= 0.\" />\n  </figure>\n  \n  This asks Herbie to consider only non-negative\n  values of <code>xim</code> when improving the accuracy of this\n  expression.</p>\n  \n  <h2>Using Herbie's results</h2>\n\n  <p>Herbie will churn for a few seconds and produce an output,\n  perhaps something like this:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-prog2.png\" />\n    <figcaption>Herbie's version of the complex square root expression.</figcaption>\n  </figure>\n\n  <p>Herbie's algorithm is randomized, so you likely won't see the\n  exact same thing. For example, the branch expression <code>xre ≤\n  -4.780438341784697e-111</code> will probably have some other really\n  small number. And perhaps Herbie will choose slightly different\n  expressions. But the result should be recognizably similar. In this\n  case, Herbie reports that the initial expression had 38.7 bits of\n  error, and that the output has 29.4.</p>\n\n  <p>It's a little harder to describe what Herbie found wrong with the\n  original expression, and why its new version is better—it is due to\n  a floating-point phenomenon called “cancellation”. But you can get\n  some insight from the error plot just below the program block.\n  Select the <code>xim</code> variable just below the plot, and you\n  will see something like this:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-plot2.png\" />\n    <figcaption>Herbie's error plot for the complex square root expression.</figcaption>\n  </figure>\n\n  <p>There's a lot going on here. Along the horizontal axis, you have\n  the various values of <code>xim</code>. Note that the graph is\n  log-scale, and includes only non-negative values thanks to our\n  precondition. The value 1 is in the middle; to the left are values\n  with small exponents close to zero, and to the right you have values\n  with large exponents approaching infinity.</p>\n\n  <p>The vertical axis measures bits of error, from 0 to 64. Lower is\n  better. There are two lines drawn: a red one for the original\n  expression and a blue one for Herbie's version. You can see from the\n  plot that as <code>xim</code> gets smaller (toward the left, closer\n  to zero), Herbie's improvement becomes more and more significant.\n  You can also see that for very large values of <code>xim</code>, the\n  original program had maximal error (in fact, it overflows) but the\n  Herbie's version is better, though not great.</p>\n\n  <p>Of course, your exact output will differ a bit from the\n  screenshots and descriptions here, because Herbie is randomized.</p>\n\n  <p>Now that you have the more accurate version of this expression,\n    all you need to do is insert it back into the program:</p>\n\n  <pre>var r = Math.sqrt(x.re * x.re + x.im * x.im);\n// Herbie version of 0.5 * Math.sqrt(2.0 * (r + x.re))\nvar re;\nif (x.re &lt;= -4.780438341784697e-111) {\n    re = Math.abs(x.im) * Math.sqrt(0.5) / Math.sqrt(r - x.re);\n} else if (x.re &lt;= 1.857088496624289e-105) {\n    re = 0.5 * Math.sqrt(2.0 * (x.re + x.im));\n} else if (x.re &lt;= 117.16871373388169) {\n    re = 0.5 * Math.sqrt(2.0 * (r + x.re));\n} else if (x.re &lt;= 5.213930590364927e+88) {\n    re = 0.5 * Math.sqrt(2.0 * (x.re + x.im));\n} else {\n    re = 0.5 * Math.sqrt(2.0 * (x.re + x.re));\n}\nif (x.im &gt;= 0) {\n  return new Complex(\n      re,\n      0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}\nelse {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      -0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}</pre>\n\n  <p>Note that I've left the original code in place in a comment. As\n  Herbie gets better, you can re-run it on this original expression to\n  see if it comes up with improvements in accuracy.</p>\n\n  <p>By the way, for some languages, like C, you can use the drop-down\n  in the top-right corner of the gray program block to translate\n  Herbie's output to that language.</p>\n\n  <h2>Next steps</h2>\n\n  <p>With this change, we've made this part of the complex square root\n  function much more accurate, and we could repeat the same steps for\n  the other branches and other fields in this program. You now have a\n  pretty good understanding of Herbie and how to use it.\n  Please <a href=\"mailto:herbie@cs.washington.edu\">let us know</a> if\n  Herbie has helped you, and check out\n  the <a href=\"../../doc.html\">documentation</a> to learn more about\n  Herbie's various options and outputs.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.6/using-cli.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie from the Command Line</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Using Herbie from the Command Line</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>Herbie can be used from the command-line or\n  from <a href=\"using-web.html\">the browser</a>. This page covers\n  using Herbie from the command line.</p>\n\n  <h2 id=\"interactive\">The Herbie shell</h2>\n\n  <p>\n    The Herbie shell lets you interact with Herbie: you type in input\n    expressions and Herbie prints their more accurate versions. Run\n    the Herbie shell with this command:\n  </p>\n\n  <pre class=\"shell\">herbie shell\nHerbie 1.4 with seed 2098242187\nFind help on https://herbie.uwplse.org/, exit with Ctrl-D\n<strong>herbie&gt;</strong> </pre>\n\n\n  <p>\n    Herbie prints a seed, which you can <a href=\"options.html\">use to\n    reproduce</a> a Herbie run, and links you to documentation. Then,\n    it waits for inputs, which you can type directly into your\n    terminal in <a href=\"input.html\">FPCore format</a>:\n</p>\n\n  <pre><strong>herbie&gt;</strong> (FPCore (x) (- (+ 1 x) x))\n(FPCore\n  (x)\n  <var>...</var>\n  1.0)</pre>\n\n  <p>Herbie suggests that <code>1</code> is more accurate than the\n  original expression <code>(- (+ 1 x) x)</code>. The\n  the <var>...</var> elides \n  <a href=\"input.html#properties\">additional information</a> provided\n  by Herbie.</p>\n\n  <p>The Herbie shell makes it easy to play with different expressions\n  and try multiple variants, informed by Herbie's advice.</p>\n\n  <h2 id=\"batch\">Batch processing FPCores</h2>\n\n  <p>\n    Alternatively, you can run Herbie on a file with multiple\n    expressions in it, writing Herbie's versions of each to a file.\n    This mode is intended for use by scripts.\n  </p>\n\n  <pre class=\"shell\">herbie improve bench/tutorial.fpcore out.fpcore\nStarting Herbie on 3 problems (seed: 1809676410)...\n  1/3   [   1.799s]   39→ 0     Expanding a square\n  2/3   [   3.256s]    0→ 0     Commute and associate\n  3/3   [   0.937s]   29→ 0     Cancel like terms</pre>\n\n  <p>\n    The output file <code>out.fpcore</code> contains more accurate\n    versions of each program:\n  </p>\n\n  <pre>;; seed: 1809676410\n\n(FPCore (x) <var>...</var> 1.0)\n(FPCore (x) <var>...</var> (* x (+ x 2.0)))\n(FPCore (x y z) <var>...</var> 0.0)</pre>\n\n  <p>\n    Note that output file is in the same order as the input file. For\n    more control over Herbie, see the documentation of\n    Herbie's <a href=\"options.html\">command-line options</a>.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/1.6/using-web.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie from the Browser</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Using Herbie from the Browser</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> rewrites floating point expressions to\n    make them more accurate. Herbie can be used\n    from <a href=\"using-cli.html\">the command-line</a> or from the\n    browser; this page is about using Herbie from the browser.</p>\n\n\n  <h2 id=\"interactive\">The Herbie web shell</h2>\n\n  <p>\n    The Herbie web shell lets you interact with Herbie through your\n    browser, featuring a convenient input format. The web shell is the\n    friendliest and easiest way to use Herbie. Run the Herbie web\n    shell with this command:\n  </p>\n\n  <pre class=\"shell\">herbie web</pre>\n\n  <p>After a few seconds, the web shell will rev up and direct your\n  browser to Herbie:</p>\n  \n  <pre class=\"shell\">herbie web\nHerbie 1.6 with seed 841489305\nFind help on https://herbie.uwplse.org/, exit with Ctrl-C\nYour Web application is running at http://localhost:8000/.\nStop this program at any time to terminate the Web Server.</pre>\n\n  <figure>\n    <img width=\"100%\" src=\"web-main.png\" alt=\"A screenshot of the Herbie web shell main page.\"/>\n  </figure>\n\n  <p>\n    Type expressions in standard mathematical syntax (parsed\n    by <a href=\"http://mathjs.org\">Math.js</a>). For each input variable,\n    specify the range of values that Herbie should consider when trying \n    to improve the expression. Hit the \"Improve with Herbie\" button to have \n    Herbie attempt to improve the expression.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"web-progress.png\" />\n    <figcaption>Herbie shows improvement logs as it works.</figcaption>\n  </figure>\n\n  <p>\n    The web shell reports Herbie's progress and redirects to a\n    <a href=\"report.html\">report</a> once Herbie is done.\n  </p>\n\n  <p>\n    The web shell can also automatically save the generated reports,\n    and has <a href=\"options.html\">many other options</a> you might\n    want to explore.\n  </p>\n\n\n  <h2 id=\"batch\">Batch report generation</h2>\n\n  <p>A <a href=\"report.html\">report</a> can also be generated directly\n  from a file of <a href=\"input.html\">input expressions</a>:</p>\n  \n  <pre class=\"shell\">herbie report bench/tutorial.fpcore output/\nStarting Herbie on 3 problems (seed: 1809676410)...\n  1/3   [   1.799s]   39→ 0     Expanding a square\n  2/3   [   3.256s]    0→ 0     Commute and associate\n  3/3   [   0.937s]   29→ 0     Cancel like terms</pre>\n\n  <p>\n    This command asks Herbie to generate a report from the input\n    expressions in <code>bench/tutorial.fpcore</code> and to save the report in\n    the directory <code>output/</code>. It's best if that directory\n    doesn't exist before running this command.\n  </p>\n\n  <p>\n    Once generated, open <code>output/results.html</code> in your\n    favorite browser (but see <a href=\"faq.html\">the FAQ</a> if you're\n    using Chrome). That page summarizes Herbie's results for all\n    expression in your input file, and you can click on individual\n    expressions to see their report.\n  </p>\n\n  <p>Batch report generation is the most informative way to run Herbie\n  on a large collection of inputs. Like the web shell, it can be\n  customized through <a href=\"options.html\">command-line options</a>,\n  including parallelizing Herbie with multiple threads.</p>\n\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.0/api-endpoints.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Herbie HTTP API Endpoints</title>\n    <link rel='stylesheet' type='text/css' href='../../main.css'>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <script type=\"text/javascript\" src=\"toc.js\"></script>\n  </head>\n  <body>\n    <header>\n      <h1>HTTP API</h1>\n      <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n      <nav>\n        <ul>\n          <li><a href=\"../../demo/\">Try</a></li>\n          <li><a href=\"installing.html\">Install</a></li>\n          <li><a href=\"tutorial.html\">Learn</a></li>\n        </ul>\n      </nav>\n    </header>\n\n    <p>The <a href=\"../../\">Herbie</a> API allows applications to\n    interface with Herbie using HTTP requests. The API is designed to\n    be stateless: the order in which endpoints are called shouldn't\n    matter.</p>\n\n    <h2 id=\"all-endpoints-info\">Format for all endpoints</h2>\n\n    <p>All the endpoints listed below respond to POST requests unless\n    otherwise specified. A typical example of sending a POST request\n    to a running Herbie server is:</p>\n\n    <pre class=\"shell\">curl -X POST -d \\\n  '{\"formula\": \"(FPCore (x) (- (sqrt (+ x 1))))\",\\\n    \"seed\": 5})}' \\\n  -H 'Content-Type: application/json' \\\n  http://127.0.0.1:8000/api/sample\n    </pre>\n\n    <h2 id=\"sample\">/api/sample</h2>\n\n    <details>\n    <summary>Example input & output</summary>\n\n    <p>Request:</p>\n\n    <pre>{\n        formula: &lt;FPCore expression&gt;,\n        seed: &lt;random seed for point generation&gt;\n      }</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n        points: [[point, exact], ... ]\n      }</pre>\n    </details>\n\n    <p>The <code>sample</code> endpoint allows the user to request a\n    sample of points given the FPCore expression and a seed.</p>\n\n    <p>Returns a collection of points and the exact evaluation of each\n    point with the given spec. The results are returned through the\n    \"points\" field and are represented by an array of point-exact\n    pairs with the first value representing the point and the second\n    value representing the exact evaluation; the exact value of\n    point <code>n</code> is <code>points[n][1]</code>.</p>\n\n    <p>Herbie calculates the \"ground truth\" by calculating the values\n    with more precise numbers. This can be slow.</p>\n\n    <h2 id=\"exacts\">/api/exacts</h2>\n\n    <details>\n    <summary>Example input & output</summary>\n\n    <p>Request:</p>\n\n    <pre>{\n        formula: &lt;FPCore expression&gt;,\n        sample: [point, ... ]\n      }</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n        points: [[point, exact], ... ]\n      }</pre>\n    </details>\n\n    <p>The <code>exacts</code> endpoint allows the user to request the\n    exact value of a set of points evaluated at a real number\n    specification given as an FPCore expression.</p>\n\n    <p>Some points may not be calculable given the FPCore\n    expression.</p>\n\n    <p>Returns a collection of points and the exact evaluation of each\n    point with the given spec. The results are returned through the\n    \"points\" field and are represented by an array of point-exact\n    pairs with the first value representing the point and the second\n    value representing the exact evaluation; the exact value of\n    point <code>n</code> is <code>points[n][1]</code>.</p>\n\n    <p>Herbie calculates the \"ground truth\" by calculating the values\n    with more precise numbers. This can be slow.</p>\n\n    <h2 id=\"calculate\">/api/calculate</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n\n    <p>Request:</p>\n\n    <pre>{\n        formula: &lt;FPCore expression&gt;,\n        sample: [point ... ]\n      }</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n        points: [[point, exact], ... ]\n      }</pre>\n    </details>\n\n    <p>The <code>calculate</code> endpoint allows the user to request\n    the evaluation of a set of points evaluated at a floating-point\n    implementation given as an FPCore expression.</p>\n\n    <p>Some points may not be calculable given the FPCore expression.</p>\n\n    <p>Returns a collection of points and the evaluation of each point\n    using the given FPCore as a floating-point implementation. The\n    results are returned through the \"points\" field and are\n    represented by an array of point-exact pairs with the first value\n    representing the point and the second value representing the\n    evaluated value; the evaluated value of point <code>n</code>\n    is <code>points[n][1]</code>.</p>\n\n    <h2 id=\"analyze\">/api/analyze</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n\n    <p>Request:</p>\n\n    <pre>{\n  formula: &lt;FPCore expression&gt;,\n  sample: [[point, exact], ... ]\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n  points: [[point, error], ... ]\n}</pre>\n    </details>\n\n    <p>The <code>analyze</code> endpoint allows the user to request\n    error analysis of a set of point-exact pairs and a given\n    floating-point implementation.</p>\n\n    <p>Given a collection of points, their exact values, and an FPCore\n    expression to analyze on, the <code>analyze</code> endpoint\n    returns the error for each point for that expression. The error\n    value returned is Herbie's internal error heuristic.</p>\n\n    <h2 id=\"alternatives\">/api/alternatives</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n    <p>Request:</p>\n\n    <pre>{\n  formula: &lt;FPCore expression&gt;,\n  sample: [[point, exact], ... ]\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n  alternatives: [alt, ... ],\n  histories: [history, ... ],\n  splitpoints: [splitpoint, ... ]\n}</pre>\n    </details>\n\n    <p>The <code>alternatives</code> endpoint allows the user to\n    request rewrites from Herbie given an expression to rewrite and a\n    set of point-exact pairs.</p>\n\n    <p>Returns a list of alternatives represented by FPCore\n    expressions through the \"alternatives\" field.</p>\n\n    <p>Returns a list of derivations of each alternative through the\n    \"histories\" field where <code>history[n]</code> corresponds\n    to <code>alternatives[n]</code>.</p>\n\n    <p>Returns a list of splitpoints for each alternative through the\n    \"splitpoints\" field where <code>splitpoints[n]</code> corresponds\n    to <code>alternatives[n]</code>. <code>splitpoints[n]</code> will\n    only contain information about the corresponding alternative.s\n    splitpoints if the alternative is a branch-expression.</p>\n\n    <h2 id=\"mathjs\">/api/mathjs</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n    <p>Request:</p>\n\n    <pre>{\n  formula: &lt;FPCore expression&gt;\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n  mathjs: &lt;mathjs expression&gt;\n}</pre>\n    </details>\n\n    <p>The <code>mathjs</code> endpoint allows the user to translate\n    FPCore expressions into mathjs expressions.</p>\n\n    <h2 id=\"localerror\">/api/local-error</h2>\n    <!--TODO--> Forthcoming.\n\n\n    <h2 id=\"cost\">/api/cost</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n\n    <p>Request:</p>\n\n  <pre>{\n    formula: &lt;FPCore expression&gt;,\n    sample: [point ... ]\n}</pre>\n\n    <p>Response:</p>\n\n  <pre>{\n    cost: [cost]\n}</pre>\n\n    <p><b>Specific Example: sqrt(x+1)-sqrt(x)</b></p>\n\n    <p>Request:</p>\n\n  <pre>{\n    formula: &lt;(FPCore (x) (- (sqrt (+ x 1)) (sqrt x)))&gt;,\n    sample: [ [[1], -1.4142135623730951] ]\n}</pre>\n\n    <p>Response:</p>\n\n  <pre>{\n    cost: [13120]\n}</pre>\n\n    <p><b>Lower-Cost Example: (x+1)-(x)</b></p>\n\n    <p>Request:</p>\n\n  <pre>{\n    formula: &lt;(FPCore (x) (- (+ x 1 ) x))&gt;,\n    sample: [ [[1], -1.4142135623730951] ]\n}</pre>\n\n    <p>Response:</p>\n\n  <pre>{\n    cost: [320]\n}</pre>\n\n    </details>\n\n    <p>The <code>cost</code> endpoint allows the user to request\n    the evaluation of an expression's overall cost. Cost is \n    calculated depending on the complexity of operations contained\n    in the expression. </p>\n\n    <p>Given an FPCore expression and a collection of points,\n    returns the cost of the expression. The cost value returned \n    is calculated internally by Herbie.</p> \n    \n    <p>The points should be of the same format as the points \n    generated in the sample endpoint. Refer to /api/sample \n    for more details. </p>\n\n    <p>Note the sample points are not used in the cost calculation.\n    The contents of the points do not matter as long as they are\n    in the correct format as mentioned above.</p>\n\n    <!-- Translate Endpoint -->\n\n    <h2 id=\"translate\">/api/translate</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n\n    <p>Request:</p>\n\n  <pre>{\n    formula: &lt;FPCore expression&gt;,\n    language: \"language\"\n}</pre>\n\n    <p>Response:</p>\n\n  <pre>{\n    result: \"translated expression\"\n}</pre>\n\n    <p><b>Specific Example: sqrt(x+1)-sqrt(x)</b></p>\n\n    <p>Request:</p>\n\n  <pre>{\n    formula: &lt;(FPCore (x) (- (sqrt (+ x 1)) (sqrt x)))&gt;,\n    language: \"python\"\n}</pre>\n\n    <p>Response:</p>\n\n  <pre>{\n    result: \"def expr(x): return math.sqrt((x + 1.0)) - math.sqrt(x)\"\n}</pre>\n\n    </details>\n\n    <p>The <code>translate</code> endpoint allows users to translate\n    FPCore expressions into equivalent expressions in various programming\n    languages.</p>\n\n    <p>Given an FPCore expression and a target language, this endpoint\n      returns the translated expression in the specified language.\n      The language parameter should be a string representing the desired\n      programming language. The response includes the translated expression.</p>\n\n    <p>Currently supported languages are: <code>python</code>, <code>c</code>,\n    <code>fortran</code>, <code>java</code>, <code>julia</code>, <code>matlab</code>,\n    <code>wls</code>, <code>tex</code>, and <code>js</code>.</p>\n\n  </body>\n</html>\n"
  },
  {
    "path": "www/doc/2.0/diagrams.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Diagrams</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <script src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML\"></script>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Diagrams</h1>\n    <a href=\"../..\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <figure>\n    <img width=\"100%\" src=\"system-1.6.png\" alt=\"System diagram of Herbie\" />\n  </figure>\n\n  <p>\n    High-level system diagram of Herbie. It highlights Herbie's core architecture,\n      external libraries, and user interactions.\n    Basic flow: Herbie passes user input (expression, precondition, etc.) to the\n      mainloop (scheduler) which alternates between generate and test phases multiple times,\n      maintaining and improving a set of accurate expressions at each iteration.\n    Once the generate-and-test phase is complete, Herbie extracts either\n      one or many output expressions using an algorithm called regime inference.\n    Regime inference chooses the \"best\" (usually most accurate)\n      generated candidate expression or combines multple candidates,\n      each \"best\" on a smaller part of the input range, with a branch condition.\n  </p>\n  \n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.0/docker.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie on Docker</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Installing with Docker</h1>\n    <a href=\"../..\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> is available\n    through <a href=\"https://www.docker.com/\">Docker</a>, which is\n    sort of like a virtual machine. This page describes how to install\n    the <a href=\"https://hub.docker.com/r/uwplse/herbie\">official Docker\n    image</a> for Herbie.\n  </p>\n  \n  <p>\n    Herbie can also be <a href=\"installing.html\">installed from\n    package or source</a>. Herbie via Docker is only recommended if\n    you already have Docker experience.\n  </p>\n  \n  <h2>Installing Herbie via Docker</h2>\n\n  <p>\n    First, <a href=\"https://docs.docker.com/installation/\">install\n    Docker</a>. Docker supports Windows, macOS, and Linux. Depending\n    on how you install Docker, you may need to prefix\n    the <code>docker</code> commands with <code>sudo</code> or run them\n    as the administrative user.\n  </p>\n\n  <p>With Docker installed, you can run the <a href=\"using-cli.html\">Herbie shell</a> with:</p>\n\n  <pre>docker run -it uwplse/herbie shell</pre>\n  \n  <p>This will download the Herbie image and then run\n  its <a href=\"options.html\">shell tool</a>.</p>\n  \n  <p>Herbie in Docker is more limited; for example, it will not\n  recognize plugins installed outside the Docker container.</p>\n\n  <h2>Running the web interface</h2>\n\n  <p>\n    You can run the Herbie web server locally with\n\n  <pre class=\"shell\">docker run -it --rm -p 8000:80 uwplse/herbie</pre>\n\n    and access the server at <a href=\"http://localhost:8000\">http://localhost:8000</a>.\n    </p>\n    <p>\n      (Herbie's Docker image binds to port 80 by\n    default; this command uses the <code>-p &lt;hostport&gt;:80</code> option to expose Herbie on port 8000.)\n  </p>\n\n  <p>\n    If you are using the <code>--log</code>\n    or <code>--save-session</code> flags for the web shell,\n    you will also need to mount the relevant directories into the\n    Docker container using the <code>-v</code> Docker option, as in\n    the examples below.\n  </p>\n\n  <h2>Generating files and reports</h2>\n\n  <p>\n    To use Herbie in <a href=\"using-cli.html\">batch mode</a>, you will\n    need to mount the input in the Docker container. Do that with:\n  </p>\n  \n  <pre class=\"shell\">docker run -it --rm \\\n    -v <var>in-dir</var>:/in \\\n    -v <var>out-dir</var>:/out \\\n    -u $USER \\\n    uwplse/herbie improve /in/<var>in-file</var> /out/<var>out-file</var></pre>\n\n  <p>\n    In this command, you are asking Herbie to read input\n    from <var>in-file</var> in <var>in-dir</var>, and write output\n    to <var>out-file</var> in <var>out-dir</var>. The command looks\n    the same if you want Herbie to read input from a directory;\n    just leave <var>in-file</var> blank.\n  </p>\n\n  <p>\n    To generate reports from Herbie, you can run:\n  </p>\n\n  <pre class=\"shell\">docker run -it --rm \\\n    -v <var>in-dir</var>:/in \\\n    -v <var>out-dir</var>:/out \\\n    -u $USER \\\n    uwplse/herbie report /in/<var>in-file</var> /out/</pre>\n\n  <p>\n    As before, the input and output directories must be mounted inside\n    the Docker container. Note that both here and above, the user is\n    set to the current user. This is to ensure that the files Herbie creates\n    have the correct permissions set.\n  </p>\n\n  <h2>Building the Docker image</h2>\n\n  <p>This section is primarily of interest for the Herbie developers.</p>\n\n  <p>\n    Clone the repo and confirm that Herbie builds correctly\n    with <code>make install</code>.\n  </p>\n\n  <p>\n    Next, examine the Dockerfile and Makefile together. The Dockerfile\n    should follow a process exactly like the Makefile, except a clean\n    initial environment is assumed. The build may be split into 2 or\n    more stages to limit the size of the resulting image. Each stage\n    consists of a <code>FROM</code> command and a series of further\n    commands to build up the desired environment, and later stages can\n    refer to earlier stages by name&mdash;for example, <code>COPY\n    --from=earlier-stage ...</code> can copy files compiled in earlier\n    images. You may need to do things like bumping the version of Rust\n    used for binary compilation or the version of Racket used in\n    production, or adjusting paths to match the newest version of the\n    repo.\n  </p>\n\n  <p>Once you are ready to build, run this command from the repository root:</p>\n\n  <pre class=\"shell\">docker build -t uwplse/herbie:test .</pre>\n\n  <p>This builds a new test image and tags\n  it <code>uwplse/herbie:test</code>. You can run this image with:</p>\n\n  <pre class=\"shell\">docker run -p 8000:80 -it uwplse/herbie:test</pre>\n\n  <p>The web demo should now be visiable at <code>http://localhost:8000</code>.</p>\n  \n  <p>To open a shell in a running container for testing, first get the container ID with:</p>\n\n  <pre class=\"shell\">docker ps</pre>\n\n  <p>Then open a root shell in that container with</p>\n\n  <pre class=\"shell\">docker exec -it &lt;CONTAINER ID&gt; sh</pre>\n  \n  <p>The code and egg-herbie binaries should be\n  under <code>/src</code>.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.0/error.html",
    "content": "<!doctype html>\n<meta charset=\"utf-8\" />\n<title>Herbie Input Format</title>\n<link rel='stylesheet' type='text/css' href='../../main.css'>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<script type=\"text/javascript\" src=\"toc.js\"></script>\n\n<header>\n  <h1>What is Error?</h1>\n  <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n  <nav>\n    <ul>\n      <li><a href=\"../../demo/\">Try</a></li>\n      <li><a href=\"installing.html\">Install</a></li>\n      <li><a href=\"tutorial.html\">Learn</a></li>\n    </ul>\n  </nav>\n</header>\n\n<p>\n  <a href=\"../../\">Herbie</a> helps you identify and correct floating\n  point error in your numeric programs. But what is floating point\n  error, and how does Herbie measure it?\n</p>\n\n<h2>The summary</h2>\n\n<p>When Herbie reports a \"percentage accuracy\" number like 92.3%, it's\nusually best to think of that as the percentage of floating-point\ninputs where the expression is reasonably accurate.</p>\n\n<p>The impact of this error on your application will depend a lot\non <em>which</em> 7.7% of inputs are inaccurate, and what kind of\nerror that is. You can find this out using\nthe <a href=\"report.html\">accuracy graph in Herbie reports</a>. You\ncan also use preconditions to restrict the inputs Herbie is\nconsidering.</p>\n\n<h2>Why rounding matters</h2>\n\n<p>In mathematics, we work with real numbers, but on a computer, we\ntypically use floating-point numbers. Because there are infinitely\nmany real numbers, but only finitely many floating-point numbers, some\nreal numbers can't be accurately represented. This means that every\ntime you do an operation, the true result typically has to\nbe <em>rounded</em> to a representable one.</p>\n\n<p>Take an extreme example: the code <code>1e100 + 1</code>, which\nincrements a huge number in IEEE 754 double-precision floating-point.\nThere's an exact real-number answer, a one followed by 99 zeros and\nthen another 1, but the closest <em>floating-point</em> value is the\nsame as <code>1e100</code>.</p>\n\n<p>Errors like this can cause problems. In the example above, the\nanswers differ by one part per googol, which is pretty small. But the\nerror can grow. For example, since <code>1e100 + 1</code> rounds to\nthe same value as <code>1e100</code>, the larger computation\n\n<pre>(1e100 + 1) - 1e100</pre>\n\nreturns <code>0</code> instead of the correct answer, <code>1</code>.\nNow the difference is pretty stark, and can grow even bigger through\nlater operations.</p>\n\n<h2>Bits of error</h2>\n\n<p>There are lots of ways to <em>measure</em> how much rounding error\nthere is in a computation. Most people find the notions of absolute\nand relative error most intuitive, but Herbie internally uses a more\ncomplex notion called <em>bits of error</em>.</p>\n\n<p>The bits of error metric imagines you have a list of all of the\npossible floating-point numbers, from largest to smallest. In that\nlist, compare the floating-point value you computed to the one closest\nto the true answer. If they are the same, that's called 0 bits of\nerror; if they are one apart, that's called one bit of error; three\napart is two bits of error; and so on.</p>\n\n<p>In general, if the two floating-point values are <var>n</var> items\napart, Herbie says they have <code>log2(n + 1)</code> bits of error.\nValues like <code>0</code> and <code>-0</code> are treated as having 0\nbits of error, and <code>NaN</code> is considered to have the maximum\nnumber of bits of error against non-<code>NaN</code> values. While\nthere's all sorts of theoretical justifications, Herbie mainly uses\nthis error metric because we've found it to give the best\nresults. </p>\n\n<p>On a single input, the best way to interpret the \"bits of error\"\nmetric is that it tells you roughly how many bits of the answer,\nstarting at the end, are useless. With zero bits of error, you have\nthe best answer possible. With four bits, that's still pretty good\nbecause it's four out of 64. But with 40 or 50 bits of error, you're\ngetting less accuracy out of the computation than even a\nsingle-precision floating-point value. And it's even possible to have\nsomething like 58 or 60 bits of error, in which case even the sign and\nexponent bits (which in double-precision floating-point occupy the top\n12 bits of the number) are incorrect.</p>\n\n<h2>Percentage accuracy</h2>\n\n<p>Because different number representations have different numbers of\nbits, Herbie shows the percentage of bits that are accurate instead of\nthe bits of error. With double-precision floats, for example, 75%\naccurate means 16 bits of error.</p>\n\n<p>Bits of error measures the error of a computation for some specific\ninput. But usually you're interested in the error of a computation\nacross many possible inputs. Herbie therefore averages the accuracy\npercentage across many randomly-sampled valid inputs.</p>\n\n<p>Typically, inputs points are either very accurate or not accurate\nat all. So when computing percentage accuracy, Herbie's averaging a\nlot of points with near-100% accuracy and a lot of points with near-0%\naccuracy. In that sense, you can think of percentage accuracy as\nmeasuring mostly what percentage <em>of inputs</em> are accurate. If\nHerbie says your computation is 75% accurate what it's really saying\nis that about a quarter of inputs produce usable outputs.</p>\n\n<h2>Valid inputs</h2>\n\n<p>Since percentage accuracy averages over many points, it depends on\nwhat points it is averaging over, and how is samples among them.\nHerbie samples among <em>valid</em> inputs, uniformly distributed.</p>\n\n<p>Herbie considers an input valid if it is a floating-point value in\nthe appropriate precision and its true, real-number output 1) exists;\n2) satisfies the user's precondition; and 3) can be computed. Let's\ndive into each requirement.</p>\n\n<ol>\n  <li>An output can fail to exist for an input if that input does\n    something like divide by zero or take the square root of a\n    negative number. Then that input is invalid.</li>\n  <li>An input can fail to satisfy the user's precondition.\n    Preconditions can be basically anything, but most often they\n    specify a range of inputs. For example, if the precondition\n    is <code>(&lt; 1 x 2)</code>, then the input <code>x = 3</code> is\n    invalid.</li>\n  <li>Finally, and most rarely, Herbie can fail to compute the output\n    for a particular input. For example, the computation <code>(/ (exp\n    1e9) (exp 1e9))</code>, which divides two identical but gargantuan\n    numbers, does have an exact real-number answer (one), but Herbie\n    can't compute that exact answer because the intermediate steps are\n    too large. This input is also invalid.</li>\n</ol>\n\n<p>Herbie's percentage accuracy metric only averages over valid\npoints. This means that when you change your precondition, you change\nwhich points are valid, and that can change the percentage accuracy\nreported by Herbie. This is useful: if you know there's a rare error,\nbut Herbie thinks error is low, you can change your precondition to\nfocus on the points of interest.</p>\n\n<h2>Sampling inputs</h2>\n\n<p>When randomly sampling inputs, Herbie considers each valid input\nequally likely. Importantly, this does not mean that it uses a uniform\ndistribution, because floating-point values themselves are not\nuniformly distributed.</p>\n\n<p>For example, there are as many floating-point values between 1 and\n2 as there are between one and one half, because floating-point values\nuse an exponential encoding. But that means that if you're looking at\na computation where the input comes from the interval <kbd>[0.5,\n2]</kbd>, Herbie will weight the first third of that range twice as\nhigh as the other two thirds.</p>\n\n<p>This can produce unintuitive results, especially for intervals that\ncross 0. For example, in the interval <kbd>[0, 1]</kbd>, the second\nhalf of that interval (from one half to one) has a tiny proportion of\nthe weight (in double-precision floating-point, about 0.1%). If Herbie\ncan improve accuracy by a little bit between zero and one half, while\ndramatically reducing accuracy between one half and one, it will think\nthat that's an accuracy improvement. You might disagree.</p>\n\n<p>Unfortunately, there's no way for Herbie to intuit exactly what you\nmean, so understanding this error distribution is essential to\nunderstanding Herbie's outputs. For example, if Herbie reports that\naccuracy improved from 75% to 76%, it's essential to know: is the\nimprovement happening on inputs between one half and one, or\nbetween <code>1e-100</code> and <code>2e-100</code>? To answer this\nquestion, it's important to look over\nthe <a href=\"report.html\">reports and graphs</a> generated by\nHerbie.</p>\n"
  },
  {
    "path": "www/doc/2.0/faq.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie FAQ</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Common Errors and Warnings</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p><a href=\"../../\">Herbie</a> automatically transforms floating\n  point expressions into more accurate forms. This page troubleshoots\n  common Herbie errors, warnings, and known issues.</p>\n\n\n  <h2>Common errors</h2>\n\n  <p>\n    Herbie error messages refer to this second for additional\n    information and debugging tips.\n  </p>\n\n  <h3 id=\"invalid-syntax\">Invalid syntax</h3>\n\n  <p>\n    This error means you mis-formatted Herbie's input. Common errors\n    include misspelled function names and parenthesized expressions\n    that should not be parenthesized. For example, in\n    <code>(- (exp (x)) 1)</code>, the expression <code>x</code> is a\n    variable so shouldn't be parenthesized. <code>(- (exp x) 1)</code>\n    would be the correct way to write that expression.\n    The <a href=\"input.html\">input format</a> documentation has more\n    details on Herbie's syntax.\n  </p>\n\n  <h3 id=\"sample-valid-points\">Cannot sample enough valid points</h3>\n\n  <p>This error occurs when Herbie is unable to find enough valid\n  points. For example, the expression <code>(acos (+ 1000 x))</code>\n  is invalid unless <code>(&lt;= -1001 x -999)</code>, a rather narrow\n  range. The simplest fix is to increase\n  the <a href=\"options.html\"><code>--num-analysis</code> flag</a>.\n  Specifying the range of valid points as\n  a <a href=\"input.html#preconditions\">precondition</a> can also help.\n  </p>\n\n  <h3 id=\"no-valid-values\">No valid values</h3>\n\n  <p>This error indicates that your input has no valid inputs, usually\n  due to an overly restriction precondition. For example, the\n  precondition <code>(&lt 3 x 2)</code> excludes all inputs. The\n  solution is to fix the precondition or input program.</p>\n\n\n  <h2>Common warnings</h2>\n\n  <p>Herbie warnings refer to this section for explanations and common\n  actions to take.</p>\n  \n  <h3 id=\"inf-points\">Infinite outputs for <var>N</var>% of points.</h3>\n  \n  <p>\n    Sometimes, an input to your expression produces an output so large\n    that it's best represented by a floating-point infinity. For\n    example, <code>(exp 1000)</code> is over 10<sup>434</sup>, so it's\n    much larger than the largest floating-point value. Herbie raises\n    this warning when too many inputs (more than 20% of them) are this\n    large, because that usually indicates you should set a more\n    restrictive precondition.\n  </p>\n\n  <h3 id=\"ground-truth\">Could not determine a ground truth</h3>\n\n  <p>\n    Herbie raises this warning when some inputs require more than\n    10,000 bits to compute an exact ground truth. For example, to\n    compute <code>(/ (exp x) (exp x))</code> for very\n    large <code>x</code>, absurdly large numbers would be required.\n    Herbie discards such inputs and raises this warning. If you see\n    this warning, you should add a restrictive precondition, such\n    as <code>:pre (&lt; -100 x 100)</code>, to prevent large inputs.\n  </p>\n\n  <h3 id=\"value-to-string\">Could not uniquely print <var>val</var></h3>\n\n  <p>\n    Herbie will raise this warning when it needs more than 10,000 bits\n    to produce a string representation for a given value. This is\n    likely the result of a bug in a third-party plugin.\n  </p>\n\n  <h3 id=\"unsound-rules\">Unsound rule application detected</h3>\n  \n  <p>\n    Herbie uses a set of algebraic rewrite rules in order to simplify\n    expressions, but these rules can sometimes lead to a\n    contradiction. Herbie will automatically compensate for this, and\n    in most cases nothing needs to be done. However, Herbie may have\n    failed to simplify the output.\n  </p>\n\n  <h3 id=\"unused-variable\">Unused variable <var>var</var></h3>\n  \n  <p>\n    The input FPCore contains a variable that is not\n      used in the body expression.\n  </p>\n\n  <h3 id=\"strange-variable\">Strange variable <var>var</var></h3>\n  \n  <p>\n    The input expression contains a variable that is similar in name\n      to named constants, e.g. <var>e</var> instead of <var>E</var>.\n  </p>\n\n  <h2>Known bugs</h2>\n\n  <p>Bugs that cannot be directly fixed are documented in this section.</p>\n\n  <h3 id=\"chrome-missing-report\">Missing reports chart on Chrome</h3>\n\n  <p>\n    When using Chrome to view web pages on your local machine, Herbie\n    reports cannot draw the arrow chart due to security restrictions.\n    <a href=\"http://www.chrome-allow-file-access-from-file.com/\">Run\n    Chrome with <code>--allow-file-access-from-files</code></a> to fix\n    this error.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.0/input.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Input Format</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>The Input Format</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> uses\n    the <a href=\"http://fpbench.org\">FPCore</a> format to specify an\n    input program, and has extensive options for precisely describing\n    its context.\n  </p>\n\n  <h2>Math format</h2>\n\n  <p>The Herbie web shell takes input in a subset of\n  the <a href=\"https://mathjs.org/docs/expressions/syntax.html\">math.js\n  syntax</a>. The web shell automatically checks for syntax errors,\n  and provides a graphical user interface for specifying the input\n  domain. The web shell converts the mathematical expression and input\n  ranges into FPCore before sending it to Herbie.</p>\n  \n  <h2 id=\"sec1\">FPCore format</h2>\n\n  <p>Herbie's command-line and batch-mode tools\n  use <a href=\"http://fpbench.org\">FPCore</a> format to describe\n  mathematical expressions. FPCore looks like this:</p>\n\n  <pre>(FPCore (<var>inputs ...</var>) <var>properties ...</var> <var>expression</var>)</pre>\n  <pre>(FPCore <var>name</var> (<var>inputs ...</var>) <var>properties ...</var> <var>expression</var>)</pre>\n\n  <p>\n    Each <var>input</var> is a variable name, like <code>x</code>,\n    used in the <var>expression</var>. Properties are used to specify\n    additional information about the <var>expression</var>'s context.\n    If <var>name</var> is specified, the function can be referenced in\n    subsequent FPCore declarations in the file.\n  </p>\n\n  <p>\n    The expression is written in prefix form, with every function call\n    parenthesized, as in Lisp. For example, the formula for the\n    hypotenuse of a triangle with legs <i>a</i> and <i>b</i> is:\n  </p>\n\n  <pre>(FPCore (a b) (sqrt (+ (* a a) (* b b))))</pre>\n\n  <p>\n    The semicolon (<kbd>;</kbd>) character introduces a line comment.\n    We recommend the <code>.fpcore</code> file extension for Herbie input files.\n  </p>\n  \n  <h2>Supported functions</h2>\n  \n  <p>\n    Herbie supports all functions\n    from <a href=\"http://pubs.opengroup.org/onlinepubs/7908799/xsh/math.h.html\">math.h</a>\n    with floating-point-only inputs and outputs. The best supported\n    functions include:\n  </p>\n\n  <dl class=\"function-list\">\n    <dt><code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>, <code>fabs</code></dt>\n    <dd>The usual arithmetic functions</dd>\n    <dt><code>sqrt</code>, <code>cbrt</code></dt>\n    <dd>Square and cube roots</dd>\n    <dt><code>pow</code>, <code>exp</code>, <code>log</code></dt>\n    <dd>Various exponentiations and logarithms</dd>\n    <dt><code>sin</code>, <code>cos</code>, <code>tan</code></dt>\n    <dd>The trigonometric functions</dd>\n    <dt><code>asin</code>, <code>acos</code>, <code>atan</code>, <code>atan2</code></dt>\n    <dd>The inverse trigonometric functions</dd>\n    <dt><code>sinh</code>, <code>cosh</code>, <code>tanh</code></dt>\n    <dd>The hyperbolic functions</dd>\n    <dt><code>asinh</code>, <code>acosh</code>, <code>atanh</code></dt>\n    <dd>The inverse hyperbolic functions</dd>\n    <dt><code>fma</code>, <code>expm1</code>, <code>log1p</code>, <code>hypot</code></dt>\n    <dd>Specialized numeric functions</dd>\n  </dl>\n\n  <p>Herbie also supports the constants <code>PI</code>\n  and <code>E</code>. The arithmetic operators associate to the left,\n  and <code>-</code> is used for both subtraction and negation.</p>\n\n  <p>Herbie links against your computer's <code>libm</code> to\n  evaluate these functions. So, each function has the same behavior in\n  Herbie as in your code. You can instead use\n  the <a href=\"#precisions\"><code>racket</code> precision</a> if you\n  instead want reproducible behavior.</p>\n\n  <h2 id=\"conditionals\">Conditionals</h2>\n  \n  <p>FPCore uses <code>if</code> for conditional expressions:</p>\n\n  <pre>(if <var>cond</var> <var>if-true</var> <var>if-false</var>)</pre>\n\n  <p>\n    The conditional <code><var>cond</var></code> may use:\n  </p>\n  \n  <dl class=\"function-list\">\n    <dt><code>==</code>, <code>!=</code>, <code>&lt;</code>, <code>&gt;</code>, <code>&lt;=</code>, <code>&gt;=</code></dt>\n    <dd>The usual comparison operators</dd>\n    <dt><code>and</code>, <code>or</code>, <code>not</code></dt>\n    <dd>The usual logical operators</dd>\n    <dt><code>TRUE</code>, <code>FALSE</code></dt>\n    <dd>The two boolean values</dd>\n  </dl>\n\n  <p>The comparison functions support chained comparisons with more than two arguments.</p>\n\n  <h2 id=\"intermediates\">Intermediate variables</h2>\n  \n  <p>Intermediate variables can be defined\n    using <code>let</code> and <code>let*</code>:</p>\n\n  <pre>(let ([<var>variable</var> <var>value</var>] <var>...</var>) <var>body</var>)</pre>\n  <pre>(let* ([<var>variable</var> <var>value</var>] <var>...</var>) <var>body</var>)</pre>\n\n  <p>In both <code>let</code> and <code>let*</code>,\n  each <var>variable</var> is bound to its <var>value</var> and can be\n  used in the <var>body</var>. The difference between <code>let</code>\n  and <code>let*</code> is what order the values are\n  evaluated in:</p>\n\n  <dl>\n    <dt><code>let</code> expressions</dt>\n    <dd>In a <code>let</code> expression, all the values are evaluated\n      in parallel, before they are bound to their variables. This\n      means that later values can't refer to earlier variables in the\n      same <code>let</code> block.</dd>\n\n    <dt><code>let*</code> expressions</dt>\n    <dd>A <code>let*</code> block looks the same as a <code>let</code>\n      block, except the values are evaluated one at a time, and later\n      values can refer to earlier variables.</dd>\n  </dl>\n\n  <p>Unless you have a lot of Lisp experience, you'll probably\n  find <code>let*</code> more intuitive.</p>\n\n  <p>Internally, Herbie treats intermediate values only as a\n  notational convenience, and inlines their values before improving\n  the formula's accuracy. Using intermediate variables will therefore\n  not produce a more accurate result or help Herbie run faster.</p>\n\n  <h2 id=\"specs\">Specifications</h2>\n\n  <p>In some cases, your input program is an approximation of some\n  more complex mathematical expression. The <code>:spec</code> (for\n  “specification”) lets you specify the more complex ideal case.\n  Herbie will then try to modify the input program to make it more\n  accurately evaluate the specification.</p>\n\n  <p>For example, suppose you want to evaluate <code>sin(1/x)</code>\n  via a series expansion. Write:</p>\n\n  <pre>(FPCore (x)\n  :spec (sin (/ 1 x))\n  (+ (/ 1 x) (/ 1 (* 6 (pow x 3)))))</pre>\n\n  <p>Herbie will only use the <code>:spec</code> expression to\n  evaluate error, not to search for accurate expressions.</p>\n\n  <h2 id=\"preconditions\">Preconditions</h2>\n\n  <p>By default, the arguments to formulas are assumed to be\n  arbitrarily large or small floating-point numbers. However, in most\n  programs a smaller range of argument values is possible.\n  The <code>:pre</code> property (for “precondition”) describes this\n  smaller range.</p>\n\n  <p>Preconditions use comparison and boolean operators, just\n  like <a href=\"#conditionals\">conditional statements</a>:</p>\n\n  <pre>(FPCore (x) :pre (&lt; 1 x 10) (/ 1 (- x 1)))</pre>\n\n  <p>Herbie is particularly efficient when when the precondition is\n  an <code>and</code> of ranges for each variable, but more complex\n  preconditions also work.</p>\n\n  <h2 id=\"precisions\">Precisions</h2>\n\n  <p>Herbie supports both single- and double-precision values; you can\n  specify the precision with the <code>:precision</code> property:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>binary32</code></dt>\n    <dd>Single-precision IEEE-754 floating point</dd>\n    <dt><code>binary64</code></dt>\n    <dd>Double-precision IEEE-754 floating point</dd>\n    <dt><code>racket</code></dt>\n    <dd>Like <code>binary64</code>, but using Racket math functions\n      rather than your computer's <code>libm</code>.</dd>\n  </dl>\n\n  <p>By default, <code>binary64</code> is assumed. Herbie also has\n  a <a href=\"plugins.html\">plugin system</a> to load additional\n  precisions.</p>\n\n  <p>Herbie won't produce mixed-precision code unless you allow it to\n  do so, using the <code>:herbie-conversions</code> property:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>:herbie-conversions<br/>([<var>prec1</var> <var>prec2</var>] ...)</code></dt>\n    <dd>Expressions in precision <code>prec1</code>, can be rewriten\n    to use precision <code>prec2</code>, and vice versa.</dd>\n  </dl>\n\n  <p>All conversions are assumed to be bidirectional. For example, if\n  you specify <code>:herbie-conversions ([binary64 binary32])</code>,\n  Herbie will be able to add conversions between single- and\n  double-precision floating-point.</p>\n\n  <h2 id=\"properties\">Miscellaneous Properties</h2>\n\n  <p>Herbie uses the <code>:name</code> property to name FPCores in\n  its UI. Its value ought to be a string.</p>\n\n  <p>Herbie's output provide additional information in custom\n  properties:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>:herbie-status <var>status</var></code></dt>\n    <dd><var>status</var> describes whether Herbie worked: it is one\n    of <code>success</code>, <code>timeout</code>, <code>error</code>,\n    or <code>crash</code>.</dd>\n    <dt><code>:herbie-time <var>ms</var></code></dt>\n    <dd>The time, in milliseconds, used by Herbie to find a more accurate formula.</dd>\n    <dt><code>:herbie-error-input<br/>([<var>pts</var> <var>err</var>] ...)</code></dt>\n    <dd>The average <var>err</var>or of the input program at <var>pts</var> points. Multiple entries correspond to Herbie's training and test sets.</dd>\n    <dt><code>:herbie-error-output<br/>([<var>pts</var> <var>err</var>] ...)</code></dt>\n    <dd>The computed average error of the output program, similar to <code>:herbie-error-input</code>.</dd>\n  </dl>\n\n  <p>Herbie's benchmark suite also uses properties such\n  as <code>:herbie-target</code> for continuous integration, but these\n  are not officially supported and their use is discouraged.</p>\n  \n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.0/installing.html",
    "content": "<!doctype html>\n<html>\n\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Installing Herbie</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n\n<body>\n  <header>\n    <h1>Installing Herbie</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> supports Linux, macOS, and Windows \n    (though, on Windows, you will need to <a href=\"https://stackoverflow.com/questions/32127524/how-to-install-and-use-make-in-windows\">install Make</a>). It\n    can be installed from a package or from source. To start, install\n    <a href=\"https://racket-lang.org\">Racket</a>, which Herbie is\n    written in. Then install Herbie. (Herbie can also be installed\n    from source or via a <a href=\"docker.html\">Docker image</a>.)\n  </p>\n\n  <h2>Installing Racket</h2>\n\n  <p>\n    Install Racket either using\n    the <a href=\"http://download.racket-lang.org/racket-v8.9.html\">official\n      installer</a> or distro-provided packages. Versions as old as 8.0\n    are supported, but more recent versions are faster.\n  </p>\n\n  <p>\n    Please note: on Linux, we recommend the official Racket installer\n    over installing Racket via Snap. If you must install Racket from\n    Snap, make sure Herbie and all packages are located in your home\n    directory or another allow-listed directory.\n  </p>\n\n  <p>\n    Test that Racket is installed correctly and has a correct version:\n  </p>\n\n  <pre class=\"shell\">racket\nWelcome to Racket v8.9 [cs].\n> (exit)</pre>\n\n  <h2>Installing Herbie from a package</h2>\n\n  <p>\n    This installation method supports Windows, macOS, and Linux for\n    x86-64. It won't work for ARM computers, including recent Apple\n    computers. You may also need a working version\n    of <code>make</code>; on Windows, that might have to be installed\n    separately.</p>\n\n  <p>First install Racket, as above. Then install Herbie from a package with:</p>\n\n  <pre class=\"shell\">raco pkg install --auto herbie</pre>\n\n  <!-- This is a copy of the text above -->\n\n  <p>\n    This command installs Herbie and its dependencies, compiles it for\n    faster startup, and places the <code>herbie</code> executable in\n    your Racket user path (example paths for Racket 8.9):\n  </p>\n\n  <ul>\n    <li>On Windows, <code>AppData\\Roaming\\Racket\\8.9\\bin</code> in your user folder.</li>\n    <li>On macOS, <code>Library/Racket/8.9/bin</code> in your home folder.</li>\n    <li>On Linux, <code>.local/share/racket/8.9/bin</code> in your home directory.</li>\n  </ul>\n\n  <p>\n    You can run <code>herbie</code> from that directory, or add it to\n    your executable path. Please note that the path of the binary will\n    be different on Linux if you have opted to use Snap. Once Herbie\n    is installed and working correctly, check out\n    the <a href=\"tutorial.html\">tutorial</a>.\n  </p>\n\n  <!-- End of copy -->\n\n  <h2>Installing Herbie from source</h2>\n  \n  <p>\n    Installing Herbie from source is best if you plan to develop\n    Herbie or Herbie <a href=\"plugins.html\">plugins</a>, or if you are\n    on an ARM machine.</p>\n\n  <p>\n    Install Racket.\n    Then install Rust, using <a href=\"https://rustup.rs/\">rustup</a> or via some other means.\n    Versions as old as 1.60.0 are supported.\n  </p>\n\n  <p>\n    Once Racket and Rust are installed, download the Herbie source\n    <a href=\"https://github.com/uwplse/herbie\">from GitHub</a> with:\n  </p>\n\n  <pre class=\"shell\">git clone https://github.com/uwplse/herbie</pre>\n\n  <p>\n    Change to the <code>herbie</code> directory;\n    you should see a <code>README.md</code> file, a directory named <code>src</code>,\n    a directory named <code>bench/</code>, and a few other directories.\n    Install Herbie on your system with:\n  </p>\n\n  <pre class=\"shell\">make install</pre>\n\n  <p>\n    This command installs Herbie and its dependencies, compiles it for\n    faster startup, and places the <code>herbie</code> executable in\n    your Racket user path, just like the package installation.\n    Once Herbie is installed and working correctly, check out\n    the <a href=\"tutorial.html\">tutorial</a>.\n  </p>\n\n  <h2>Installing Herbie with Docker</h2>\n\n  <p>\n    <a href=\"https://docker.com\">Docker</a> is a container manager,\n    which is sort of like a virtual machine. Herbie in Docker is more\n    limited; we do not recommend using Herbie through Docker without\n    prior Docker experience.\n  </p>\n\n  <p>\n    The <a href=\"docker.html\">Docker documentation</a> describes how\n    to install and run the official <code>uwplse/herbie</code> image.\n  </p>\n\n</body>\n\n</html>\n"
  },
  {
    "path": "www/doc/2.0/options.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Command-line Options</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Command-line Options</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>The <a href=\"../../\"><code>herbie</code></a> command has\n  subcommands and options that influence both its user interface and\n  the quality of its output.</p>\n\n  <h2>Herbie commands</h2>\n\n  <p>There are a few different methods for interacting with Herbie, which we call\n  tools. For example, Herbie can be run both interactively or in batch mode, and\n  can generate output intended for the <a href=\"using-cli.html\">command line</a>\n  or for <a href=\"using-web.html\">the web</a>. Herbie provides four of these\n  tools as subcommands:<p>\n\n  <dl>\n    <dt><code>herbie web</code></dt>\n    <dd>Use Herbie <a href=\"using-web.html\">through your browser</a>.\n    The <code>herbie web</code> command runs Herbie on your local\n    machine and opens its main page in your browser.</dd>\n\n    <dt><code>herbie shell</code></dt>\n    <dd>Use Herbie <a href=\"using-cli.html\">via a command-line shell</a>.\n    Enter an <a href=\"input.html\">FPCore expression</a> and Herbie\n    will print its more-accurate version.</dd>\n\n    <dt><code>herbie improve <var>input</var> <var>output</var></code></dt>\n    <dd>Run Herbie on the expressions in the file or\n    directory <var>input</var>. The results are written\n    to <var>output</var>, a single file in FPCore format.</dd>\n\n    <dt><code>herbie report <var>input</var> <var>output</var></code></dt>\n    <dd>Run Herbie on the expressions in the file or\n    directory <var>input</var>. The results are written\n    to <var>output</var>, a directory of\n    HTML <a href=\"report.html\">reports</a>. These pages can be viewed\n    in any browser (though with a <a href=\"faq.html#chrome-missing-report\">quirk</a>\n    for Chrome).</dd>\n  </dl>\n\n  <p>We recommend using <code>report</code> and <code>web</code>,\n  which produce <a href=\"report.html\">reports</a> with lots of\n  information about floating-point accuracy, including graphs of input values\n  versus error and plots comparing cost and accuracy. This can help you\n  understand whether Herbie's improvements matter for your use case.</p>\n\n  <p>Use <code>herbie <var>tool</var> --help</code> to view available\n  command-line options for a tool. This command also shows unsupported\n  options not listed on this page.</p>\n\n  <h2>General options</h2>\n\n  <p>\n    These options can be set on any tool. Pass them after the tool\n    name but before other arguments, like this:\n  </p>\n\n  <pre class=\"shell\">herbie report --timeout 60 in.fpcore out/</pre>\n\n  <p>Arguments cannot go before options.</p>\n\n  <dl>\n    <dt><code>--seed S</code></dt>\n    <dd>The random seed, which changes the randomly-selected points\n      that Herbie evaluates candidate expressions on. The seed is a\n      number between 0 and 2<sup>31</sup> (exclusive both ends). This\n      option can be used to make Herbie's results reproducible or to\n      compare two different runs. Seeds are not preserved across\n      runs.</dd>\n\n    <dt><code>--num-points N</code></dt>\n    <dd>The number of input points Herbie uses to evaluate candidate\n      expressions. The default, 256, is a good balance for most\n      programs. Increasing this option, say to 512 or 1024, will slow\n      Herbie down but may make its results more consistent.</dd>\n\n    <dt><code>--num-iters N</code></dt>\n    <dd>The number of times Herbie attempts to improve accuracy. The\n      default, 4, suffices for most programs and helps keep Herbie\n      fast; in practice iterations beyond the first few rarely lead to\n      lower error. Increase this option, say to 6, to check that there\n      aren't further improvements that Herbie could seek out.</dd>\n\n    <dt><code>--num-analysis N</code></dt>\n    <dd>The number of input subdivisions to use when searching for\n      valid input points. The default is 12. Increasing this option\n      will slow Herbie down, but may fix the\n      \"<a href=\"faq.html#sample-valid-points\">Cannot sample enough\n      valid points</a>\" error.</dd>\n    \n    <dt><code>--num-enodes N</code></dt>\n    <dd>The number of equivalence graph nodes to use when doing\n    algebraic reasoning. The default is 8000. Increasing this option\n    will slow Herbie down, but may improve results slightly.</dd>\n    \n    <dt><code>--timeout T</code></dt>\n    <dd>The timeout to use per-input, in seconds. A fractional number\n      of seconds can be given.</dd>\n\n    <dt><code>--threads N</code> (for the <code>improve</code> and <code>report</code> tools)</dt>\n    <dd>Enables multi-threaded operation. By default, no threads are\n      used. A number can be passed to this option to use that many\n      threads, or <code>yes</code> can be passed to tell Herbie to use\n      all of the hardware threads.</dd>\n\n    <dt><code>--no-pareto</code></dt>\n    <dd>Disables cost-aware search. Herbie will only return a single\n    program, which optimizes exclusively for accuracy. Herbie will be\n    slightly faster as a result.</dd>\n  </dl>\n\n  <h2>Web shell options</h2>\n  \n  <p>The <code>web</code> tool runs Herbie and connects to it from\n  your browser. It has options to control the underlying web\n  server.</p>\n  \n  <dl>\n    <dt><code>--port N</code></dt>\n    <dd>The port the Herbie server runs on. The default port is 8000.</dd>\n\n    <dt><code>--save-session dir</code></dt>\n    <dd>Save all the reports to this directory. The directory also\n    caches previously-computed expressions.</dd>\n\n    <dt><code>--log file</code></dt>\n    <dd>Write an access log to this file, formatted like an Apache\n    log. This log does <em>not</em> contain crash tracebacks.</dd>\n\n    <dt><code>--quiet</code></dt>\n    <dd>By default, but not when this option is set, a browser is\n    automatically started to show the Herbie page. This option also\n    shrinks the text printed on start up.</dd>\n\n    <dt><code>--public</code></dt>\n    <dd>When set, users on other computers can connect to the demo and\n    use it. (In other words, the server listens\n    on <code>0.0.0.0</code>.). Essential when Herbie is run\n    from <a href=\"docker.html\">Docker</a>.</dd>\n  </dl>\n\n  <h2>Rulesets</h2>\n\n  <p>\n    Herbie uses rewrite rules to change programs and improve accuracy.\n    The <code>--disable rules:<var>group</var></code>\n    and <code>--enable rules:<var>group</var></code> options turn rule\n    sets on and off. In general, turning a ruleset on makes Herbie\n    produce more accurate but more confusing programs.\n  </p>\n\n  <p>The full list of rule groups is:</p>\n\n  <table class=\"function-list\">\n    <thead><tr><th>Rule Group</th><th>Topic of rewrite rules</th></tr></thead>\n    <tr><td>arithmetic</td><td>Basic arithmetic facts</td></tr>\n    <tr><td>polynomials</td><td>Factoring and powers</td></tr>\n    <tr><td>fractions</td><td>Fraction arithmetic</td></tr>\n    <tr><td>exponents</td><td>Exponentiation identities</td></tr>\n    <tr><td>trigonometry</td><td>Trigonometric identities</td></tr>\n    <tr><td>hyperbolic</td><td>Hyperbolic trigonometric identities</td></tr>\n    <tr><td>bools</td><td>Boolean operator identities</td></tr>\n    <tr><td>branches</td><td><code>if</code> statement simplification</td></tr>\n    <tr><td>special</td><td>The gamma, Bessel, and error functions</td></tr>\n    <tr><td>numerics</td><td>Numerical compounds <code>expm1</code>, <code>log1p</code>, <code>fma</code>, and <code>hypot</code></td></tr>\n  </table>\n\n  <h2>Search options</h2>\n\n  <p>\n    These options change the types of transformations that Herbie uses\n    to find candidate programs. We recommend sticking to the defaults.\n  </p>\n\n  <p>\n    Each option can be turned off with the <code>-o</code>\n    or <code>--disable</code> command-line flag and on with\n    <code>+o</code> or <code>--enable</code>. Turning an option off\n    typically results in less-accurate results, while turning a option\n    on typically results in more confusing output expressions.\n  </p>\n\n  <dl>\n    <dt><code>setup:search</code></dt>\n    <dd>This option, on by default, uses interval subdivision search\n    to help compute ground truth for complicated expressions. If\n    turned off, Herbie will be slightly faster, but may hit the\n    \"<a href=\"faq.html#sample-valid-points\">Cannot sample enough valid\n    points</a>\" error more often. Instead of turning this option off,\n    you may want to adjust the <kbd>--num-analysis</kbd> flag\n    instead.</dd>\n\n    <dt><code>setup:simplify</code></dt>\n    <dd>This option, on by default, simplifies the expression before\n    starting the Herbie improvement loop. If turned off, Herbie's\n    results will likely be somewhat worse, but its output program may\n    be more similar to the input program.</dd>\n\n    <dt><code>generate:rr</code></dt>\n    <dd>This option, on by default, uses Herbie's recursive rewriting\n    algorithm to generate candidate programs. If turned off, Herbie\n    will use a non-recursive rewriting algorithm, which will\n    substantially limit Herbie's creativity.</dd>\n\n    <dt><code>generate:taylor</code></dt>\n    <dd>This option, on by default, uses series expansion to produce\n    new candidates during the main improvement loop. If turned off,\n    Herbie will not use series expansion. If turned off, Herbie's\n    results will more likely be algebraically equivalent to the input\n    expression, but may be less accurate.</dd>\n\n    <dt><code>generate:simplify</code></dt>\n    <dd>This option, on by default, simplifies candidates during the\n    main improvement loop. If turned off, candidates will not be\n    simplified, which typically results in much less accurate\n    expressions.</dd>\n\n    <dt><code>generate:proofs</code></dt>\n    <dd>This option, on by default, generates step-by-step derivations\n    for HTML reports. If turned off, the step-by-step derivations will\n    be absent, and Herbie will be slightly faster.</dd>\n\n    <dt><code>reduce:regimes</code></dt>\n    <dd>This option, on by default, uses Herbie's regime inference\n    algorithm to branch between several program candidates. If turned\n    off, branches will not be inferred and the output program will be\n    straight-line code (if the input was). Turn this option off if\n    your programming environment makes branches very expensive, such\n    as on a GPU.</dd>\n\n    <dt><code>reduce:avg-error</code></dt>\n    <dd>This option, on by default, causes Herbie to output the\n    candidate with the best average error over the chosen inputs. If\n    turned off, Herbie will choose the candidate with the least\n    maximum error instead. This usually produces programs with worse\n    overall accuracy. Turn this option off if worst-case accuracy is\n    more important to you than overall accuracy.</dd>\n\n    <dt><code>reduce:binary-search</code></dt>\n    <dd>This option, on by default, uses binary search to refine the\n    values used in inferred branches. If turned off, different runs of\n    Herbie will be less consistent, and accuracy near branches will\n    suffer.</dd>\n\n    <dt><code>reduce:branch-expressions</code></dt>\n    <dd>This option, on by default, allows Herbie to branch on\n      expressions, not just variables. This slows Herbie down,\n      particularly for large programs. If turned off, Herbie will only\n      try to branch on variables.</dd>\n  </dl>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.0/plugins.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Plugins</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Plugins</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p><a href=\"../../\">Herbie</a> plugins define new functions, add\n  rewrite rules, and even implement number representations.</p>\n\n  <p>Herbie plugins are installed separately. Herbie then\n  automatically loads and uses them.</p>\n  \n  <h2>Posit arithmetic</h2>\n\n  <p>The <kbd>softposit-herbie</kbd> plugin implements support\n  for <a href=\"https://posithub.org/\">posit</a> arithmetic. Install it\n  with:</p>\n\n  <pre class=\"shell\">raco pkg install --auto softposit-herbie</pre>\n\n  <p>This plugin uses the SoftPosit library, only supported on Linux.\n  Even then is reported to misbehave on some machines. The plugin\n  support arithmetic operations, <code>sqrt</code>, and quires.</p>\n\n  <p>Once <kbd>softposit-herbie</kbd> is installed,\n  specify <code>:precision posit16</code> to inform Herbie that it\n  should assume the core's inputs and outputs are posit numbers. Other\n  posit sizes (with 8 or 32 bits) and also quires (for 8, 16, and 32\n  bit posits) are available, but are poorly supported.</p>\n\n\n  <h2 id=\"complex\">Complex numbers</h2>\n\n  <p>The <kbd>complex-herbie</kbd> plugin has been removed as of Herbie 1.6.\n    This plugin may be brought back in the future.\n\n  <h2 id=\"complex\">Generic floating-point numbers</h2>\n\n  <p>The <kbd>float-herbie</kbd> plugin implements support for any IEEE-754\n    binary floating-point number. To install, check out the\n    <a href=\"https://github.com/bksaiki/float-herbie\">source code</a>\n    and run\n  </p>\n\n  <pre class=\"shell\">raco pkg install</pre>\n\n  <p>\n    at the top-level directory of the repository.\n    Once <kbd>float-herbie</kbd> is installed,\n    specify <code>:precision (float <i>ex</i> <i>nb</i>)</code>\n    to inform Herbie that it should assume the core's inputs and outputs are\n    floating-point numbers with <i>ex</i> exponent bits and <i>nb</i> total bits\n    (sign bit + mantissa bits + exponent bits).\n  </p>\n\n  <h2 id=\"complex\">Generic fixed-point numbers</h2>\n\n  <p>The <kbd>fixedpoint-herbie</kbd> plugin implements support for any fixed-point number.\n    To install, check out the\n    <a href=\"https://github.com/bksaiki/fixedpoint-herbie\">source code</a>\n    and run\n  </p>\n\n  <pre class=\"shell\">raco pkg install</pre>\n\n  <p>\n    at the top-level directory of the repository.\n    Once <kbd>fixedpoint-herbie</kbd> is installed,\n    specify <code>:precision (fixed <i>nb</i> <i>sc</i>)</code>\n    to inform Herbie that it should assume the core's inputs and outputs are\n    signed fixed-point numbers with <i>nb</i> total bits and a scaling factor of\n    2<sup><i>sc</i></sup> (integer formats have a scaling factor of 2<sup>0</sup>).\n    This plugin also supports unsigned fixed-point numbers specified by\n    <code>:precision (ufixed <i>nb</i> <i>sc</i>)</code> and provides\n    simpler aliases for integer formats with <code>:precision (integer <i>nb</i>)</code>\n    and <code>:precision (uinteger <i>nb</i>)</code>.\n  </p>\n  \n  <h2>Developing plugins</h2>\n\n  <p>The following is a guide to creating a Herbie plugin.\n  Plugins are considered experimental and may change considerably\n  between releases.\n  If you run into issues, please \n  <a href=\"https://github.com/uwplse/herbie/issues\">file a bug</a>.\n  Be sure to check out the <a href=\"https://github.com/herbie-fp/herbie/tree/main/src/reprs\">\n  built-in plugins</a> in the Herbie repository before getting started.</p>\n\n  <p><b>First Steps</b><br>\n\n  All plugins are implemented as Racket packages. The easiest way to\n  initialize a new Racket package is to run\n\n  <pre class=\"shell\">raco pkg new <i>pkg-name</i></pre>\n\n  in a new folder. Make sure the folder name is the same as the package name!\n  This will initialize a Racket package with all the necessary files.\n  Read the official Racket documentation on the\n  <a href=\"https://docs.racket-lang.org/pkg/getting-started.html#%28part._how-to-create%29\">\n  raco</a> tool for more information.</p>\n\n  <p>A single entry needs to be added to the package manifest stored in <code>info.rkt</code>,\n  and add <code>(define herbie-plugin '<i>name</i>)</code> to the bottom of the file\n  where <i>name</i> is a unique symbol that doesn't conflict with other Herbie plugins.\n  As a suggestion, this should just be the package name.</p>\n\n  <p>Next, edit the <code>main.rkt</code> file by erasing everything except the\n  language specifier on the first line, and add the line <code>(require herbie/plugin)</code>.\n  This gives the package access to the Herbie plugin interface.\n  Optionally add the following for debugging purposes\n  <code>(eprintf \"Loading <i>pkg-name</i> support...\\n\")</code>\n  directly after the <i>require</i> statement.</p>\n\n  <p>Finally, run the following in the folder containing <code>info.rkt</code>\n  and <code>main.rkt</code>:\n\n  <pre class=\"shell\">raco pkg install</pre>\n\n  This should install your package and check for errors.\n  Now everything is set up!\n  Of course, your plugin is empty and doesn't add any useful features.\n  If you added the debugging line in <code>main.rkt</code>, you should see the string\n  when you run Herbie.\n  </p>\n\n  <p><b>Adding Features</b><br>\n  \n  Now that you have an empty plugin, you can begin adding new functions, rewrite\n  rules, and number representatons.\n  The procedures exported by the Herbie plugin interface can be roughly divided into\n  two categories: unique and parameterized.\n  Whether or not you use the unique or parameterized half of the interface\n  (or maybe both!) depends entirely on the number representation a feature is being\n  implemented for.\n  First, identify if your number representation is unique or parameterized.\n  For example, if you are adding features for <code>double</code> precision\n  (or rather <code>binary64</code>), the representation is unique.\n  If you are adding features for a generic floating point format, say\n  <code>(float <i>ebits</i> <i>nbits</i>)</code>, then the representation is parameterized.</p>\n\n  <p><b>Plugin Interface (Unique)</b><br>\n\n  The following are the signatures and descriptions of the\n  plugin procedures for unique representations.\n  These procedures are required to be at the top-level of\n  <code>main.rkt</code> rather than inside a function.</p>\n\n  <dl>\n    <dt>\n      <code>(<b>define-type</b> <i>name</i> (<i>exact?</i> <i>inexact?</i>)\n                         <i>exact->inexact</i> <i>inexact->exact</i>)</code>\n    </dt>\n    <dd>Adds a new type with the unique identifier <code><i>name</i></code>.\n      The arguments <code><i>exact?</i></code> and <code><i>inexact?</i></code>\n      return true if a value is an exact or high-precision approximate representation.\n      For Herbie's <code>real</code> type, <code><i>exact?</i></code> is implemented\n      with <code>real?</code> and <code><i>inexact?</i></code> is implemented\n      with <code>bigfloat?</code>. The procedures <code><i>exact->inexact</i></code> and\n      <code><i>inexact->exact</i></code> convert between <code><i>exact?</i></code>\n      and <code><i>inexact?</i></code> values.\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-representation</b> (<i>name</i> <i>type</i> <i>repr?</i>)</td>\n                     <td><i>bigfloat->repr</i></td></tr>\n        <tr><td></td><td><i>repr->bigfloat</i></td></tr>\n        <tr><td></td><td><i>ordinal->repr</i></td></tr>\n        <tr><td></td><td><i>repr->ordinal</i></td></tr>\n        <tr><td></td><td><i>width</i></td></tr>\n        <tr><td></td><td><i>special?</i>)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Adds a new representation with the unique identifier <code><i>name</i></code>.\n      The representation will inherit all rewrite rules defined for <code><i>type</i></code>.\n      By default, Herbie defines two types: <code>real</code> and <code>bool</code>.\n      Your representation will most likely inherit from <code>real</code>.\n      The <code><i>width</i></code> argument should be the bitwidth of the representation,\n      e.g. 64 for <code>binary64</code>.\n      The argument <code><i>repr?</i></code> is a procedure that accepts any argument and returns\n      true if the argument is a value in the representation, e.g. an integer representation\n      should use Racket's <code>integer?</code>, while <code><i>special?</i></code> takes a\n      value in the representation and returns true if it is not finite, e.g. NaN or infinity.<br><br>\n\n      The other four arguments are single-argument procedures that implement different conversions.\n      The first two convert between a value in your representation and a Racket\n      <a href=\"https://docs.racket-lang.org/math/bigfloat.html\">bigfloat</a>\n      (you need to import <code>math/bigfloat</code>).\n      The last two convert between a value in your representation and its corresponding ordinal value.\n      Ordinal values for any representation must be within the interval [0, 2<sup><i>width</i></sup> - 1].\n      Check Racket's definition of\n      <a href=\"https://docs.racket-lang.org/math/flonum.html?q=ordinal#%28def._%28%28lib._math%2Fflonum..rkt%29._flonum-~3eordinal%29%29\">\n      ordinals</a> for floats.\n      Note that those ordinal values can be negative.\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-operator</b> (<i>name</i> <i>itype-names ...</i>)</td><td> otype-name</td></tr>\n        <tr><td></td><td>[bf <i>bf-fn</i>]</td></tr>\n        <tr><td></td><td>[ival <i>ival-fn</i>])\n      </table>\n      </code>\n    </dt>\n    <dd>Adds a new operator. Operators describe pure mathematical functions,\n      i.e. <code>+</code> or <code>sin</code>.\n      The parameters <code><i>itype-names</i></code> and <code><i>otype-name</i></code>\n      are the input type(s) and output type names.\n      For example, <code>+</code> takes two <code>real</code> inputs and produces\n      one <code>real</code> output.\n      The <code><i>bf-fn</i></code> argument is the\n      <a href=\"https://docs.racket-lang.org/math/bigfloat.html\">bigfloat</a> implementation of your operator.\n      The <code><i>ival-fn</i></code> argument is the <a href=\"https://github.com/herbie-fp/rival\">Rival</a>\n      implementation of your operator. This is optional but improves the quality of Herbie's output.\n      If you don't want to implement this, set <code><i>ival-fn</i></code> to <code>false</code>.\n      To define operators with an unknown number of arguments, e.g. comparators,\n      add the attribute <code>[itype <i>itype</i>]</code>.\n      This will override the input type names defined by <code><i>itype-names</i></code>.\n      See the bottom of this section for support for constants.\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-operator-impl</b> (<i>op</i> <i>name</i> <i>irepr-names ...</i>)</td><td><i>orepr-name</i></td></tr>\n        <tr><td></td><td>[fl <i>fl-fn</i>]</td></tr>\n        <tr><td></td><td>...)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Implements <code><i>op</i></code> with input representation(s) <code><i>irepr-names</i></code>\n      and output representation <code><i>orepr-name</i></code>.\n      The field <code><i>name</i></code> must be unique.\n      For example, Herbie implements <code>+.f64</code> and <code>+.f32</code>\n      for double- and single-precision floats.\n      The argument <code><i>fl-fn</i></code> is the actual procedure that does the computation.\n      Like <code>define-operator</code>, the input representations can be\n      overridden with <code>[itype <i>irepr</i>]</code>.\n      By default, the attributes <code>bf</code> and <code>ival</code>\n      are inherited from <code><i>op</i></code> but can be overridden as previously\n      described.\n      See the bottom of this section for support for constant implementations.\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-ruleset</b> <i>name</i> (<i>groups ...</i>)</td>\n            <td>#:type ([<i>var</i> <i>repr</i>] ...)</td></tr>\n        <tr><td></td><td>[<i>rule-name</i> <i>match</i> <i>replace</i>]</td></tr>\n        <tr><td></td><td>...)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Defines a set of rewrite rules.\n      The <code><i>name</i></code> of the ruleset as well as each <code><i>rule-name</i></code>\n      must be a unique symbol.\n      Each ruleset must be marked with a set of <code><i>groups</i></code>\n      (read <a href=\"options.html#heading-3\">here</a> on ruleset groups).\n      Each rewrite rule takes the form <code>match ⇝ replace</code> where Herbie's rewriter\n      will replace <code>match</code> with <code>replace</code> (not vice-versa).\n      Each <code><i>match</i></code> and <code><i>replace</i></code> is an expression whose operators are\n      the names of operator implementations rather than pure mathematical operators.\n      Any variable must be listed in the type information with its associated representation.\n      See the <code>softposit-herbie</code> plugin for a more concrete example.\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-ruleset*</b> <i>name</i> (<i>groups ...</i>)</td>\n            <td>#:type ([<i>var</i> <i>type</i>] ...)</td></tr>\n        <tr><td></td><td>[<i>rule-name</i> <i>match</i> <i>replace</i>]</td></tr>\n        <tr><td></td><td>...)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Like <code>define-ruleset</code>, but it defines a ruleset for every representation that\n      inherits from <code><i>type</i></code>.\n      Currently, every <code><i>type</i></code> must be the same, e.g.\n      all <code>real</code>, for this procedure to function correctly.\n      Unlike <code>define-ruleset</code>, <code><i>match</i></code> and <code><i>replace</i></code>\n      contain the names of operators rather than operator implementations.\n    </dd>\n  </dl>\n\n  <p>Procedures for declaring constants are not a part of the plugin interface.\n    Instead, constants and constant implementations are defined as\n      zero-argument operators and operator implementations.\n    The fields <code><i>fl-fn</i></code>, <code><i>bf-fn</i></code>,\n      and <code><i>ival-fn</i></code> should be implemented with zero-argument\n      procedures (thunks).\n    Similar to operator and operator implementations, constants describe pure\n      mathematical values like <code>π</code> or <code>e</code> while constant\n      implementations define an approximation of those constants in a particular\n      representation.\n  </p>\n\n  <p><b>Plugin Interface (Parameterized)</b><br>\n\n  Defining operators, constants, and representations for parameterized functions requires\n  a <i>generator</i> procedure for just-in-time loading of features for a particular\n  representation.\n  When Herbie encounters a representation it does not recognize (not explicitly defined\n  using <code>define-representation</code>) it queries a list of generators in case the\n  representation requires just-in-time loading.\n  </p>\n\n  <p>The following procedure handles represention objects:</p>\n\n  <dl>\n    <dt><code>(<b>get-representation</b> name)</code></dt>\n    <dd>Takes a representation name and returns a representation object.\n      Do not call this function before the associated representation has been registered!\n    </dd>\n  </dl>\n\n  <p>The following procedures handle generators:</p>\n\n  <dl>\n    <dt><code>(<b>register-generator!</b> gen)</code></dt>\n    <dd>Adds a representation generator procedure to Herbie's set of generators.\n      Representation generator procedures take the name of a representation and\n      return the associated representation object if it successfully created the\n      operators, constants, and rules for that representation.\n      In the case that your plugin does not register the requested representation,\n      the generator procedure need not do anything and should just return\n      <code>false</code>.\n    </dd>\n  </dl>\n\n  <dl>\n    <dt><code>(<b>register-conversion-generator!</b> gen)</code></dt>\n    <dd>Adds a conversion generator procedure to Herbie's set of generators.\n      Conversion generator procedures take the names of two representations\n      and returns <code>true</code> if it successfully registered conversion(s)\n      between the two representations.\n      Conversions are one-argument operator implementations of the <code>cast</code>\n        operator that have one representation as an input representation and\n        a different representation as an output representation.\n      User-defined conversions are <i>OPTIONAL</i> for multi-precision optimization,\n        since Herbie can synthesize these by default.\n      However Herbie's implementations are often slow since they are\n        representation-agnostic and work for any two representations.\n      In the case that your plugin does not register the requested conversion(s),\n      the generator procedure need not do anything and should just return\n      <code>false</code>.\n    </dd>\n  </dl>\n\n  <p>\n    To actually add representations, operators, etc. within a generator procedure,\n    you must use a set of alternate procedures.\n  </p>\n\n  <dl>\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>register-representation!</b> </td><td> <i>name</i></td></tr>\n        <tr><td></td><td><i>type</i></td></tr>\n        <tr><td></td><td><i>repr?</i></td></tr>\n        <tr><td></td><td><i>bigfloat->repr</i></td></tr>\n        <tr><td></td><td><i>repr->bigfloat</i></td></tr>\n        <tr><td></td><td><i>ordinal->repr</i></td></tr>\n        <tr><td></td><td><i>repr->ordinal</i></td></tr>\n        <tr><td></td><td><i>width</i></td></tr>\n        <tr><td></td><td><i>special?</i>)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Like <code>define-representation</code>, but used within generators.</dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>register-representation-alias!</b> </td><td> <i>name</i> <i>repr</i>)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Adds an alias <i>name</i> for an existing representation <i>repr</i>.\n      If two representations are equivalent, e.g. <i>(float 8 32)</i> and <i>binary32</i>,\n      this procedure can be used to declare the two representations equivalent.\n    </dd>\n\n    <dt>\n      <code>(<b>register-operator!</b> <i>op</i> <i>name</i> <i>itype-names</i>\n        <i>otype-name</i> <i>attribs</i>)</code>\n    </dt>\n    <dd>Like <code>define-operator</code>, but used within generators.\n      The argument <code><i>itype-names</i></code> is a list of the input types\n      while the argument <code><i>attribs</i></code> are the same attributes for\n      <code>define-operator</code>, e.g. <code>bf</code>.\n      In this case, <code><i>attribs</i></code> is an association:\n      <code>(list (cons 'bf <i>bf-fn</i>) ...)</code>.\n    </dd>\n\n    <dt>\n      <code>(<b>register-operator-impl!</b> <i>op</i> <i>name</i> <i>ireprs</i>\n        <i>orepr</i> <i>attribs</i>)</code>\n    </dt>\n    <dd>Like <code>define-operator-impl</code>, but used within generators.\n      Unlike <code>define-operator-impl</code>, this procedure takes representation\n        objects rather than representation names for <code><i>ireprs</i></code>\n        and <code><i>orepr</i></code>.\n      Use <code>get-representation</code> to produce these objects.\n      See <code>register-operator!</code> for a description of <code><i>attribs</i></code>.\n    </dd>\n\n    <dt><code>(<b>register-ruleset!</b> <i>name</i> <i>groups</i>\n        <i>var-repr-names</i> <i>rules</i>)</code>\n    </dt>    \n    <dd>Like <code>define-ruleset</code>, but used within generators.\n      In this case, <code><i>groups</i></code> is a list of rule groups;\n        <code><i>var-repr-names</i></code> is an association\n        pairing each variable in the ruleset with its representation, e.g.\n        <code>(list (cons 'x '(float 5 16)) ...)</code>;\n        and <code><i>rules</i></code> is a list of rules of the following\n        form <code>(list (list <i>rule-name</i> <i>match</i> <i>replace</i>) ...)</code>.\n    </dd>\n\n  </dl>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.0/release-notes.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie 2.0 Release Notes</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <script src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML\"></script>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <style>\n    .showcase { margin: 1em 0; }\n    #team {\n        display: block; box-sizing: border-box; width: 100%;\n        border-radius: 2em; border: 3px solid black;\n    }\n  </style>\n</head>\n<body>\n  <header>\n    <h1>Herbie 2.0 Release Notes</h1>\n    <a href=\"../..\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>The <a href=\"../..\">Herbie</a> developers are excited to announce\n  Herbie 2.0! This release focuses clarity, transparency, and trade-offs.</p>\n\n  <p><b>What is Herbie?</b> Herbie automatically improves the accuracy\n  of floating point expressions. This avoids the bugs, errors, and\n  surprises that so often occur with floating point arithmetic.\n  Visit <a href=\"../..\">the main page</a> to learn more about Herbie.</p>\n\n  <img src=\"team.png\" id=\"team\" alt=\"The Herbie 2.0 team at UW and U of U\" />\n\n  <p><b>Join us!</b> Join the Herbie developers on the\n  <a href=\"https://fpbench.org\">FPBench</a> Slack, at the monthly\n  FPBench community meetings, and at\n  <a href=\"https://fpbench.org/talks/fptalks22.html\">FPTalks 2023</a>.\n\n  <h2>Speed-accuracy trade-offs</h2>\n\n  <figure class=\"showcase\">\n    <img src=\"report-cost-accuracy.png\"\n         alt=\"The Accuracy vs Speed section of a Herbie report, which has an accuracy vs speedup Pareto plot on the left and a tabular view of the accuracy and speed of each of Herbie's alternatives on the right.\">\n    <figcaption>\n      Herbie's new Accuracy vs Speed view, showing how multiple\n      alternatives found by Herbie compare on these different axes.\n    </figcaption>\n  </figure>\n\n  <p>\n  Two years ago, <a href=\"../1.5/release-notes.html\">Herbie 1.5</a>\n  added the <kbd>--pareto</kbd> mode, wherein suggested multiple\n  alternatives that trade off speed and accuracy. We've made this mode\n  faster, clearer, and more reliable, and as a result, we've made this\n  mode the default. Speed-accuracy trade-offs are central to numerics,\n  and we're excited for Herbie to help users with these trade-offs.\n  </p>\n\n  <h2>New Metrics and Redesign</h2>\n  \n  <figure class=\"showcase\">\n    <img src=\"report-large.png\" alt=\"The metrics shown at the top of each Herbie report: percentage accurate, time, alternatives, and speedup.\">\n    <figcaption>\n      The metrics now being showcased on a Herbie results page:\n      percentage accuracy replaces the old \"bits of error\" metric,\n      while \"speedup\" now highlights the speed of the fastest\n      alternative found by Herbie that is also more accurate than the\n      initial program.\n    </figcaption>\n  </figure>\n\n  <p>\n  We've cleaned up the report page significantly. Besides a visual\n  redesign&mdash;we've refreshed and standardized the new fonts,\n  colors, and spacing&mdash;we've switched to <a href=\"error.html\">a\n  new way</a> of measuring accuracy and speed, which we think will be\n  more intuitive for users and avoid some misconceptions we see users\n  run into.\n  </p>\n\n  <h2>Derivations</h2>\n\n  <figure class=\"showcase\">\n    <img src=\"report-alternative-derivation.png\" alt=\"The derivation section shown for each alternative produced by Herbie, which show step by step how the initial program was transformed into the alternative.\">\n    <figcaption>\n      New \"Step-by-step derivation\" buttons show how a transformation\n      was done by Herbie, with each step annotated with its mathematical\n      axiom from Herbie's database.\n    </figcaption>\n  </figure>\n\n  <p>\n    Herbie can now explain step by step how it transformed your\n    original input into the final program. This can help you\n    understand how Herbie works, and potentially help us identify bugs\n    or misbehaviors. More importantly, when Herbie comes up with\n    something truly surprising, you can now have more confidence that\n    the answer is correct.\n  </p>\n\n  <h2>Foundations for a Herbie Workbench</h2>\n  \n  <p>\n    We&apos;ve started building\n    a <a href=\"https://github.com/herbie-fp/herbie-vscode\">prototype\n    numerics workbench</a>, codenamed \"Odyssey\". This release thus\n    contains the beginnings of a <a href=\"api-endpoints.html\">REST\n    API</a> for interacting with Herbie. Our long-term goal is an\n    interactive, task-oriented interface for working with\n    floating-point accuracy, leveraging Herbie but also potentially\n    other tools. A prototype is currently available in the VS Code\n    store as the <kbd>herbie-vscode</kbd> plugin.\n  </p>\n\n  <h2>Other improvements</h2>\n  <ul>\n    <li>Inputs whose real-valued result rounds to floating-point\n      infinity are now considered valid. This changes Herbie&apos;s\n      accuracy estimates, sometimes significantly, but we found that\n      typically this yields better final programs.\n    <li>Most sections of the Herbie reports page now have \"help\" links\n      directly to the relevant section of the documentation.\n    <li>Many, many algorithms within Herbie, especially pruning,\n      regimes, and binary search, have seen significant speed ups.\n    <li>Graphs are now drawn using JavaScript, on the client side,\n      making them look sharper, especially on high-DPI displays.\n    <li>Herbie&apos;s localization pass was written to be more\n      accurate on tricky cases, which improves Herbie&apos;s results.\n    <li>Herbie&apos;s support for the <code>tgamma</code>\n      and <code>lgamma</code> functions was rewritten to be more\n      accurate (though it remains quite slow).\n  </ul>\n\n  <h2>Try it out!</h2>\n\n  <p>\n    We want Herbie to be more useful to scientists, engineers, and\n    programmers around the world. We've got a lot of features we're\n    excited to work on in the coming months. Please\n    <a href=\"https://github.com/uwplse/herbie/issues\">report bugs</a>\n    or <a href=\"https://github.com/uw-plse/herbie\">contribute</a>.\n  </p>\n  <br>\n  <p style=\"font-weight: bold; text-align: center;\">If you find Herbie\n  useful, <a href=\"mailto:herbie@cs.washington.edu\">let us know!</p>\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.0/report.html",
    "content": "<!doctype html>\n<html>\n\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie reports</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n\n<body>\n  <header>\n    <h1>Herbie reports</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>When used <a href=\"using-web.html\">in the browser</a>, Herbie\n    generates HTML reports full of information about the accuracy and relative \n    speed of the initial and alternative expressions.</p>\n\n  <h2 id=\"links\">Summary and Additional links</h2>\n\n  <p>The top of the report page has a right-hand menu bar with\n    additional links. “Metrics” give you detailed internal information\n    about Herbie, while “Report”, if present, takes you back to the\n    full Herbie report.</p>\n\n  <p>Below the menu lies a brief summary of the results. Herbie can\n    produce multiple alternatives to the initial program, and this\n    summary gives their basic statistics.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-large.png\" />\n    <figcaption>Summary numbers from a Herbie report.</figcaption>\n  </figure>\n\n  <dl>\n    <dt>Percentage Accurate</dt>\n    <dd>The <a href=\"errors.html\">percentage accuracy</a> of the\n    initial program and what Herbie thinks is its most accurate\n    alternative.</dd>\n    <dt>Time</dt>\n    <dd>The time it took Herbie to generate all of the alternatives.</dd>\n    <dt>Alternatives</dt>\n    <dd>The number of alternatives found.</dd>\n    <dt>Speedup</dt>\n    <dd>The speed of the fastest alternative that is more accurate\n    than the initial program, relative to the initial program.</dd>\n  </dl>\n\n  <h2 id=\"spec\">Specification</h2>\n\n  <p>Next, the specification that you gave to Herbie. This section is\n    closed by default. Typically, the specification is also the\n    initial program, but in some cases, like if\n    the <a href=\"input.html\"><kbd>:spec</kbd> property</a> is used,\n    they can differ. The specification also includes\n    any <a href=\"input.html#preconditions\">preconditions</a> given to\n    Herbie.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"specification.png\" />\n  </figure>\n\n  <p>You can use the drop-down in the top left to display the\n  specification in an alternative syntax.</p>\n\n  <p>The colored outcome bar summarizes the sampled floating-point\n    inputs that produce valid, unknown, or invalid outputs. Green\n    outcomes are valid, broken down into finite and infinite. Unknown\n    outputs are red. Blue outcomes are invalid (fail precondition or\n    domain errors) and are ignored by Herbie.</p>\n\n  <!-- Colors copied from src/web/resources/report.css -->\n  <h2 id=\"graph\">Local Percentage Accuracy graph</h2>\n\n  <p>\n    Next, the <em>Local Percentage Accuracy</em> graph compares the\n    accuracy of the initial program to Herbie's most accurate\n    alternative. This is helpful for understanding the sorts of inputs\n    Herbie is improving accuracy on. Sometimes, Herbie improved\n    accuracy on some inputs at the cost of accuracy on other inputs\n    that you care more about. You can add a\n    <a href=\"input.html#preconditions\">precondition</a> to restrict Herbie to \n    the more important inputs in that case.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-accuracy.png\" />\n  </figure>\n\n  <p>In the plot, each individual sampled point is shown with a faint\n    circle, and the thick line is moving average of those individual\n    samples. The red line is the initial program and the blue line is\n    Herbie's most accurate alternative.</p>\n  \n  <p>Accuracy is shown on the vertical axis, and higher is better. The\n    horizontal axis shows one of the variables in the input program;\n    the dropdown in the title switches between input variables. The\n    checkboxes below the graph toggle the red and blue lines on and\n    off.</p>\n\n  <p>If Herbie decided to insert an <code>if</code> statement into the\n    program, the locations of those <code>if</code> statements will be\n    marked with vertical bars.</p>\n\n  <h2 id=\"cost-accuracy\">Accuracy vs Speed</h2>\n  <p>Next, a Pareto graph and table list the alternatives Herbie\n    found.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-cost-accuracy.png\" />\n  </figure>\n\n  <p>Both the plot and the table show the same data. In the plot,\n  accuracy is on the vertical axis and speedup is on the horizontal\n  axis. Up and to the right is better. The initial program is shown\n  with a red square, while each of Herbie's alternatives is shown with\n  a blue circle. A faint line shows the Pareto frontier&mdash;that is,\n  it goes through all Herbie alternatives that maximize speed for\n  their level of accuracy. Some of Herbie's alternatives may not be on\n  the Pareto frontier due to differences between the training and test\n  set.</p>\n\n  <p>In the table, each alternative is shown along with its accuracy\n  and speed relative to the initial program. Values are green if they\n  are better than the initial program, and black otherwise. Each\n  alternative is linked to its description lower on the page.</p>\n\n  <h2 id=\"alternatives\">Initial program and Alternatives</h2>\n\n  <p>Below the table come a series of boxes detailing the initial\n    program and each of Herbie's alternatives, along with their\n    accuracy and relative speed.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-alternative.png\" />\n  </figure>\n\n  <p>The accuracy and relative speed of each alternative is given in\n    the title. Below the title, the alternative expression itself is\n    given. The dropdown in the top right can be used to change the\n    syntax used.</p>\n\n  <p>By definition, the speed of the initial program is 1.0×, and it\n    has no derivation since it was provided by the user.</p>\n\n  <p>Each alternative also has a derivation, which can be shown by\n    clicking on \"Derivation\". The derivation shows each step Herbie\n    took to transform the initial program into this alternative.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-alternative-derivation.png\" />\n  </figure>\n\n  <p>Each step in the derivation gives the accuracy after that step.\n    Sometimes you can use that to pick a less-complex and\n    not-substantially-less-accurate program. The derivation will also\n    call out any time the input is split into cases. When a part of\n    the step is colored blue, that identifies the changed part of the\n    expression.</p>\n\n  <p>Derivations may also contain \"step-by-step derivations\"; you can\n  click on those step-by-step derivations to expand them. Each step in\n  the step-by-step derivation names an arithmetic law from Herbie's\n  database, with <kbd>metadata-eval</kbd> meaning that Herbie used\n  direct computation in a particular step.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-step-by-step.png\" />\n  </figure>\n\n  <h2 id=\"reproduction\">Reproduction</h2>\n\n  <p>Finally, Herbie gives a command to reproduce that result. If you\n    find a Herbie bug, include this code snippet when\n    <a href=\"https://github.com/uwplse/herbie/issues\">filing an issue</a>.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-reproduce.png\" />\n  </figure>\n\n  <p>We expect the report to grow more informative with future\n    versions. Please <a href=\"mailto:herbie@cs.washington.edu\">get in\n      touch</a> if there is more information you'd like to see.</p>\n\n</body>\n\n</html>\n"
  },
  {
    "path": "www/doc/2.0/toc.js",
    "content": "function make_toc() {\n    var headings = document.querySelectorAll(\"h2\");\n    var toc = document.createElement(\"nav\");\n    toc.classList.add(\"toc\")\n    var list = document.createElement(\"ul\");\n    for (var i = 0; i < headings.length; i++) {\n        var li = document.createElement(\"li\");\n        var a = document.createElement(\"a\");\n        var h = headings[i];\n        if (! h.id) {\n            h.setAttribute(\"id\", \"heading-\" + i);\n        }\n        a.setAttribute(\"href\", \"#\" + h.id);\n        a.innerHTML = h.innerHTML;\n        li.appendChild(a);\n        list.appendChild(li);\n    }\n    toc.appendChild(list);\n    headings[0].parentNode.insertBefore(toc, headings[0]);\n}\n\nwindow.addEventListener(\"load\", make_toc);\n"
  },
  {
    "path": "www/doc/2.0/tutorial.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Tutorial</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Herbie Tutorial</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> rewrites floating point expressions to\n      make them more accurate. Floating point arithmetic is\n      <a href=\"error.html\">inaccurate</a>; even 0.1 + 0.2 ≠ 0.3 in\n      floating-point. Herbie helps find and fix these mysterious\n      inaccuracies.\n  </p>\n\n  <p>\n    To get started, <a href=\"installing.html\">download and install</a>\n    Herbie. You're then ready to begin using it.\n  </p>\n\n  <h2>Giving Herbie expressions</h2>\n\n  <p>Start Herbie with:</p>\n\n  <pre class=\"shell\">herbie web</pre>\n\n  <p>\n    After a brief wait, your web browser should open and show you\n    Herbie's main window. The most important part of the page is this\n    bit:\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"web-input.png\" alt=\"The program input field in the Herbie web UI.\"/>\n  </figure>\n\n  <p>\n    Let's start by just looking at an example of Herbie running.\n    Click \"Show an example\". This will pre-fill the expression\n    <kbd>sqrt(x + 1) - sqrt(x)</kbd>\n    with <code>x</code> ranging from to <kbd>0</kbd> and <kbd>1.79e308</kbd>.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"range-input.png\" alt=\"The input range field in the Herbie web UI.\"/>\n  </figure>\n\n  <p>\n    Now that you have an expression and a range for each variable,\n    click the \"Improve with Herbie\" button. You should see the entry\n    box gray out, and shortly thereafter some text should appear\n    describing what Herbie is doing. After a few seconds, you'll be\n    redirected to a page with Herbie's results.\n  </p>\n\n  <p>\n    The very top of this results page gives some quick statistics\n    about the alternative ways Herbie found for evaluating this\n    expression:\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-large.png\" alt=\"Statistics and error measures for this Herbie run.\" />\n  </figure>\n\n  <p>\n    Here, you can see that Herbie's most accurate alternative has an\n    accuracy of 99.7%, much better than the initial program's 53.2%,\n    and that in total Herbie found 5 alternative. One of those\n    alternatives is both more accurate than the original expression\n    and also 1.9&times; faster. The <a href=\"report.html\">rest of the\n    result page</a> shows each of these alternatives, including\n    details like how they were derived. These details are all\n    <a href=\"report.html\">documented</a>, but for the sake of the\n    tutorial let's move on to a more realistic example.\n  </p>\n\n  <h2>Programming with Herbie</h2>\n\n  <p>\n    You can use Herbie on expressions from source code, mathematical\n    models, or debugging tools. But most users use Herbie as they\n    write code, passing any complex floating-point tool to Herbie as\n    they go. Herbie has <a href=\"options.html\">options</a> to log all\n    the expressions you enter so that you can refer to them later.\n  </p>\n\n  <p>But to keep the tutorial focused, let's suppose you're instead\n    tracking down a floating-point bug in existing code. Then you'll\n    need to start by identifying the problematic floating-point\n    expression.</p>\n\n  <p>To demonstrate the workflow, let's walk through\n    <a href=\"https://github.com/josdejong/mathjs/pull/208\">bug 208</a>\n    in <a href=\"http://mathjs.org\">math.js</a>, a math library for\n    JavaScript. The bug deals with inaccurate square roots for complex\n    numbers. (For a full write-up of the bug itself, check out\n    a <a href=\"https://pavpanchekha.com/blog/casio-mathjs.html\">blog\n    post</a> by one of the Herbie authors.)\n  </p>\n\n  <h2>Finding the problematic expression</h2>\n\n  <p>\n    In most programs, there's a small core that does the mathematical\n    computations, while the rest of the program sets up parameters,\n    handles control flow, visualizes or prints results, and so on. The\n    mathematical core is what Herbie will be interested in.\n  </p>\n\n  <p>\n    For our example, let's start\n    in <a href=\"https://github.com/josdejong/mathjs/tree/master/lib/function\"><code>lib/function/</code></a>.\n    This directory contains many subdirectories; each file in each\n    subdirectory defines a collection of mathematical functions. The\n    bug we're interested in is about complex square root, which is\n    defined in\n    <a href=\"https://github.com/josdejong/mathjs/blob/da306e26ed34272db44e35f07a3b015c0155d99a/lib/function/arithmetic/sqrt.js\"><code>arithmetic/sqrt.js</code></a>.\n  </p>\n\n  <p>\n    This file handles argument checks, five different number types,\n    and error handling, for both real and complex square roots. None\n    of that is of interest to Herbie; we want to extract just the\n    mathematical core. So skip down to the <code>isComplex(x)</code>\n    case:\n  </p>\n\n  <pre>var r = Math.sqrt(x.re * x.re + x.im * x.im);\nif (x.im &gt;= 0) {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}\nelse {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      -0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}</pre>\n\n  <p>This is the mathematical core that we want to send to Herbie.</p>\n\n  <h2>Converting problematic code to Herbie input</h2>\n\n  <p>\n    In this code, <code>x</code> is of type <code>Complex</code>, a\n    data structure with multiple fields. Herbie only deals with\n    floating-point numbers, not data structures, so we will treat the\n    input <code>x</code> as two separate inputs to\n    Herbie: <code>xre</code> and <code>xim</code>. We'll also pass\n    each field of the output to Herbie separately.\n  </p>\n\n  <p>\n    This code also branches between non-negative <code>x.im</code> and\n    negative <code>x.im</code>. It's usually better to send each\n    branch to Herbie separately. So in total, this code turns into four\n    Herbie inputs: two output fields, for each of the two branches.\n  </p>\n\n  <p>Let's focus on the first field of the output for the case of\n  non-negative <code>x.im</code>.</p>\n\n  <p>The variable <code>r</code> is an intermediate variable in this\n  code block. Intermediate variables provide Herbie with crucial\n  information that Herbie can use to improve accuracy, so you want to\n  expand or inline them. The result looks like this:</p>\n\n  <pre>0.5 * sqrt(2.0 * (sqrt(xre * xre + xim * xim) + xre))</pre>\n\n  <p>Recall that this code is only run when <code>x.im</code> is\n  non-negative (but it runs for all values of <code>x.re</code>). So, \n  select the full range of values for <code>x.re</code>, but restrict\n  the range of <code>x.im</code>, like this: \n  \n  <figure>\n    <img width=\"100%\" src=\"range-input-2.png\" alt=\"Restricting the input range to xim >= 0.\" />\n  </figure>\n  \n  This asks Herbie to consider only non-negative\n  values of <code>xim</code> when improving the accuracy of this\n  expression.</p>\n  \n  <h2>Herbie's results</h2>\n\n  <p>Herbie will churn for a few seconds and produce a results page.\n    In this case, Herbie found 4 alternatives, and we're interested in\n    the most accurate one, which should have an\n    <a href=\"error.html\">accuracy of 84.6%:</a></p>\n\n  <figure>\n    <img width=\"100%\" src=\"problematic-highlight.png\" />\n  </figure>\n\n  <p>Below these summary statistics, we can see a graph of accuracy\n  versus input value. By default, it shows accuracy\n  versus <code>xim</code>; higher is better:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"problematic-xim.png\" />\n  </figure>\n\n  <p>The drop in accuracy once <code>xim</code> is bigger than\n  about <code>1e150</code> really stands out, but you can also see\n  that Herbie's alternative more accurate for smaller <code>xim</code>\n  values, too. You can also change the graph to plot accuracy\n  versus <code>xre</code> instead:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"problematic-xre.png\" />\n  </figure>\n\n  <p>This plot makes it clear that Herbie's alternative is almost\n  perfectly accurate for positive <code>xre</code>, but still has some\n  error for negative <code>xre</code>.\n\n  <p>Herbie also found other alternatives, which are less accurate but\n  might be faster. You can see a summary in this table:</p>\n\n  <figure>\n    <figcaption></figcaption>\n    <img width=\"100%\" src=\"problematic-pareto-table.png\" />\n  </figure>\n\n  <p>Herbie's algorithm is randomized, so you likely won't see the\n  exact same thing; you might see more or fewer alternatives, and they\n  might be more or less accurate and fast. That said, the most\n  accurate alternative should be pretty similar.</p>\n\n  <p>That alternative itself is shown lower down on the page:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"problematic-improved-accuracy.png\" />\n  </figure>\n\n  <p>A couple features of this alternative stand out immediately.\n  First of all, Herbie inserted an <code>if</code> statement.\n  This <code>if</code> statement handles a phenomenon known as\n  cancellation, and is part of why Herbie's alternative is more\n  accurate. Herbie also replaced the square root operation with\n  the <code>hypot</code> function, which computes distances more\n  accurately than a direct square root operation.</p>\n\n  <p>If you want to see more about how Herbie derived this result, you\n  could click on the word \"Derivation\" to see a detailed, step-by-step\n  explanation of how Herbie did it. For now, though, let's move on to\n  look at another alternative.</p>\n  \n  <p>The fifth alternative suggested by Herbie is much less accurate,\n  but it is about twice as fast as the original program:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"problematic-improved-speed.png\" />\n  </figure>\n  \n  <p>This alternative is kind of strange: it has two branches, and\n  each one only uses one of the two variables <code>xre</code>\n  and <code>xim</code>. That explains why it's fast, but it's still\n  more accurate than the initial program because it avoids\n  cancellation and overflow issues that plagued the original.</p>\n  \n  <h2>Using Herbie's alternatives</h2>\n  \n  <p>In this case, we were interested in the most accurate possible\n  implementation, so let's try to use Herbie's most accurate\n  alternative.</p>\n\n  <pre>\n// Herbie version of 0.5 * sqrt(2.0 * (sqrt(xre*xre + xim*xim) + xre))\nvar r = Math.hypot(x.re, x.im);\nvar re;\nif (xre + r <= 0) {\n    re = 0.5 * Math.sqrt(2 * (x.im / (x.re / x.im) * -0.5));\n} else {\n    re = 0.5 * Math.sqrt(2 * (x.re + r));\n}\nif (x.im &gt;= 0) {\n  return new Complex(\n      re,\n      0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}\nelse {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      -0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}</pre>\n\n  <p>Note that I&apos;ve left the Herbie query in a comment. As Herbie\n  gets better, you can re-run it on this original expression to see if\n  it comes up with improvements in accuracy.</p>\n\n  <p>By the way, for some languages, including JavaScript, you can use\n  the drop-down in the top-right corner of the alternative block to\n  translate Herbie&apos;s output to that language. However, you will\n  still probably need to refactor and modify the results to fit your\n  code structure, just like here.</p>\n\n  <h2>Next steps</h2>\n\n  <p>With this change, we&apos;ve made this part of the complex square\n  root function much more accurate, and we could repeat the same steps\n  for the other branches and other fields in this program. You now\n  have a pretty good understanding of Herbie and how to use it.\n  Please <a href=\"mailto:herbie@cs.washington.edu\">let us know</a> if\n  Herbie has helped you, and check out\n  the <a href=\"../../doc.html\">documentation</a> to learn more about\n  Herbie&apos;s various options and outputs.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.0/using-cli.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie from the Command Line</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Shell and Batch Mode</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>Herbie can be used from the command-line or\n  from <a href=\"using-web.html\">the browser</a>. This page covers\n  using Herbie from the command line.</p>\n\n  <h2 id=\"interactive\">The Herbie shell</h2>\n\n  <p>\n    The Herbie shell lets you interact with Herbie: you type in input\n    expressions and Herbie prints their more accurate versions. Run\n    the Herbie shell with this command:\n  </p>\n\n  <pre class=\"shell\">herbie shell\nHerbie 2.0 with seed 2098242187\nFind help on https://herbie.uwplse.org/, exit with Ctrl-D\n<strong>herbie&gt;</strong> </pre>\n\n\n  <p>\n    Herbie prints a seed, which you can <a href=\"options.html\">use to\n    reproduce</a> a Herbie run, and links you to documentation. Then,\n    it waits for inputs, which you can type directly into your\n    terminal in <a href=\"input.html\">FPCore format</a>:\n</p>\n\n  <pre><strong>herbie&gt;</strong> (FPCore (x) (- (+ 1 x) x))\n(FPCore\n  (x)\n  <var>...</var>\n  1)</pre>\n\n  <p>Herbie suggests that <code>1</code> is more accurate than the\n  original expression <code>(- (+ 1 x) x)</code>. The\n  the <var>...</var> elides \n  <a href=\"input.html#properties\">additional information</a> provided\n  by Herbie.</p>\n\n  <p>The Herbie shell only shows Herbie's most accurate variant.</p>\n\n  <h2 id=\"batch\">Batch processing FPCores</h2>\n\n  <p>\n    Alternatively, you can run Herbie on a file with multiple\n    expressions in it, writing Herbie's versions of each to a file.\n    This mode is intended for use by scripts.\n  </p>\n\n  <pre class=\"shell\">herbie improve bench/tutorial.fpcore out.fpcore\nStarting Herbie on 3 problems (seed: 1551571787)...\n  1/3\t[   0.882s]   30→ 0\tCancel like terms\nWarning: 24.7% of points produce a very large (infinite) output.\nYou may want to add a precondition.\nSee <a href=\"https://herbie.uwplse.org/doc/2.0/faq.html#inf-points\">&lt;https://herbie.uwplse.org/doc/2.0/faq.html#inf-points&gt;</a> for more.\n  2/3\t[   1.721s]   29→ 0\tExpanding a square\n  3/3\t[   2.426s]    0→ 0\tCommute and associate</pre>\n\n  <p>\n    The output file <code>out.fpcore</code> contains more accurate\n    versions of each program:\n  </p>\n\n  <pre>;; seed: 1551571787\n\n(FPCore (x) <var>...</var> 1)\n(FPCore (x) <var>...</var> (* x (- x -2)))\n(FPCore (x y z) <var>...</var> 0)</pre>\n\n  <p>\n    Note that output file is in the same order as the input file. For\n    more control over Herbie, see the documentation of\n    Herbie's <a href=\"options.html\">command-line options</a>.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.0/using-web.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie from the Browser</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>The Browser UI</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> rewrites floating point expressions to\n    make them more accurate. Herbie can be used\n    from <a href=\"using-cli.html\">the command-line</a> or from the\n    browser; this page is about using Herbie from the browser.</p>\n\n\n  <h2 id=\"interactive\">The Herbie web shell</h2>\n\n  <p>\n    The Herbie web shell lets you interact with Herbie through your\n    browser, featuring a convenient input format. The web shell is the\n    friendliest and easiest way to use Herbie. Run the Herbie web\n    shell with this command:\n  </p>\n\n  <pre class=\"shell\">herbie web</pre>\n\n  <p>After a few seconds, the web shell will rev up and direct your\n  browser to Herbie:</p>\n  \n  <pre class=\"shell\">herbie web\nHerbie 2.0 with seed 1003430182\nFind help on https://herbie.uwplse.org/, exit with Ctrl-C\nYour Web application is running at http://localhost:8000/.\nStop this program at any time to terminate the Web Server.</pre>\n\n  <figure>\n    <img width=\"100%\" src=\"web-main.png\" alt=\"A screenshot of the Herbie web shell main page.\"/>\n  </figure>\n\n  <p>You can type an input expressions in\n    <a href=\"input.html\">standard mathematical syntax</a>. After typing in an \n    expression, you will be asked to specify the range of values for each input \n    variable that Herbie should consider when trying to improve the expression. \n    Hit the \"Improve with Herbie\" button once you're done to run Herbie.\n  </p>\n  \n  <p>\n    The web shell reports Herbie's progress and redirects to a\n    <a href=\"report.html\">report</a> once Herbie is done.\n  </p>\n\n  <p>\n    The web shell can also automatically save the generated reports,\n    and has <a href=\"options.html\">many other options</a> you might\n    want to explore.\n  </p>\n\n\n  <h2 id=\"batch\">Batch report generation</h2>\n\n  <p>A <a href=\"report.html\">report</a> can also be generated directly\n  from a file of input expressions in <a href=\"input.html\">FPCore format</a>:</p>\n  \n  <pre class=\"shell\">herbie report bench/tutorial.fpcore output/ \nStarting Herbie on 3 problems (seed: 770126425)...\nWarning: 25.0% of points produce a very large (infinite) output. \nYou may want to add a precondition.\nSee <a href=\"faq.html#inf-points\">https://herbie.uwplse.org/doc/latest/faq.html#inf-points</a> for \nmore.\n  1/3   [   0.703s]   29→ 0     Expanding a square\n  2/3   [   1.611s]    0→ 0     Commute and associate\n  3/3   [   0.353s]   30→ 0     Cancel like terms</pre>\n\n  <p>\n    This command asks generates a report from the input expressions\n    in <code>bench/tutorial.fpcore</code> and saves the report in the\n    directory <code>output/</code>. It's best if that directory\n    doesn't exist before running this command, because otherwise\n    Herbie may overwrite files in that directory.\n  </p>\n\n  <p>\n    Occasionally you may also see Herbie emit warnings as shown above.\n    All of Herbie's warnings are listed, with explanations, in\n    the <a href=\"faq.html\">FAQ</a>.\n  </p>\n\n  <p>\n    Once generated, open <code>output/index.html</code> in your\n    favorite browser (but see <a href=\"faq.html\">the FAQ</a> if you're\n    using Chrome). That page summarizes Herbie's results for all\n    expression in your input file, and you can click on individual\n    expressions to see their report.\n  </p>\n\n  <p>Batch report generation is the most informative way to run Herbie\n  on a large collection of inputs. Like the web shell, it can be\n  customized through <a href=\"options.html\">command-line options</a>,\n  including parallelizing Herbie with multiple threads.</p>\n\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.1/api-endpoints.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Herbie HTTP API Endpoints</title>\n    <link rel='stylesheet' type='text/css' href='../../main.css'>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <script type=\"text/javascript\" src=\"toc.js\"></script>\n  </head>\n  <body>\n    <header>\n      <h1>HTTP API</h1>\n      <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n      <nav>\n        <ul>\n          <li><a href=\"../../demo/\">Try</a></li>\n          <li><a href=\"installing.html\">Install</a></li>\n          <li><a href=\"tutorial.html\">Learn</a></li>\n        </ul>\n      </nav>\n    </header>\n\n    <p>The <a href=\"../../\">Herbie</a> API allows applications to\n    interface with Herbie using HTTP requests. The API is designed to\n    be stateless: the order in which endpoints are called shouldn't\n    matter.</p>\n\n    <h2 id=\"all-endpoints-info\">Format for all endpoints</h2>\n\n    <p>All the endpoints listed below respond to POST requests unless\n    otherwise specified. A typical example of sending a POST request\n    to a running Herbie server is:</p>\n\n    <pre class=\"shell\">curl -d \\\n  '{\"formula\": \"(FPCore (x) (- (sqrt (+ x 1))))\", \"seed\": 5}' \\\n  -H 'Content-Type: application/json' \\\n  http://127.0.0.1:8000/api/sample\n    </pre>\n\n    <h2 id=\"sample\">/api/sample</h2>\n\n    <details>\n    <summary>Example input & output</summary>\n\n    <p>Request:</p>\n\n    <pre>{\n    formula: &lt;FPCore expression&gt;,\n    seed: &lt;random seed for point generation&gt;\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n    points: [[point, exact], ... ]\n}</pre>\n    </details>\n\n    <p>The <code>sample</code> endpoint allows the user to request a\n    sample of points given the FPCore expression and a seed.</p>\n\n    <p>Returns a collection of points and the exact evaluation of each\n    point with the given spec. The results are returned through the\n    \"points\" field and are represented by an array of point-exact\n    pairs with the first value representing the point and the second\n    value representing the exact evaluation; the exact value of\n    point <code>n</code> is <code>points[n][1]</code>.</p>\n\n    <p>Herbie calculates the \"ground truth\" by calculating the values\n    with more precise numbers. This can be slow.</p>\n\n    <h2 id=\"exacts\">/api/exacts</h2>\n\n    <details>\n    <summary>Example input & output</summary>\n\n    <p>Request:</p>\n\n    <pre>{\n    formula: &lt;FPCore expression&gt;,\n    sample: [point, ... ]\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n    points: [[point, exact], ... ]\n}</pre>\n    </details>\n\n    <p>The <code>exacts</code> endpoint allows the user to request the\n    exact value of a set of points evaluated at a real number\n    specification given as an FPCore expression.</p>\n\n    <p>Some points may not be calculable given the FPCore\n    expression.</p>\n\n    <p>Returns a collection of points and the exact evaluation of each\n    point with the given spec. The results are returned through the\n    \"points\" field and are represented by an array of point-exact\n    pairs with the first value representing the point and the second\n    value representing the exact evaluation; the exact value of\n    point <code>n</code> is <code>points[n][1]</code>.</p>\n\n    <p>Herbie calculates the \"ground truth\" by calculating the values\n    with more precise numbers. This can be slow.</p>\n\n    <h2 id=\"calculate\">/api/calculate</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n\n    <p>Request:</p>\n\n    <pre>{\n    formula: &lt;FPCore expression&gt;,\n    sample: [point ... ]\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n    points: [[point, exact], ... ]\n}</pre>\n    </details>\n\n    <p>The <code>calculate</code> endpoint allows the user to request\n    the evaluation of a set of points evaluated at a floating-point\n    implementation given as an FPCore expression.</p>\n\n    <p>Some points may not be calculable given the FPCore expression.</p>\n\n    <p>Returns a collection of points and the evaluation of each point\n    using the given FPCore as a floating-point implementation. The\n    results are returned through the \"points\" field and are\n    represented by an array of point-exact pairs with the first value\n    representing the point and the second value representing the\n    evaluated value; the evaluated value of point <code>n</code>\n    is <code>points[n][1]</code>.</p>\n\n    <h2 id=\"analyze\">/api/analyze</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n\n    <p>Request:</p>\n\n    <pre>{\n  formula: &lt;FPCore expression&gt;,\n  sample: [[point, exact], ... ]\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n  points: [[point, error], ... ]\n}</pre>\n    </details>\n\n    <p>The <code>analyze</code> endpoint allows the user to request\n    error analysis of a set of point-exact pairs and a given\n    floating-point implementation.</p>\n\n    <p>Given a collection of points, their exact values, and an FPCore\n    expression to analyze on, the <code>analyze</code> endpoint\n    returns the error for each point for that expression. The error\n    value returned is Herbie's internal error heuristic.</p>\n\n    <h2 id=\"alternatives\">/api/alternatives</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n    <p>Request:</p>\n\n    <pre>{\n  formula: &lt;FPCore expression&gt;,\n  sample: [[point, exact], ... ]\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n  alternatives: [alt, ... ],\n  histories: [history, ... ],\n  splitpoints: [splitpoint, ... ]\n}</pre>\n    </details>\n\n    <p>The <code>alternatives</code> endpoint allows the user to\n    request rewrites from Herbie given an expression to rewrite and a\n    set of point-exact pairs.</p>\n\n    <p>Returns a list of alternatives represented by FPCore\n    expressions through the \"alternatives\" field.</p>\n\n    <p>Returns a list of derivations of each alternative through the\n    \"histories\" field where <code>history[n]</code> corresponds\n    to <code>alternatives[n]</code>.</p>\n\n    <p>Returns a list of splitpoints for each alternative through the\n    \"splitpoints\" field where <code>splitpoints[n]</code> corresponds\n    to <code>alternatives[n]</code>. <code>splitpoints[n]</code> will\n    only contain information about the corresponding alternative.s\n    splitpoints if the alternative is a branch-expression.</p>\n\n    <h2 id=\"mathjs\">/api/mathjs</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n    <p>Request:</p>\n\n    <pre>{\n  formula: &lt;FPCore expression&gt;\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n  mathjs: &lt;mathjs expression&gt;\n}</pre>\n    </details>\n\n    <p>The <code>mathjs</code> endpoint allows the user to translate\n    FPCore expressions into mathjs expressions.</p>\n\n\n    <h2 id=\"cost\">/api/cost</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n\n    <p>Request:</p>\n\n  <pre>{\n    formula: &lt;FPCore expression&gt;,\n    sample: [point ... ]\n}</pre>\n\n    <p>Response:</p>\n\n  <pre>{\n    cost: cost\n}</pre>\n\n    <p><b>Specific Example: sqrt(x+1)-sqrt(x)</b></p>\n\n    <p>Request:</p>\n\n  <pre>{\n    formula: &lt;(FPCore (x) (- (sqrt (+ x 1)) (sqrt x)))&gt;,\n    sample: [ [[1], -1.4142135623730951] ]\n}</pre>\n\n    <p>Response:</p>\n\n  <pre>{\n    cost: 13120\n}</pre>\n\n    <p><b>Lower-Cost Example: (x+1)-(x)</b></p>\n\n    <p>Request:</p>\n\n  <pre>{\n    formula: &lt;(FPCore (x) (- (+ x 1 ) x))&gt;,\n    sample: [ [[1], -1.4142135623730951] ]\n}</pre>\n\n    <p>Response:</p>\n\n  <pre>{\n    cost: 320\n}</pre>\n\n    </details>\n\n    <p>The <code>cost</code> endpoint allows the user to request\n    the evaluation of an expression's overall cost. Cost is \n    calculated depending on the complexity of operations contained\n    in the expression. </p>\n\n    <p>Given an FPCore expression and a collection of points,\n    returns the cost of the expression. The cost value returned \n    is calculated internally by Herbie.</p> \n    \n    <p>The points should be of the same format as the points \n    generated in the sample endpoint. Refer to /api/sample \n    for more details. </p>\n\n    <p>Note the sample points are not used in the cost calculation.\n    The contents of the points do not matter as long as they are\n    in the correct format as mentioned above.</p>\n\n    <!-- Translate Endpoint -->\n\n    <h2 id=\"translate\">/api/translate</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n\n    <p>Request:</p>\n\n  <pre>{\n    formula: &lt;FPCore expression&gt;,\n    language: \"language\"\n}</pre>\n\n    <p>Response:</p>\n\n  <pre>{\n    result: \"translated expression\"\n}</pre>\n\n    <p><b>Specific Example: sqrt(x+1)-sqrt(x)</b></p>\n\n    <p>Request:</p>\n\n  <pre>{\n    formula: &lt;(FPCore (x) (- (sqrt (+ x 1)) (sqrt x)))&gt;,\n    language: \"python\"\n}</pre>\n\n    <p>Response:</p>\n\n  <pre>{\n    result: \"def expr(x): return math.sqrt((x + 1.0)) - math.sqrt(x)\"\n}</pre>\n\n    </details>\n\n    <p>The <code>translate</code> endpoint allows users to translate\n    FPCore expressions into equivalent expressions in various programming\n    languages.</p>\n\n    <p>Given an FPCore expression and a target language, this endpoint\n      returns the translated expression in the specified language.\n      The language parameter should be a string representing the desired\n      programming language. The response includes the translated expression.</p>\n\n    <p>Currently supported languages are: <code>python</code>, <code>c</code>,\n    <code>fortran</code>, <code>java</code>, <code>julia</code>, <code>matlab</code>,\n    <code>wls</code>, <code>tex</code>, and <code>js</code>.</p>\n  <h2>⚠️ Beta endpoints</h2>\n    <p>The endpoints below are currently a work in progress.</p>\n  <h2 id=\"localerror\">/api/localerror</h2>\n    <!--TODO--> Forthcoming.\n  <h2 id=\"timeline\">/api/timeline/{job-id}</h2>\n  <p>Retrieves the <code>timeline</code> data for a given API call. You may find the job id in either the JSON response or in the headers of the HTTP response for of the endpoints in Herbie.</p>\n  <p>The timeline is an exception to the others in that it uses a GET request. Below is a sample of what the request might look like. You may consult the <code>/infra/testApi.mjs</code> file for current examples of how to use this API.</p>\n  <pre class=\"shell\">curl -X GET \\\n  http://127.0.0.1:8000/api/timeline/0b95161a77fc3e29376bbb013d96c2827e2a1cd7\n      </pre>\n  </body>\n</html>\n"
  },
  {
    "path": "www/doc/2.1/diagrams.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Diagrams</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <script src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML\"></script>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Diagrams</h1>\n    <a href=\"../..\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>This page contains systems diagrams for Herbie.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"system-2.1.png\" alt=\"System diagram of Herbie\" />\n    <figcaption>\n    High-level system diagram of Herbie. It highlights Herbie's core architecture,\n      external libraries, and user interactions.\n    Basic flow: Herbie passes user input (expression, precondition, etc.) to\n      a sampler which generates points on which Herbie can evaluate\n      any candidate expression's error.\n    The mainloop (scheduler) then alternates between generate and test phases,\n      maintaining and improving a set of accurate expressions at each iteration.\n    Once the generate-and-test phase is complete, Herbie extracts either\n      one or many output expressions using an algorithm called regime inference.\n    Regime inference chooses the \"best\" (usually most accurate)\n      generated candidate expression or combines multple candidates,\n      each \"best\" on a smaller part of the input range, with a branch condition.\n    </figcaption>\n  </figure>\n  \n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.1/docker.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie on Docker</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Installing with Docker</h1>\n    <a href=\"../..\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> is available\n    through <a href=\"https://www.docker.com/\">Docker</a>, which is\n    sort of like a virtual machine. This page describes how to install\n    the <a href=\"https://hub.docker.com/r/uwplse/herbie\">official Docker\n    image</a> for Herbie.\n  </p>\n  \n  <p>\n    We recommend most users <a href=\"installing.html\">install Herbie\n    from package or source</a>. Herbie via Docker is only recommended\n    if you already have Docker experience.\n  </p>\n  \n  <h2>Installing Herbie via Docker</h2>\n\n  <p>\n    First, <a href=\"https://docs.docker.com/installation/\">install\n    Docker</a>. Docker supports Windows, macOS, and Linux. Depending\n    on how you install Docker, you may need to prefix\n    the <code>docker</code> commands with <code>sudo</code> or run them\n    as the administrative user.\n  </p>\n\n  <p>With Docker installed, you can run the <a href=\"using-cli.html\">Herbie shell</a> with:</p>\n\n  <pre>docker run -it uwplse/herbie shell</pre>\n  \n  <p>This will download the Herbie image and then run\n  its <a href=\"options.html\">shell tool</a>.</p>\n  \n  <p>Herbie in Docker is more limited; for example, it will not\n  recognize plugins installed outside the Docker container.</p>\n\n  <h2>Running the web interface</h2>\n\n  <p>\n    You can run the Herbie web server locally with\n\n  <pre class=\"shell\">docker run -it --rm -p 8000:80 uwplse/herbie</pre>\n\n    and access the server at <a href=\"http://localhost:8000\">http://localhost:8000</a>.\n    </p>\n    <p>\n      (Herbie's Docker image binds to port 80 by\n    default; this command uses the <code>-p &lt;hostport&gt;:80</code> option to expose Herbie on port 8000.)\n  </p>\n\n  <p>\n    If you are using the <code>--log</code>\n    or <code>--save-session</code> flags for the web shell,\n    you will also need to mount the relevant directories into the\n    Docker container using the <code>-v</code> Docker option, as in\n    the examples below.\n  </p>\n\n  <h2>Generating files and reports</h2>\n\n  <p>\n    To use Herbie in <a href=\"using-cli.html\">batch mode</a>, you will\n    need to mount the input in the Docker container. Do that with:\n  </p>\n  \n  <pre class=\"shell\">docker run -it --rm \\\n    -v <var>in-dir</var>:/in \\\n    -v <var>out-dir</var>:/out \\\n    -u $USER \\\n    uwplse/herbie improve /in/<var>in-file</var> /out/<var>out-file</var></pre>\n\n  <p>\n    In this command, you are asking Herbie to read input\n    from <var>in-file</var> in <var>in-dir</var>, and write output\n    to <var>out-file</var> in <var>out-dir</var>. The command looks\n    the same if you want Herbie to read input from a directory;\n    just leave <var>in-file</var> blank.\n  </p>\n\n  <p>\n    To generate reports from Herbie, you can run:\n  </p>\n\n  <pre class=\"shell\">docker run -it --rm \\\n    -v <var>in-dir</var>:/in \\\n    -v <var>out-dir</var>:/out \\\n    -u $USER \\\n    uwplse/herbie report /in/<var>in-file</var> /out/</pre>\n\n  <p>\n    As before, the input and output directories must be mounted inside\n    the Docker container. Note that both here and above, the user is\n    set to the current user. This is to ensure that the files Herbie creates\n    have the correct permissions set.\n  </p>\n\n  <h2>Building the Docker image</h2>\n\n  <p>This section is primarily of interest for the Herbie developers.</p>\n\n  <p>\n    Clone the repo and confirm that Herbie builds correctly\n    with <code>make install</code>.\n  </p>\n\n  <p>\n    Next, examine the Dockerfile and Makefile together. The Dockerfile\n    should follow a process exactly like the Makefile, except a clean\n    initial environment is assumed. The build may be split into 2 or\n    more stages to limit the size of the resulting image. Each stage\n    consists of a <code>FROM</code> command and a series of further\n    commands to build up the desired environment, and later stages can\n    refer to earlier stages by name&mdash;for example, <code>COPY\n    --from=earlier-stage ...</code> can copy files compiled in earlier\n    images. You may need to do things like bumping the version of Rust\n    used for binary compilation or the version of Racket used in\n    production, or adjusting paths to match the newest version of the\n    repo.\n  </p>\n\n  <p>Once you are ready to build, run this command from the repository root:</p>\n\n  <pre class=\"shell\">docker build -t uwplse/herbie:test .</pre>\n\n  <p>This builds a new test image and tags\n  it <code>uwplse/herbie:test</code>. You can run this image with:</p>\n\n  <pre class=\"shell\">docker run -p 8000:80 -it uwplse/herbie:test</pre>\n\n  <p>The web demo should now be visible at <code>http://localhost:8000</code>.</p>\n  \n  <p>To open a shell in a running container for testing, first get the container ID with:</p>\n\n  <pre class=\"shell\">docker ps</pre>\n\n  <p>Then open a root shell in that container with</p>\n\n  <pre class=\"shell\">docker exec -it &lt;CONTAINER ID&gt; sh</pre>\n  \n  <p>The code and egg-herbie binaries should be\n  under <code>/src</code>.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.1/error.html",
    "content": "<!doctype html>\n<meta charset=\"utf-8\" />\n<title>What is Error?</title>\n<link rel='stylesheet' type='text/css' href='../../main.css'>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<script type=\"text/javascript\" src=\"toc.js\"></script>\n\n<header>\n  <h1>What is Error?</h1>\n  <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n  <nav>\n    <ul>\n      <li><a href=\"../../demo/\">Try</a></li>\n      <li><a href=\"installing.html\">Install</a></li>\n      <li><a href=\"tutorial.html\">Learn</a></li>\n    </ul>\n  </nav>\n</header>\n\n<p>\n  <a href=\"../../\">Herbie</a> helps you identify and correct floating\n  point error in your numeric programs. But what is floating point\n  error, and how does Herbie measure it?\n</p>\n\n<h2>The summary</h2>\n\n<p>When Herbie reports a \"percentage accuracy\" number like 92.3%, it's\nusually best to think of that as the percentage of floating-point\ninputs where the expression is reasonably accurate.</p>\n\n<p>The impact of this error on your application will depend a lot\non <em>which</em> 7.7% of inputs are inaccurate, and what kind of\nerror that is. You can find this out using\nthe <a href=\"report.html\">accuracy graph in Herbie reports</a>. You\ncan also use preconditions to restrict the inputs Herbie is\nconsidering.</p>\n\n<h2>Why rounding matters</h2>\n\n<p>In mathematics, we work with real numbers, but on a computer, we\ntypically use floating-point numbers. Because there are infinitely\nmany real numbers, but only finitely many floating-point numbers, some\nreal numbers can't be accurately represented. This means that every\ntime you do an operation, the true result typically has to\nbe <em>rounded</em> to a representable one.</p>\n\n<p>Take an extreme example: the code <code>1e100 + 1</code>, which\nincrements a huge number in IEEE 754 double-precision floating-point.\nThere's an exact real-number answer, a one followed by 99 zeros and\nthen another 1, but the closest <em>floating-point</em> value is the\nsame as <code>1e100</code>.</p>\n\n<p>Errors like this can cause problems. In the example above, the\nanswers differ by one part per googol, which is pretty small. But the\nerror can grow. For example, since <code>1e100 + 1</code> rounds to\nthe same value as <code>1e100</code>, the larger computation\n\n<pre>(1e100 + 1) - 1e100</pre>\n\nreturns <code>0</code> instead of the correct answer, <code>1</code>.\nNow the difference is pretty stark, and can grow even bigger through\nlater operations.</p>\n\n<h2>Bits of error</h2>\n\n<p>There are lots of ways to <em>measure</em> how much rounding error\nthere is in a computation. Most people find the notions of absolute\nand relative error most intuitive, but Herbie internally uses a more\ncomplex notion called <em>bits of error</em>.</p>\n\n<p>The bits of error metric imagines you have a list of all of the\npossible floating-point numbers, from largest to smallest. In that\nlist, compare the floating-point value you computed to the one closest\nto the true answer. If they are the same, that's called 0 bits of\nerror; if they are one apart, that's called one bit of error; three\napart is two bits of error; and so on.</p>\n\n<p>In general, if the two floating-point values are <var>n</var> items\napart, Herbie says they have <code>log2(n + 1)</code> bits of error.\nValues like <code>0</code> and <code>-0</code> are treated as having 0\nbits of error, and <code>NaN</code> is considered to have the maximum\nnumber of bits of error against non-<code>NaN</code> values. While\nthere's all sorts of theoretical justifications, Herbie mainly uses\nthis error metric because we've found it to give the best\nresults. </p>\n\n<p>On a single input, the best way to interpret the \"bits of error\"\nmetric is that it tells you roughly how many bits of the answer,\nstarting at the end, are useless. With zero bits of error, you have\nthe best answer possible. With four bits, that's still pretty good\nbecause it's four out of 64. But with 40 or 50 bits of error, you're\ngetting less accuracy out of the computation than even a\nsingle-precision floating-point value. And it's even possible to have\nsomething like 58 or 60 bits of error, in which case even the sign and\nexponent bits (which in double-precision floating-point occupy the top\n12 bits of the number) are incorrect.</p>\n\n<h2>Percentage accuracy</h2>\n\n<p>Because different number representations have different numbers of\nbits, Herbie shows the percentage of bits that are accurate instead of\nthe bits of error. With double-precision floats, for example, 75%\naccurate means 16 bits of error.</p>\n\n<p>Bits of error measures the error of a computation for some specific\ninput. But usually you're interested in the error of a computation\nacross many possible inputs. Herbie therefore averages the accuracy\npercentage across many randomly-sampled valid inputs.</p>\n\n<p>Typically, inputs points are either very accurate or not accurate\nat all. So when computing percentage accuracy, Herbie's averaging a\nlot of points with near-100% accuracy and a lot of points with near-0%\naccuracy. In that sense, you can think of percentage accuracy as\nmeasuring mostly what percentage <em>of inputs</em> are accurate. If\nHerbie says your computation is 75% accurate what it's really saying\nis that about a quarter of inputs produce usable outputs.</p>\n\n<h2>Valid inputs</h2>\n\n<p>Since percentage accuracy averages over many points, it depends on\nwhat points it is averaging over, and how is samples among them.\nHerbie samples among <em>valid</em> inputs, uniformly distributed.</p>\n\n<p>Herbie considers an input valid if it is a floating-point value in\nthe appropriate precision and its true, real-number output 1) exists;\n2) satisfies the user's precondition; and 3) can be computed. Let's\ndive into each requirement.</p>\n\n<ol>\n  <li>An output can fail to exist for an input if that input does\n    something like divide by zero or take the square root of a\n    negative number. Then that input is invalid.</li>\n  <li>An input can fail to satisfy the user's precondition.\n    Preconditions can be basically anything, but most often they\n    specify a range of inputs. For example, if the precondition\n    is <code>(&lt; 1 x 2)</code>, then the input <code>x = 3</code> is\n    invalid.</li>\n  <li>Finally, and most rarely, Herbie can fail to compute the output\n    for a particular input. For example, the computation <code>(/ (exp\n    1e9) (exp 1e9))</code>, which divides two identical but gargantuan\n    numbers, does have an exact real-number answer (one), but Herbie\n    can't compute that exact answer because the intermediate steps are\n    too large. This input is also invalid, but you'll\n    get <a href=\"faq.html#ground-truth\">a warning</a> if this\n    happens.</li>\n</ol>\n\n<p>Herbie's percentage accuracy metric only averages over valid\npoints. This means that when you change your precondition, you change\nwhich points are valid, and that can change the percentage accuracy\nreported by Herbie. This is useful: if you know there's a rare error,\nbut Herbie thinks error is low, you can change your precondition to\nfocus on the points of interest.</p>\n\n<p>Some inputs are valid in surprising ways. For example, consider the\nexpression <code>(exp x)</code> for <code>x = 1e100</code>. The true\nreal-number result is a very large but finite number; but that real\nnumber, whatever it is, rounds to infinity in double-precision\nfloating point. Herbie does consider this input valid, but infinite\nvalues are a little odd in floating-point so you might find this\nsurprising. For this reason, Herbie\nissues <a href=\"faq.html#inf-points\">a warning</a> if too many outputs\nare infinite.</p>\n\n<h2>Sampling inputs</h2>\n\n<p>When randomly sampling inputs, Herbie considers each valid input\nequally likely. Importantly, this does not mean that it uses a uniform\ndistribution, because floating-point values themselves are not\nuniformly distributed.</p>\n\n<p>For example, there are as many floating-point values between 1 and\n2 as there are between one and one half, because floating-point values\nuse an exponential encoding. But that means that if you're looking at\na computation where the input comes from the interval <kbd>[0.5,\n2]</kbd>, Herbie will weigh the first third of that range twice as\nhigh as the other two thirds.</p>\n\n<p>This can produce unintuitive results, especially for intervals that\ncross 0. For example, in the interval <kbd>[0, 1]</kbd>, the second\nhalf of that interval (from one half to one) has a tiny proportion of\nthe weight (in double-precision floating-point, about 0.1%). If Herbie\ncan improve accuracy by a little bit between zero and one half, while\ndramatically reducing accuracy between one half and one, it will think\nthat that's an accuracy improvement. You might disagree.</p>\n\n<p>Unfortunately, there's no way for Herbie to intuit exactly what you\nmean, so understanding this error distribution is essential to\nunderstanding Herbie's outputs. For example, if Herbie reports that\naccuracy improved from 75% to 76%, it's essential to know: is the\nimprovement happening on inputs between one half and one, or\nbetween <code>1e-100</code> and <code>2e-100</code>? To answer this\nquestion, it's important to look over\nthe <a href=\"report.html\">reports and graphs</a> generated by\nHerbie.</p>\n"
  },
  {
    "path": "www/doc/2.1/faq.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie FAQ</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Common Errors and Warnings</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p><a href=\"../../\">Herbie</a> automatically transforms floating\n  point expressions into more accurate forms. This page troubleshoots\n  common Herbie errors, warnings, and known issues.</p>\n\n\n  <h2>Common errors</h2>\n\n  <p>\n    Herbie error messages refer to this second for additional\n    information and debugging tips.\n  </p>\n\n  <h3 id=\"invalid-syntax\">Invalid syntax</h3>\n\n  <p>\n    This error means you mis-formatted Herbie's input. Common errors\n    include misspelled function names and parenthesized expressions\n    that should not be parenthesized. For example, in\n    <code>(- (exp (x)) 1)</code>, the expression <code>x</code> is a\n    variable so shouldn't be parenthesized. <code>(- (exp x) 1)</code>\n    would be the correct way to write that expression.\n    The <a href=\"input.html\">input format</a> documentation has more\n    details on Herbie's syntax.\n  </p>\n\n  <h3 id=\"sample-valid-points\">Cannot sample enough valid points</h3>\n\n  <p>This error occurs when Herbie is unable to find enough valid\n  points. For example, the expression <code>(acos (+ 1000 x))</code>\n  is invalid unless <code>(&lt;= -1001 x -999)</code>, a rather narrow\n  range. The simplest fix is to increase\n  the <a href=\"options.html\"><code>--num-analysis</code> flag</a>.\n  Specifying the range of valid points as\n  a <a href=\"input.html#preconditions\">precondition</a> can also help.\n  </p>\n\n  <h3 id=\"no-valid-values\">No valid values</h3>\n\n  <p>This error indicates that your input has no valid inputs, usually\n  due to an overly restriction precondition. For example, the\n  precondition <code>(&lt 3 x 2)</code> excludes all inputs. The\n  solution is to fix the precondition or input program.</p>\n\n\n  <h2>Common warnings</h2>\n\n  <p>Herbie warnings refer to this section for explanations and common\n  actions to take.</p>\n  \n  <h3 id=\"inf-points\">Infinite outputs for <var>N</var>% of points.</h3>\n  \n  <p>\n    Sometimes, an input to your expression produces an output so large\n    that it's best represented by a floating-point infinity. For\n    example, <code>(exp 1000)</code> is over 10<sup>434</sup>, so it's\n    much larger than the largest floating-point value. Herbie raises\n    this warning when too many inputs (more than 20% of them) are this\n    large, because that usually indicates you should set a more\n    restrictive precondition.\n  </p>\n\n  <h3 id=\"ground-truth\">Could not determine a ground truth</h3>\n\n  <p>\n    Herbie raises this warning when some inputs require more than\n    10,000 bits to compute an exact ground truth. For example, to\n    compute <code>(/ (exp x) (exp x))</code> for very\n    large <code>x</code>, absurdly large numbers would be required.\n    Herbie discards such inputs and raises this warning. If you see\n    this warning, you should add a restrictive precondition, such\n    as <code>:pre (&lt; -100 x 100)</code>, to prevent large inputs.\n  </p>\n\n  <h3 id=\"value-to-string\">Could not uniquely print <var>val</var></h3>\n\n  <p>\n    Herbie will raise this warning when it needs more than 10,000 bits\n    to produce a string representation for a given value. This is\n    likely the result of a bug in a third-party plugin.\n  </p>\n\n  <h3 id=\"unsound-rules\">Unsound rule application detected</h3>\n  \n  <p>\n    Herbie uses a set of algebraic rewrite rules in order to simplify\n    expressions, but these rules can sometimes lead to a\n    contradiction. Herbie will automatically compensate for this, and\n    in most cases nothing needs to be done. However, Herbie may have\n    failed to simplify the output.\n  </p>\n\n  <h3 id=\"unused-variable\">Unused variable <var>var</var></h3>\n  \n  <p>\n    The input FPCore contains a variable that is not\n      used in the body expression.\n  </p>\n\n  <h3 id=\"strange-variable\">Strange variable <var>var</var></h3>\n  \n  <p>\n    The input expression contains a variable that is similar in name\n      to named constants, e.g. <var>e</var> instead of <var>E</var>.\n  </p>\n\n  <h2>Known bugs</h2>\n\n  <p>Bugs that cannot be directly fixed are documented in this section.</p>\n\n  <h3 id=\"chrome-missing-report\">Missing reports chart on Chrome</h3>\n\n  <p>\n    When using Chrome to view web pages on your local machine, Herbie\n    reports cannot draw the arrow chart due to security restrictions.\n    <a href=\"http://www.chrome-allow-file-access-from-file.com/\">Run\n    Chrome with <code>--allow-file-access-from-files</code></a> to fix\n    this error.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.1/input.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Input Format</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>The Input Format</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> uses\n    the <a href=\"http://fpbench.org\">FPCore</a> format to specify an\n    input program, and has extensive options for precisely describing\n    its context.\n  </p>\n\n  <h2>Math format</h2>\n\n  <p>The Herbie web shell takes input in a subset of\n  the <a href=\"https://mathjs.org/docs/expressions/syntax.html\">math.js\n  syntax</a>. The web shell automatically checks for syntax errors,\n  and provides a graphical user interface for specifying the input\n  domain. The web shell converts the mathematical expression and input\n  ranges into FPCore before sending it to Herbie.</p>\n  \n  <h2 id=\"sec1\">FPCore format</h2>\n\n  <p>Herbie's command-line and batch-mode tools\n  use <a href=\"http://fpbench.org\">FPCore</a> format to describe\n  mathematical expressions. FPCore looks like this:</p>\n\n  <pre>(FPCore (<var>inputs ...</var>) <var>properties ...</var> <var>expression</var>)</pre>\n  <pre>(FPCore <var>name</var> (<var>inputs ...</var>) <var>properties ...</var> <var>expression</var>)</pre>\n\n  <p>\n    Each <var>input</var> is a variable name, like <code>x</code>,\n    used in the <var>expression</var>. Properties are used to specify\n    additional information about the <var>expression</var>'s context.\n    If <var>name</var> is specified, the function can be referenced in\n    subsequent FPCore declarations in the file.\n  </p>\n\n  <p>\n    The expression is written in prefix form, with every function call\n    parenthesized, as in Lisp. For example, the formula for the\n    hypotenuse of a triangle with legs <i>a</i> and <i>b</i> is:\n  </p>\n\n  <pre>(FPCore (a b) (sqrt (+ (* a a) (* b b))))</pre>\n\n  <p>\n    The semicolon (<kbd>;</kbd>) character introduces a line comment.\n    We recommend the <code>.fpcore</code> file extension for Herbie input files.\n  </p>\n  \n  <h2>Supported functions</h2>\n  \n  <p>\n    Herbie supports all functions\n    from <a href=\"http://pubs.opengroup.org/onlinepubs/7908799/xsh/math.h.html\">math.h</a>\n    with floating-point-only inputs and outputs. The best supported\n    functions include:\n  </p>\n\n  <dl class=\"function-list\">\n    <dt><code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>, <code>fabs</code></dt>\n    <dd>The usual arithmetic functions</dd>\n    <dt><code>sqrt</code>, <code>cbrt</code></dt>\n    <dd>Square and cube roots</dd>\n    <dt><code>pow</code>, <code>exp</code>, <code>log</code></dt>\n    <dd>Various exponentiations and logarithms</dd>\n    <dt><code>sin</code>, <code>cos</code>, <code>tan</code></dt>\n    <dd>The trigonometric functions</dd>\n    <dt><code>asin</code>, <code>acos</code>, <code>atan</code>, <code>atan2</code></dt>\n    <dd>The inverse trigonometric functions</dd>\n    <dt><code>sinh</code>, <code>cosh</code>, <code>tanh</code></dt>\n    <dd>The hyperbolic functions</dd>\n    <dt><code>asinh</code>, <code>acosh</code>, <code>atanh</code></dt>\n    <dd>The inverse hyperbolic functions</dd>\n    <dt><code>fma</code>, <code>expm1</code>, <code>log1p</code>, <code>hypot</code></dt>\n    <dd>Specialized numeric functions</dd>\n  </dl>\n\n  <p>Herbie also supports the constants <code>PI</code>\n  and <code>E</code>. Use <code>-</code> for both subtraction and negation.</p>\n\n  <p>Herbie links against your computer's <code>libm</code> to\n  evaluate these functions. So, each function has the same behavior in\n  Herbie as in your code. You can instead use\n  the <a href=\"#precisions\"><code>racket</code> precision</a> if you\n  instead want reproducible behavior.</p>\n\n  <h2 id=\"conditionals\">Conditionals</h2>\n  \n  <p>FPCore uses <code>if</code> for conditional expressions:</p>\n\n  <pre>(if <var>cond</var> <var>if-true</var> <var>if-false</var>)</pre>\n\n  <p>\n    The conditional <code><var>cond</var></code> may use:\n  </p>\n  \n  <dl class=\"function-list\">\n    <dt><code>==</code>, <code>!=</code>, <code>&lt;</code>, <code>&gt;</code>, <code>&lt;=</code>, <code>&gt;=</code></dt>\n    <dd>The usual comparison operators</dd>\n    <dt><code>and</code>, <code>or</code>, <code>not</code></dt>\n    <dd>The usual logical operators</dd>\n    <dt><code>TRUE</code>, <code>FALSE</code></dt>\n    <dd>The two boolean values</dd>\n  </dl>\n\n  <p>The comparison functions support chained comparisons with more than two arguments.</p>\n\n  <h2 id=\"intermediates\">Intermediate variables</h2>\n  \n  <p>Intermediate variables can be defined\n    using <code>let</code> and <code>let*</code>:</p>\n\n  <pre>(let ([<var>variable</var> <var>value</var>] <var>...</var>) <var>body</var>)</pre>\n  <pre>(let* ([<var>variable</var> <var>value</var>] <var>...</var>) <var>body</var>)</pre>\n\n  <p>In both <code>let</code> and <code>let*</code>,\n  each <var>variable</var> is bound to its <var>value</var> and can be\n  used in the <var>body</var>. The difference between <code>let</code>\n  and <code>let*</code> is what order the values are\n  evaluated in:</p>\n\n  <dl>\n    <dt><code>let</code> expressions</dt>\n    <dd>In a <code>let</code> expression, all the values are evaluated\n      in parallel, before they are bound to their variables. This\n      means that later values can't refer to earlier variables in the\n      same <code>let</code> block.</dd>\n\n    <dt><code>let*</code> expressions</dt>\n    <dd>A <code>let*</code> block looks the same as a <code>let</code>\n      block, except the values are evaluated one at a time, and later\n      values can refer to earlier variables.</dd>\n  </dl>\n\n  <p>Unless you have a lot of Lisp experience, you'll probably\n  find <code>let*</code> more intuitive.</p>\n\n  <p>Internally, Herbie treats intermediate values only as a\n  notational convenience, and inlines their values before improving\n  the formula's accuracy. Using intermediate variables will therefore\n  not produce a more accurate result or help Herbie run faster.</p>\n\n  <h2 id=\"specs\">Specifications</h2>\n\n  <p>In some cases, your input program is an approximation of some\n  more complex mathematical expression. The <code>:spec</code> (for\n  “specification”) lets you specify the more complex ideal case.\n  Herbie will then try to modify the input program to make it more\n  accurately evaluate the specification.</p>\n\n  <p>For example, suppose you want to evaluate <code>sin(1/x)</code>\n  via a series expansion. Write:</p>\n\n  <pre>(FPCore (x)\n  :spec (sin (/ 1 x))\n  (+ (/ 1 x) (/ 1 (* 6 (pow x 3)))))</pre>\n\n  <p>Herbie will only use the <code>:spec</code> expression to\n  evaluate error, not to search for accurate expressions.</p>\n\n  <h2 id=\"preconditions\">Preconditions</h2>\n\n  <p>By default, the arguments to formulas are assumed to be\n  arbitrarily large or small floating-point numbers. However, in most\n  programs a smaller range of argument values is possible.\n  The <code>:pre</code> property (for “precondition”) describes this\n  smaller range.</p>\n\n  <p>Preconditions use comparison and boolean operators, just\n  like <a href=\"#conditionals\">conditional statements</a>:</p>\n\n  <pre>(FPCore (x) :pre (&lt; 1 x 10) (/ 1 (- x 1)))</pre>\n\n  <p>Herbie is particularly efficient when when the precondition is\n  an <code>and</code> of ranges for each variable, but more complex\n  preconditions also work.</p>\n\n  <h2 id=\"precisions\">Precisions</h2>\n\n  <p>Herbie supports both single- and double-precision values; you can\n  specify the precision with the <code>:precision</code> property:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>binary32</code></dt>\n    <dd>Single-precision IEEE-754 floating point</dd>\n    <dt><code>binary64</code></dt>\n    <dd>Double-precision IEEE-754 floating point</dd>\n    <dt><code>racket</code></dt>\n    <dd>Like <code>binary64</code>, but using Racket math functions\n      rather than your computer's <code>libm</code>.</dd>\n  </dl>\n\n  <p>By default, <code>binary64</code> is assumed. Herbie also has\n  a <a href=\"plugins.html\">plugin system</a> to load additional\n  precisions.</p>\n\n  <p>Herbie won't produce mixed-precision code unless you allow it to\n  do so, using the <code>:herbie-conversions</code> property:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>:herbie-conversions<br/>([<var>prec1</var> <var>prec2</var>] ...)</code></dt>\n    <dd>Expressions in precision <code>prec1</code>, can be rewriten\n    to use precision <code>prec2</code>, and vice versa.</dd>\n  </dl>\n\n  <p>All conversions are assumed to be bidirectional. For example, if\n  you specify <code>:herbie-conversions ([binary64 binary32])</code>,\n  Herbie will be able to add conversions between single- and\n  double-precision floating-point.</p>\n\n  <h2 id=\"properties\">Miscellaneous Input Properties</h2>\n\n  <p>Herbie uses the <code>:name</code> property to name FPCores in\n  its UI. Its value ought to be a string.</p>\n\n  <p>Herbie allows <code>:alt</code> properties to specify additional\n  \"developer targets\"; these might be other alternatives you've tried\n  that you want to compare against.</p>\n\n  <h2 id=\"output-properties\">Additional Output Metadata</h2>\n\n  <p>Herbie's output provides additional information in custom\n  properties:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>:herbie-status <var>status</var></code></dt>\n    <dd><var>status</var> describes whether Herbie worked: it is one\n    of <code>success</code>, <code>timeout</code>, <code>error</code>,\n    or <code>crash</code>.</dd>\n    <dt><code>:herbie-time <var>ms</var></code></dt>\n    <dd>The time, in milliseconds, used by Herbie to find a more accurate formula.</dd>\n    <dt><code>:herbie-error-input<br/>([<var>pts</var> <var>err</var>] ...)</code></dt>\n    <dd>The average <var>err</var>or of the input program at <var>pts</var> points. Multiple entries correspond to Herbie's training and test sets.</dd>\n    <dt><code>:herbie-error-output<br/>([<var>pts</var> <var>err</var>] ...)</code></dt>\n    <dd>The computed average error of the output program, similar to <code>:herbie-error-input</code>.</dd>\n  </dl>\n\n  <p>Herbie's benchmark suite also uses properties for continuous\n  integration, but these are not officially supported and their use is\n  discouraged.</p>\n  \n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.1/installing.html",
    "content": "<!doctype html>\n<html>\n\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Installing Herbie</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n\n<body>\n  <header>\n    <h1>Installing Herbie</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> supports Linux, macOS, and Windows.\n    To start, install <a href=\"https://racket-lang.org\">Racket</a>,\n    which Herbie is written in. Then install Herbie, either from a\n    package, from source, or via a <a href=\"docker.html\">Docker\n    image</a>.\n  </p>\n\n  <h2>Installing Racket</h2>\n\n  <p>\n    Install Racket either using\n    the <a href=\"http://download.racket-lang.org/racket-v8.13.html\">official\n      installer</a> or distro-provided packages. Versions as old as 8.0\n    are supported, but more recent versions are faster. We strongly recommend\n    v8.7 or newer.\n  </p>\n\n  <p>\n    On Linux, we recommend against installing Racket via Snap. If you\n    must install Racket from Snap, locate Herbie and all other\n    packages in your home directory or another allow-listed directory.\n  </p>\n\n  <p>\n    Test that Racket is installed correctly and has a correct version:\n  </p>\n\n  <pre class=\"shell\">racket\nWelcome to Racket v8.13 [cs].\n> (exit)</pre>\n\n  <h2>Installing Herbie from a package</h2>\n\n  <p>\n    Herbie can be installed from a binary package on Windows and Linux\n    for x86-64, and on macOS on either x86-64 or ARM. If you are on a\n    more obscure platform, please install from source instead.</p>\n\n  <p>First install Racket. Then install Herbie from a package\n  with:</p>\n\n  <pre class=\"shell\">raco pkg install --auto herbie</pre>\n\n  <p>Then check that Herbie works by running:</p>\n\n  <pre class=\"shell\">racket -l herbie -- --version\nHerbie 2.1</pre>\n\n  <p>If you'd like, you can run Herbie with the <code>herbie</code>\n  command by adding the following directory to your PATH (example\n  paths for Racket 8.13):</p>\n\n  <ul>\n    <li>On Windows, <code>AppData\\Roaming\\Racket\\8.13\\bin</code> in your user folder.</li>\n    <li>On macOS, <code>Library/Racket/8.13/bin</code> in your home folder.</li>\n    <li>On Linux, <code>.local/share/racket/8.13/bin</code> in your home directory.</li>\n  </ul>\n\n  <p>\n    Please note that the path of the binary will be different on Linux\n    if you have opted (against recommendation) to use Snap. Once\n    Herbie is installed and working correctly, check out\n    the <a href=\"tutorial.html\">tutorial</a>.\n  </p>\n\n  <!-- End of copy -->\n\n  <h2>Installing Herbie from source</h2>\n  \n  <p>\n    Installing Herbie from source is best if you plan to develop\n    Herbie or Herbie <a href=\"plugins.html\">plugins</a>, or if you use\n    a more obscure hardware/OS combination. The instructions assume a\n    standard Unix userland; on Windows, you may have to install tools\n    like Make separately, or use WSL.\n  </p>\n\n  <p>\n    Install Racket. Then install Rust,\n    using <a href=\"https://rustup.rs/\">rustup</a> or via some other\n    means. Versions as old as 1.60.0 are supported.\n  </p>\n\n  <p>\n    Once Racket and Rust are installed, download the Herbie source\n    <a href=\"https://github.com/uwplse/herbie\">from GitHub</a> with:\n  </p>\n\n  <pre class=\"shell\">git clone https://github.com/uwplse/herbie</pre>\n\n  <p>\n    Change to the <code>herbie</code> directory;\n    you should see a <code>README.md</code> file, a directory named <code>src</code>,\n    a directory named <code>bench/</code>, and a few other directories.\n    Install Herbie with:\n  </p>\n\n  <pre class=\"shell\">make install</pre>\n\n  <p>This command installs Herbie and its dependencies and compiles it\n  for faster startup. Check that Herbie works by running:</p>\n\n  <pre class=\"shell\">racket -l herbie -- --version\nHerbie 2.1</pre>\n\n  <p>\n    You can also follow the install-from-package instructions to\n    add <code>herbie</code> to your path, if you'd like.' Once Herbie\n    is installed and working correctly, check out\n    the <a href=\"tutorial.html\">tutorial</a>.\n  </p>\n\n  <h2>Installing Herbie with Docker</h2>\n\n  <p>\n    <a href=\"https://docker.com\">Docker</a> is a container manager,\n    which is sort of like a virtual machine. Herbie in Docker is more\n    limited; we do not recommend using Herbie through Docker without\n    prior Docker experience.\n  </p>\n\n  <p>\n    The <a href=\"docker.html\">Docker documentation</a> describes how\n    to install and run the official <code>uwplse/herbie</code> image.\n  </p>\n\n</body>\n\n</html>\n"
  },
  {
    "path": "www/doc/2.1/options.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Command-line Options</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Command-line Options</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>The <a href=\"../../\"><code>herbie</code></a> command has\n  subcommands and options that influence both its user interface and\n  the quality of its output.</p>\n\n  <h2>Herbie commands</h2>\n\n  <p>There are a few different methods for interacting with Herbie, which we call\n  tools. For example, Herbie can be run both interactively or in batch mode, and\n  can generate output intended for the <a href=\"using-cli.html\">command line</a>\n  or for <a href=\"using-web.html\">the web</a>. Herbie provides four of these\n  tools as subcommands:<p>\n\n  <dl>\n    <dt><code>racket -l herbie web</code></dt>\n    <dd>Use Herbie <a href=\"using-web.html\">through your browser</a>.\n    The <code>web</code> command runs Herbie on your local\n    machine and opens its main page in your browser.</dd>\n\n    <dt><code>racket -l herbie shell</code></dt>\n    <dd>Use Herbie <a href=\"using-cli.html\">via a command-line shell</a>.\n    Enter an <a href=\"input.html\">FPCore expression</a> and Herbie\n    will print its more-accurate version.</dd>\n\n    <dt><code>racket -l herbie improve <var>input</var> <var>output</var></code></dt>\n    <dd>Run Herbie on the expressions in the file or\n    directory <var>input</var>. The results are written\n    to <var>output</var>, a single file in FPCore format.</dd>\n\n    <dt><code>racket -l herbie report <var>input</var> <var>output</var></code></dt>\n    <dd>Run Herbie on the expressions in the file or\n    directory <var>input</var>. The results are written\n    to <var>output</var>, a directory of\n    HTML <a href=\"report.html\">reports</a>. Viewing these requires a\n    web server.</dd>\n  </dl>\n\n  <p>We recommend <code>web</code> which\n  produces <a href=\"report.html\">reports</a> with lots of information\n  about floating-point accuracy, including graphs of error versus\n  input values and plots comparing cost and accuracy. This can help\n  you understand whether Herbie's improvements matter for your use\n  case.</p>\n\n  <p>Use <code>herbie <var>tool</var> --help</code> to view available\n  command-line options for a tool. This command also shows\n  undocumented subcommands not listed on this page.</p>\n\n  <h2>General options</h2>\n\n  <p>\n    These options can be set on any tool. Pass them after the tool\n    name but before other arguments, like this:\n  </p>\n\n  <pre class=\"shell\">racket -l herbie report --timeout 60 in.fpcore out/</pre>\n\n  <p>Arguments cannot go before options.</p>\n\n  <dl>\n    <dt><code>--seed S</code></dt>\n    <dd>The random seed, which changes the randomly-selected points\n      that Herbie evaluates candidate expressions on. The seed is a\n      number between 0 and 2<sup>31</sup> (not including the latter).\n      This option can be used to make Herbie's results reproducible or\n      to compare two different runs. If not specified, a random seed\n      is chosen.</dd>\n\n    <dt><code>--num-points N</code></dt>\n    <dd>The number of input points Herbie uses to evaluate candidate\n      expressions. The default, 256, is a good balance for most\n      programs. Increasing this option, say to 512 or 1024, will slow\n      Herbie down but may make its results more consistent.</dd>\n\n    <dt><code>--num-iters N</code></dt>\n    <dd>The number of times Herbie attempts to improve accuracy. The\n      default, 4, suffices for most programs and helps keep Herbie\n      fast; in practice iterations beyond the first few rarely lead to\n      lower error. Increase this option, say to 6, to check that there\n      aren't further improvements that Herbie could seek out.</dd>\n\n    <dt><code>--num-analysis N</code></dt>\n    <dd>The number of input subdivisions to use when searching for\n      valid input points. The default is 12. Increasing this option\n      will slow Herbie down, but may fix the\n      \"<a href=\"faq.html#sample-valid-points\">Cannot sample enough\n      valid points</a>\" error.</dd>\n    \n    <dt><code>--num-enodes N</code></dt>\n    <dd>The number of equivalence graph nodes to use when doing\n    algebraic reasoning. The default is 8000. Increasing this option\n    will slow Herbie down, but may improve results slightly.</dd>\n    \n    <dt><code>--timeout T</code></dt>\n    <dd>The timeout to use per-input, in seconds. A fractional number\n      of seconds can be given.</dd>\n\n    <dt><code>--threads N</code> (for the <code>improve</code> and <code>report</code> tools)</dt>\n    <dd>Enables multi-threaded operation. By default, no threads are\n      used. A number can be passed to this option to use that many\n      threads, or <code>yes</code> can be passed to tell Herbie to use\n      all of the hardware threads.</dd>\n\n    <dt><code>--no-pareto</code></dt>\n    <dd>Disables cost-aware search. Herbie will only return a single\n    program, which optimizes exclusively for accuracy. Herbie will be\n    slightly faster as a result.</dd>\n  </dl>\n\n  <h2>Web shell options</h2>\n  \n  <p>The <code>web</code> tool runs Herbie and connects to it from\n  your browser. It has options to control the underlying web\n  server.</p>\n  \n  <dl>\n    <dt><code>--port N</code></dt>\n    <dd>The port the Herbie server runs on. The default port is 8000.</dd>\n\n    <dt><code>--save-session dir</code></dt>\n    <dd>Save all the reports to this directory. The directory also\n    caches previously-computed expressions.</dd>\n\n    <dt><code>--log file</code></dt>\n    <dd>Write an access log to this file, formatted like an Apache\n    log. This log does <em>not</em> contain crash tracebacks.</dd>\n\n    <dt><code>--quiet</code></dt>\n    <dd>By default, but not when this option is set, a browser is\n    automatically started to show the Herbie page. This option also\n    shrinks the text printed on start up.</dd>\n\n    <dt><code>--no-browser</code></dt>\n    <dd>This flag disables the default behavior of opening the Herbie page in your default browser.</dd>\n\n    <dt><code>--public</code></dt>\n    <dd>When set, users on other computers can connect to the demo and\n    use it. (In other words, the server listens\n    on <code>0.0.0.0</code>.) Essential when Herbie is run\n    from <a href=\"docker.html\">Docker</a>.</dd>\n  </dl>\n\n  <h2>Rulesets</h2>\n\n  <p>\n    Herbie uses rewrite rules to change programs and improve accuracy.\n    The <code>--disable rules:<var>group</var></code>\n    and <code>--enable rules:<var>group</var></code> options turn rule\n    sets on and off. In general, turning a ruleset on makes Herbie\n    produce more accurate programs.\n  </p>\n\n  <p>The full list of rule groups is:</p>\n\n  <table class=\"function-list\">\n    <thead><tr><th>Rule Group</th><th>Topic of rewrite rules</th></tr></thead>\n    <tr><td>arithmetic</td><td>Basic arithmetic facts</td></tr>\n    <tr><td>polynomials</td><td>Factoring and powers</td></tr>\n    <tr><td>fractions</td><td>Fraction arithmetic</td></tr>\n    <tr><td>exponents</td><td>Exponentiation identities</td></tr>\n    <tr><td>trigonometry</td><td>Trigonometric identities</td></tr>\n    <tr><td>hyperbolic</td><td>Hyperbolic trigonometric identities</td></tr>\n    <tr><td>bools</td><td>Boolean operator identities</td></tr>\n    <tr><td>branches</td><td><code>if</code> statement simplification</td></tr>\n    <tr><td>special</td><td>The gamma and error functions</td></tr>\n    <tr><td>numerics</td><td>Numerical shorthands <code>expm1</code>, <code>log1p</code>, <code>fma</code>, and <code>hypot</code></td></tr>\n  </table>\n\n  <h2>Search options</h2>\n\n  <p>\n    These options change the types of transformations that Herbie uses\n    to find candidate programs. We recommend sticking to the defaults.\n  </p>\n\n  <p>\n    Each option can be turned off with the <code>-o</code>\n    or <code>--disable</code> command-line flag and on with\n    <code>+o</code> or <code>--enable</code>. Turning an option off\n    typically results in less-accurate results, while turning a option\n    on typically results in more confusing output expressions.\n  </p>\n\n  <dl>\n    <dt><code>setup:search</code></dt>\n    <dd>This option, on by default, uses interval subdivision search\n    to help compute ground truth for complicated expressions. If\n    turned off, Herbie will be slightly faster, but may hit the\n    \"<a href=\"faq.html#sample-valid-points\">Cannot sample enough valid\n    points</a>\" error more often. Instead of turning this option off,\n    you may want to adjust the <kbd>--num-analysis</kbd> flag\n    instead.</dd>\n\n    <dt><code>setup:simplify</code></dt>\n    <dd>This option, on by default, simplifies the expression before\n    starting the Herbie improvement loop. If turned off, Herbie's\n    results will likely be somewhat worse, but its output program may\n    be more similar to the input program.</dd>\n\n    <dt><code>generate:rr</code></dt>\n    <dd>This option, on by default, uses Herbie's recursive rewriting\n    algorithm to generate candidate programs. If turned off, Herbie\n    will use a non-recursive rewriting algorithm, which will\n    substantially limit Herbie's creativity.</dd>\n\n    <dt><code>generate:taylor</code></dt>\n    <dd>This option, on by default, uses series expansion to produce\n    new candidates during the main improvement loop. If turned off,\n    Herbie will not use series expansion. If turned off, Herbie's\n    results will more likely be algebraically equivalent to the input\n    expression, but may be less accurate.</dd>\n\n    <dt><code>generate:simplify</code></dt>\n    <dd>This option, on by default, simplifies candidates during the\n    main improvement loop. If turned off, candidates will not be\n    simplified, which typically results in much less accurate\n    expressions.</dd>\n\n    <dt><code>generate:proofs</code></dt>\n    <dd>This option, on by default, generates step-by-step derivations\n    for HTML reports. If turned off, the step-by-step derivations will\n    be absent, and Herbie will be slightly faster.</dd>\n\n    <dt><code>reduce:regimes</code></dt>\n    <dd>This option, on by default, uses Herbie's regime inference\n    algorithm to branch between several program candidates. If turned\n    off, branches will not be inferred and the output program will be\n    straight-line code (if the input was). Turn this option off if\n    your programming environment makes branches very expensive, such\n    as on a GPU.</dd>\n\n    <dt><code>reduce:avg-error</code></dt>\n    <dd>This option, on by default, causes Herbie to output the\n    candidate with the best average error over the chosen inputs. If\n    turned off, Herbie will choose the candidate with the least\n    maximum error instead. This usually produces programs with worse\n    overall accuracy. Turn this option off if worst-case accuracy is\n    more important to you than overall accuracy.</dd>\n\n    <dt><code>reduce:binary-search</code></dt>\n    <dd>This option, on by default, uses binary search to refine the\n    values used in inferred branches. If turned off, different runs of\n    Herbie will be less consistent, and accuracy near branches will\n    suffer.</dd>\n\n    <dt><code>reduce:branch-expressions</code></dt>\n    <dd>This option, on by default, allows Herbie to branch on\n      expressions, not just variables. This slows Herbie down,\n      particularly for large programs. If turned off, Herbie will only\n      try to branch on variables.</dd>\n  </dl>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.1/plugins.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Plugins</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Plugins</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p><a href=\"../../\">Herbie</a> plugins define new functions, add\n  rewrite rules, and number representations. Users install plugins\n  separately, and Herbie then automatically loads and uses them.</p>\n  \n  <h2>Posit arithmetic</h2>\n\n  <p>The <kbd>softposit-herbie</kbd> plugin implements support\n  for <a href=\"https://posithub.org/\">posit</a> arithmetic. Install it\n  with:</p>\n\n  <pre class=\"shell\">raco pkg install --auto softposit-herbie</pre>\n\n  <p>This plugin uses the SoftPosit library, only supported on Linux.\n  Even then is reported to misbehave on some machines. The plugin\n  supports arithmetic operations, <code>sqrt</code>, and quires.</p>\n\n  <p>Once <kbd>softposit-herbie</kbd> is installed,\n  specify <code>:precision posit16</code> to inform Herbie that it\n  should assume the core's inputs and outputs are posit numbers. Other\n  posit sizes (with 8 or 32 bits) and also quires (for 8, 16, and 32\n  bit posits) are available, but are poorly supported.</p>\n\n\n  <h2 id=\"complex\">Generic floating-point numbers</h2>\n\n  <p>The <kbd>float-herbie</kbd> plugin implements support for any IEEE-754\n    binary floating-point number. To install, check out the\n    <a href=\"https://github.com/bksaiki/float-herbie\">source code</a>\n    and run\n  </p>\n\n  <pre class=\"shell\">raco pkg install</pre>\n\n  <p>\n    at the top-level directory of the repository.\n    Once <kbd>float-herbie</kbd> is installed,\n    specify <code>:precision (float <i>ex</i> <i>nb</i>)</code>\n    to inform Herbie that it should assume the core's inputs and outputs are\n    floating-point numbers with <i>ex</i> exponent bits and <i>nb</i> total bits\n    (sign bit + mantissa bits + exponent bits).\n  </p>\n\n  <h2 id=\"complex\">Generic fixed-point numbers</h2>\n\n  <p>The <kbd>fixedpoint-herbie</kbd> plugin implements support for any fixed-point number.\n    To install, check out the\n    <a href=\"https://github.com/bksaiki/fixedpoint-herbie\">source code</a>\n    and run\n  </p>\n\n  <pre class=\"shell\">raco pkg install</pre>\n\n  <p>\n    at the top-level directory of the repository.\n    Once <kbd>fixedpoint-herbie</kbd> is installed,\n    specify <code>:precision (fixed <i>nb</i> <i>sc</i>)</code>\n    to inform Herbie that it should assume the core's inputs and outputs are\n    signed fixed-point numbers with <i>nb</i> total bits and a scaling factor of\n    2<sup><i>sc</i></sup> (integer formats have a scaling factor of 2<sup>0</sup>).\n    This plugin also supports unsigned fixed-point numbers specified by\n    <code>:precision (ufixed <i>nb</i> <i>sc</i>)</code> and provides\n    simpler aliases for integer formats with <code>:precision (integer <i>nb</i>)</code>\n    and <code>:precision (uinteger <i>nb</i>)</code>.\n  </p>\n  \n  <h2>Developing plugins</h2>\n\n  <p>The following is a guide to creating a Herbie plugin.\n  Plugins are considered experimental and may change considerably\n  between releases.\n  If you run into issues, please \n  <a href=\"https://github.com/uwplse/herbie/issues\">file a bug</a>.\n  Be sure to check out the <a href=\"https://github.com/herbie-fp/herbie/tree/main/src/reprs\">\n  built-in plugins</a> in the Herbie repository before getting started.</p>\n\n  <p><b>First Steps</b><br>\n\n  All plugins are implemented as Racket packages. The easiest way to\n  initialize a new Racket package is to run\n\n  <pre class=\"shell\">raco pkg new <var>pkg-name</var></pre>\n\n  in a new folder. Make sure the folder name is the same as the package name!\n  This will initialize a Racket package with all the necessary files.\n  Read the official Racket documentation on the\n  <a href=\"https://docs.racket-lang.org/pkg/getting-started.html#%28part._how-to-create%29\">\n  raco</a> tool for more information.</p>\n\n  <p>A single entry needs to be added to the package manifest stored\n  in <code>info.rkt</code>: add <code>(define herbie-plugin\n  '<var>name</var>)</code> to the bottom of the file\n  where <var>name</var> is a unique symbol that doesn't conflict with\n  other Herbie plugins, like the package name.</p>\n\n  <p>Next, edit the <code>main.rkt</code> file by erasing everything except the\n  language specifier on the first line, and add the line <code>(require herbie/plugin)</code>.\n  This gives the package access to the Herbie plugin interface.\n  Optionally add the following for debugging purposes\n  <code>(eprintf \"Loading <var>pkg-name</var> support...\\n\")</code>\n  directly after the <code>require</code> statement.</p>\n\n  <p>Finally, run the following in the folder containing <code>info.rkt</code>\n  and <code>main.rkt</code>:\n\n  <pre class=\"shell\">raco pkg install</pre>\n\n  This should install your package and check it for errors.\n  Everything is now set up.\n  If you added the debugging line in <code>main.rkt</code>, you should see the string\n  when you run Herbie.\n  Of course, your plugin is empty and doesn't yet add any useful features.\n  </p>\n\n  <p><b>Adding Features</b><br>\n  \n  Now that you have an empty plugin, you can begin adding new functions, rewrite\n  rules, and number representatons.\n  The procedures exported by the Herbie plugin interface can be roughly divided into\n  two categories: unique and parameterized.\n  Whether or not you use the unique or parameterized half of the interface\n  (or maybe both!) depends entirely on the number representation a feature is being\n  implemented for.\n  First, identify if your number representation is unique or parameterized.\n  For example, if you are adding features for <code>double</code> precision\n  (or rather <code>binary64</code>), the representation is unique.\n  If you are adding features for a generic floating point format, say\n  <code>(float <i>ebits</i> <i>nbits</i>)</code>, then the representation is parameterized.</p>\n\n  <p><b>Plugin Interface (Unique)</b><br>\n\n  The following are the signatures and descriptions of the\n  plugin procedures for unique representations.\n  These procedures are required to be at the top-level of\n  <code>main.rkt</code> rather than inside a function.</p>\n\n  <dl>\n    <dt>\n      <code>(<b>define-type</b> <i>name</i> (<i>exact?</i> <i>inexact?</i>)\n                         <i>exact->inexact</i> <i>inexact->exact</i>)</code>\n    </dt>\n    <dd>Adds a new type with the unique identifier <code><i>name</i></code>.\n      The arguments <code><i>exact?</i></code> and <code><i>inexact?</i></code>\n      return true if a value is an exact or high-precision approximate representation.\n      For Herbie's <code>real</code> type, <code><i>exact?</i></code> is implemented\n      with <code>real?</code> and <code><i>inexact?</i></code> is implemented\n      with <code>bigfloat?</code>. The procedures <code><i>exact->inexact</i></code> and\n      <code><i>inexact->exact</i></code> convert between <code><i>exact?</i></code>\n      and <code><i>inexact?</i></code> values.\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-representation</b> (<i>name</i> <i>type</i> <i>repr?</i>)</td>\n                     <td><i>bigfloat->repr</i></td></tr>\n        <tr><td></td><td><i>repr->bigfloat</i></td></tr>\n        <tr><td></td><td><i>ordinal->repr</i></td></tr>\n        <tr><td></td><td><i>repr->ordinal</i></td></tr>\n        <tr><td></td><td><i>width</i></td></tr>\n        <tr><td></td><td><i>special?</i>)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Adds a new representation with the unique identifier <code><i>name</i></code>.\n      The representation will inherit all rewrite rules defined for <code><i>type</i></code>.\n      By default, Herbie defines two types: <code>real</code> and <code>bool</code>.\n      Your representation will most likely inherit from <code>real</code>.\n      The <code><i>width</i></code> argument should be the bitwidth of the representation,\n      e.g. 64 for <code>binary64</code>.\n      The argument <code><i>repr?</i></code> is a procedure that accepts any argument and returns\n      true if the argument is a value in the representation, e.g. an integer representation\n      should use Racket's <code>integer?</code>, while <code><i>special?</i></code> takes a\n      value in the representation and returns true if it is not finite, e.g. NaN or infinity.<br><br>\n\n      The other four arguments are single-argument procedures that implement different conversions.\n      The first two convert between a value in your representation and a Racket\n      <a href=\"https://docs.racket-lang.org/math/bigfloat.html\">bigfloat</a>\n      (you need to import <code>math/bigfloat</code>).\n      The last two convert between a value in your representation and its corresponding ordinal value.\n      Ordinal values for any representation must be within the interval [0, 2<sup><i>width</i></sup> - 1].\n      Check Racket's definition of\n      <a href=\"https://docs.racket-lang.org/math/flonum.html?q=ordinal#%28def._%28%28lib._math%2Fflonum..rkt%29._flonum-~3eordinal%29%29\">\n      ordinals</a> for floats.\n      Note that those ordinal values can be negative.\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-operator</b> (<i>name</i> <i>itype-names ...</i>)</td><td> otype-name</td></tr>\n        <tr><td></td><td>[bf <i>bf-fn</i>]</td></tr>\n        <tr><td></td><td>[ival <i>ival-fn</i>])\n      </table>\n      </code>\n    </dt>\n    <dd>Adds a new operator. Operators describe pure mathematical functions,\n      i.e. <code>+</code> or <code>sin</code>.\n      The parameters <code><i>itype-names</i></code> and <code><i>otype-name</i></code>\n      are the input type(s) and output type names.\n      For example, <code>+</code> takes two <code>real</code> inputs and produces\n      one <code>real</code> output.\n      The <code><i>bf-fn</i></code> argument is the\n      <a href=\"https://docs.racket-lang.org/math/bigfloat.html\">bigfloat</a> implementation of your operator.\n      The <code><i>ival-fn</i></code> argument is the <a href=\"https://github.com/herbie-fp/rival\">Rival</a>\n      implementation of your operator. This is optional but improves the quality of Herbie's output.\n      If you don't want to implement this, set <code><i>ival-fn</i></code> to <code>false</code>.\n      To define operators with an unknown number of arguments, e.g. comparators,\n      add the attribute <code>[itype <i>itype</i>]</code>.\n      This will override the input type names defined by <code><i>itype-names</i></code>.\n      See the bottom of this section for support for constants.\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-operator-impl</b> (<i>op</i> <i>name</i> <i>irepr-names ...</i>)</td><td><i>orepr-name</i></td></tr>\n        <tr><td></td><td>[fl <i>fl-fn</i>]</td></tr>\n        <tr><td></td><td>...)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Implements <code><i>op</i></code> with input representation(s) <code><i>irepr-names</i></code>\n      and output representation <code><i>orepr-name</i></code>.\n      The field <code><i>name</i></code> must be unique.\n      For example, Herbie implements <code>+.f64</code> and <code>+.f32</code>\n      for double- and single-precision floats.\n      The argument <code><i>fl-fn</i></code> is the actual procedure that does the computation.\n      Like <code>define-operator</code>, the input representations can be\n      overridden with <code>[itype <i>irepr</i>]</code>.\n      By default, the attributes <code>bf</code> and <code>ival</code>\n      are inherited from <code><i>op</i></code> but can be overridden as previously\n      described.\n      See the bottom of this section for support for constant implementations.\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-ruleset</b> <i>name</i> (<i>groups ...</i>)</td>\n            <td>#:type ([<i>var</i> <i>repr</i>] ...)</td></tr>\n        <tr><td></td><td>[<i>rule-name</i> <i>match</i> <i>replace</i>]</td></tr>\n        <tr><td></td><td>...)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Defines a set of rewrite rules.\n      The <code><i>name</i></code> of the ruleset as well as each <code><i>rule-name</i></code>\n      must be a unique symbol.\n      Each ruleset must be marked with a set of <code><i>groups</i></code>\n      (read <a href=\"options.html#heading-3\">here</a> on ruleset groups).\n      Each rewrite rule takes the form <code>match ⇝ replace</code> where Herbie's rewriter\n      will replace <code>match</code> with <code>replace</code> (not vice-versa).\n      Each <code><i>match</i></code> and <code><i>replace</i></code> is an expression whose operators are\n      the names of operator implementations rather than pure mathematical operators.\n      Any variable must be listed in the type information with its associated representation.\n      See the <code>softposit-herbie</code> plugin for a more concrete example.\n    </dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>define-ruleset*</b> <i>name</i> (<i>groups ...</i>)</td>\n            <td>#:type ([<i>var</i> <i>type</i>] ...)</td></tr>\n        <tr><td></td><td>[<i>rule-name</i> <i>match</i> <i>replace</i>]</td></tr>\n        <tr><td></td><td>...)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Like <code>define-ruleset</code>, but it defines a ruleset for every representation that\n      inherits from <code><i>type</i></code>.\n      Currently, every <code><i>type</i></code> must be the same, e.g.\n      all <code>real</code>, for this procedure to function correctly.\n      Unlike <code>define-ruleset</code>, <code><i>match</i></code> and <code><i>replace</i></code>\n      contain the names of operators rather than operator implementations.\n    </dd>\n  </dl>\n\n  <p>Procedures for declaring constants are not a part of the plugin interface.\n    Instead, constants and constant implementations are defined as\n      zero-argument operators and operator implementations.\n    The fields <code><i>fl-fn</i></code>, <code><i>bf-fn</i></code>,\n      and <code><i>ival-fn</i></code> should be implemented with zero-argument\n      procedures (thunks).\n    Similar to operator and operator implementations, constants describe pure\n      mathematical values like <code>π</code> or <code>e</code> while constant\n      implementations define an approximation of those constants in a particular\n      representation.\n  </p>\n\n  <p><b>Plugin Interface (Parameterized)</b><br>\n\n  Defining operators, constants, and representations for parameterized functions requires\n  a <i>generator</i> procedure for just-in-time loading of features for a particular\n  representation.\n  When Herbie encounters a representation it does not recognize (not explicitly defined\n  using <code>define-representation</code>) it queries a list of generators in case the\n  representation requires just-in-time loading.\n  </p>\n\n  <p>The following procedure handles represention objects:</p>\n\n  <dl>\n    <dt><code>(<b>get-representation</b> name)</code></dt>\n    <dd>Takes a representation name and returns a representation object.\n      Do not call this function before the associated representation has been registered!\n    </dd>\n  </dl>\n\n  <p>The following procedures handle generators:</p>\n\n  <dl>\n    <dt><code>(<b>register-generator!</b> gen)</code></dt>\n    <dd>Adds a representation generator procedure to Herbie's set of generators.\n      Representation generator procedures take the name of a representation and\n      return the associated representation object if it successfully created the\n      operators, constants, and rules for that representation.\n      In the case that your plugin does not register the requested representation,\n      the generator procedure need not do anything and should just return\n      <code>false</code>.\n    </dd>\n  </dl>\n\n  <dl>\n    <dt><code>(<b>register-conversion-generator!</b> gen)</code></dt>\n    <dd>Adds a conversion generator procedure to Herbie's set of generators.\n      Conversion generator procedures take the names of two representations\n      and returns <code>true</code> if it successfully registered conversion(s)\n      between the two representations.\n      Conversions are one-argument operator implementations of the <code>cast</code>\n        operator that have one representation as an input representation and\n        a different representation as an output representation.\n      User-defined conversions are <i>OPTIONAL</i> for multi-precision optimization,\n        since Herbie can synthesize these by default.\n      However Herbie's implementations are often slow since they are\n        representation-agnostic and work for any two representations.\n      In the case that your plugin does not register the requested conversion(s),\n      the generator procedure need not do anything and should just return\n      <code>false</code>.\n    </dd>\n  </dl>\n\n  <p>\n    To actually add representations, operators, etc. within a generator procedure,\n    you must use a set of alternate procedures.\n  </p>\n\n  <dl>\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>register-representation!</b> </td><td> <i>name</i></td></tr>\n        <tr><td></td><td><i>type</i></td></tr>\n        <tr><td></td><td><i>repr?</i></td></tr>\n        <tr><td></td><td><i>bigfloat->repr</i></td></tr>\n        <tr><td></td><td><i>repr->bigfloat</i></td></tr>\n        <tr><td></td><td><i>ordinal->repr</i></td></tr>\n        <tr><td></td><td><i>repr->ordinal</i></td></tr>\n        <tr><td></td><td><i>width</i></td></tr>\n        <tr><td></td><td><i>special?</i>)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Like <code>define-representation</code>, but used within generators.</dd>\n\n    <dt>\n      <code>\n      <table>\n        <tr><td>(<b>register-representation-alias!</b> </td><td> <i>name</i> <i>repr</i>)</td></tr>\n      </table>\n      </code>\n    </dt>\n    <dd>Adds an alias <i>name</i> for an existing representation <i>repr</i>.\n      If two representations are equivalent, e.g. <i>(float 8 32)</i> and <i>binary32</i>,\n      this procedure can be used to declare the two representations equivalent.\n    </dd>\n\n    <dt>\n      <code>(<b>register-operator!</b> <i>op</i> <i>name</i> <i>itype-names</i>\n        <i>otype-name</i> <i>attribs</i>)</code>\n    </dt>\n    <dd>Like <code>define-operator</code>, but used within generators.\n      The argument <code><i>itype-names</i></code> is a list of the input types\n      while the argument <code><i>attribs</i></code> are the same attributes for\n      <code>define-operator</code>, e.g. <code>bf</code>.\n      In this case, <code><i>attribs</i></code> is an association:\n      <code>(list (cons 'bf <i>bf-fn</i>) ...)</code>.\n    </dd>\n\n    <dt>\n      <code>(<b>register-operator-impl!</b> <i>op</i> <i>name</i> <i>ireprs</i>\n        <i>orepr</i> <i>attribs</i>)</code>\n    </dt>\n    <dd>Like <code>define-operator-impl</code>, but used within generators.\n      Unlike <code>define-operator-impl</code>, this procedure takes representation\n        objects rather than representation names for <code><i>ireprs</i></code>\n        and <code><i>orepr</i></code>.\n      Use <code>get-representation</code> to produce these objects.\n      See <code>register-operator!</code> for a description of <code><i>attribs</i></code>.\n    </dd>\n\n    <dt><code>(<b>register-ruleset!</b> <i>name</i> <i>groups</i>\n        <i>var-repr-names</i> <i>rules</i>)</code>\n    </dt>    \n    <dd>Like <code>define-ruleset</code>, but used within generators.\n      In this case, <code><i>groups</i></code> is a list of rule groups;\n        <code><i>var-repr-names</i></code> is an association\n        pairing each variable in the ruleset with its representation, e.g.\n        <code>(list (cons 'x '(float 5 16)) ...)</code>;\n        and <code><i>rules</i></code> is a list of rules of the following\n        form <code>(list (list <i>rule-name</i> <i>match</i> <i>replace</i>) ...)</code>.\n    </dd>\n\n  </dl>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.1/release-notes.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie 2.1 Release Notes</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <script src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML\"></script>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <style>\n    .showcase { margin: 1em 0; }\n    .showcase.side-by-side { display: flex; gap: 1em; }\n    .showcase.side-by-side :nth-child(1) { width: 60%; }\n    .showcase.side-by-side :nth-child(2) { flex-grow: 1; hyphens: auto; }\n    #team {\n        display: block; box-sizing: border-box; width: 100%;\n        border-radius: 2em; border: 3px solid black;\n    }\n  </style>\n</head>\n<body>\n  <header>\n    <h1>Herbie 2.1 Release Notes</h1>\n    <a href=\"../..\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>The <a href=\"../..\">Herbie</a> developers are excited to announce\n  Herbie 2.1! This release focuses performance, both in the generated\n  code and in the Herbie kernel itself.</p>\n\n  <p><b>What is Herbie?</b> Herbie automatically improves the accuracy\n  of floating point expressions. This avoids the bugs, errors, and\n  surprises that so often occur with floating point arithmetic.\n  Visit <a href=\"../..\">the main page</a> to learn more about Herbie.</p>\n  \n  <p class=\"warning\"><b>OOPSLA, ASPLOS, and POPL Reviewers</b>, please\n  do not read further, because some of the work described below is\n  submitted for publication to these venues.</p>\n\n  <img src=\"team.png\" id=\"team\" alt=\"The Herbie 2.1 team at UW and U of U\" />\n\n  <h2>Faster Generated Code</h2>\n\n  <figure class=\"showcase side-by-side\">\n    <img src=\"localize-comparison.png\"\n         alt=\"A comparison of speed-accuracy curves for Herbie 2.0 and\n         2.1, showing much faster low-accuracy code in Herbie 2.1.\">\n    <figcaption>\n      Herbie 2.0 (green) and 2.1 (blue) speed-accuracy curves on the\n      Hamming test suite, showing that Herbie 2.1 generates much\n      faster code, especially at low accuracy levels. The impact is\n      due to both typed extraction (described on the plot as\n      <q>egg-serialize</q>) and the cost opportunity heuristic (described on\n      the plot as <q>cost localization</q>). The orange curve shows that both\n      components are necessary to achieve the best results.\n    </figcaption>\n  </figure>\n\n  <p>\n  Last year, <a href=\"../2.0/release-notes.html\">Herbie 2.0</a>\n  released <i>pareto mode</i>, in which Herbie generates multiple\n  expressions with different speeds and accuracies. Herbie 2.1 now\n  makes Herbie's generated code, especially at the\n  highest-performance/lowest-accuracy level, dramatically better.\n  Some features that contribute to these improvements:</p>\n\n  <ul>\n    <li>With type-based extraction (<a href=\"https://github.com/herbie-fp/herbie/pull/875\">#875</a>, <a href=\"https://github.com/herbie-fp/herbie/pull/883\">#883</a>, and <a href=\"https://github.com/herbie-fp/herbie/pull/887\">#887</a>) Herbie\n    considers performance optimizations like precision tuning at the\n    same time as it considers rewrites, instead of considering each\n    separately.</li>\n\n    <li>A new cost-opportunity heuristic\n      (<a href=\"https://github.com/herbie-fp/herbie/pull/746\">#746</a>)\n      allows Herbie to focus on parts of the program that can be sped up,\n      generating faster low-accuracy code.</li>\n\n    <li>Preprocessing for odd functions\n    (<a href=\"https://github.com/herbie-fp/herbie/pull/645\">#645</a>)\n    generates range reductions for odd functions, which can mean more\n    accurate generated code.</li>\n\n    <li>Polynomials are now evaluated in Horner form\n    (<a href=\"https://github.com/herbie-fp/herbie/pull/727\">#727</a>).\n      Together with some bug fixes\n    (<a href=\"https://github.com/herbie-fp/herbie/pull/660\">#660</a>),\n    this means faster and more accurate polynomial approximations.</li>\n  </ul>\n\n  <p>While Herbie's generated results are much better, these changes\n  alone would make Herbie more than twice as slow. This leads to the\n  second category of changes.</p>\n\n  <h2>Faster Herbie Kernel</h2>\n  \n  <figure class=\"showcase\">\n    <style>\n      #prectune thead th[colspan] { text-align: center; }\n      #prectune { width: 100%; }\n      #prectune tbody th, #prectune tfoot th { text-align: left; }\n      #prectune tr :nth-child(1n+2) { text-align: right; }\n    </style>\n    <table id=\"prectune\">\n      <thead>\n        <tr><th><th colspan=2>Iteration 0<th colspan=2>Iteration 1<th colspan=2>Iteration 2\n        <tr><th>Operation<th>Precision<th>Time (µs)<th>Precision<th>Time (µs)<th>Precision<th>Time (µs)\n      </thead>\n      <tbody>\n        <tr><th>Tuning<td><td><td><td>22.9<td><td>21.0</tr>\n        <tr><th><code>cos</code><td>78<td>75.9<td>592<td>98.9<td>1695<td>173.1</tr>\n        <tr><th><code>add</code><td>83<td>11.0<td>2107<td>10.0<td>2698<td>11.0</tr>\n        <tr><th><code>cos</code><td>78<td>8.1<td>593<td>99.1<td>1695<td>176.0</tr>\n        <tr><th><code>sub</code><td>73<td>10.0<td>73<td>10.0<td>73<td>11.0</tr>\n      </tbody>\n      <tfoot>\n        <tr><th>Total<td><td>105.0<td><td>241.0<td><td>392.1</tr>\n      </tfoot>\n    </table>\n    <figcaption>\n      A precision-tuned execution of <code>cos(x) - cos(x + ɛ)</code>\n      when <code>x = 10<sup>300</sup></code> and <code>ɛ =\n      10<sup>-300</sup></code>. Each row of the table represents one\n      mathematical operation (or the time spent precision-tuning), and\n      each pair of columns describes one iteration precision and\n      execution time for that operation. Each operation's precision is\n      chosen independently, so the precision column is not uniform.\n    </figcaption>\n  </figure>\n\n  <p>\n  Nearly every part of Herbie has been sped up, often significantly,\n  meaning that Herbie 2.1 overall&mdash;despite the much faster\n  generated code&mdash;is only 20% or so slower than Herbie 2.0.</p>\n\n  <p>\n  The most challenging improvement is a complete rewrite of Herbie's\n  real evaluation system, Rival. Herbie 2.1 uses precision tuning to\n  reduce the time and memory costs by approximately 40%, with the\n  biggest impacts to the largest and slowest expressions. Moreover,\n  Rival has\n  been <a href=\"https://docs.racket-lang.org/rival/index.html\">packaged</a>\n  for use in other projects.\n  </p>\n\n  <p>Other optimizations to Herbie include:</p>\n\n  <ul>\n    <li>Regimes saw a series of improvements, including to\n      data layout (<a href=\"https://github.com/herbie-fp/herbie/pull/696\">#696</a>),\n      sharing (<a href=\"https://github.com/herbie-fp/herbie/pull/706\">#706</a>),\n      types (<a href=\"https://github.com/herbie-fp/herbie/pull/748\">#748</a>),\n      and algorithms (<a href=\"https://github.com/herbie-fp/herbie/pull/772\">#772</a>),\n      which together lead to a 2–3× speed up to regimes.</li>\n    <li>The floating-point program interpreter was rewritten and sped up\n      (<a href=\"https://github.com/herbie-fp/herbie/pull/766\">#766</a>).</li>\n    <li>Batching sped up derivation generation significantly\n      (<a href=\"https://github.com/herbie-fp/herbie/pull/736\">#736</a>.)</li>\n    <li>An accidentally-quadratic lookup in pruning was found and fixed\n      (<a href=\"https://github.com/herbie-fp/herbie/pull/781\">#781</a>).</li>\n    <li>Analysis capped an exponential blow-up that occurred for some preconditions\n      (<a href=\"https://github.com/herbie-fp/herbie/pull/762\">#762</a>).</li>\n    <li>Random number generation saw a small speed up\n      (<a href=\"https://github.com/herbie-fp/herbie/pull/792\">#792</a>).</li>\n  </ul>\n      \n\n  <h2>New Features: Platforms and Explanations</h2>\n\n  <figure class=\"showcase\">\n    <pre>(define-accelerator (sind real) real\n  (λ (x) (sin (* x (/ (PI) 180)))))\n(define-accelerator (cosd real) real\n  (λ (x) (cos (* x (/ (PI) 180)))))\n(define-accelerator (tand real) real\n  (λ (x) (tan (* x (/ (PI) 180)))))</pre>\n    <figcaption>\n      A snippet from the Herbie \"platform\" for\n      the <a href=\"https://julialang.org/\">Julia language</a>,\n      describing special library functions <code>cosd</code>,\n      <code>sind</code>, and <code>tand</code>, which Julia provides.\n      When using this platform, Herbie will use these functions in its\n      generated code.\n    </figcaption>\n  </figure>\n\n  <p>Two new features are in development and available in an\n  undocumented <i>alpha</i> state in this release: platforms and explanations.</p>\n\n  <p>Platforms allow Herbie to generate code specific\n  to a given programming language, library, or hardware platform.\n  Herbie can use platform-specific operators, cost models,\n  and compilation styles, which leads to faster and more accurate\n  code. We hope to clean up the platforms code and release it for real\n  in Herbie 2.2.</p>\n\n  <p>Explanations describe what floating-point errors Herbie found and\n  what inputs they occur for. This should make Herbie easier to\n  understand and a more valuable tool for learning about\n  floating-point error.</p>\n\n  <h2>Sister Projects</h2>\n  \n  <p>\n    The <a href=\"https://github.com/herbie-fp/odyssey\">Odyssey numerics \n      workbench</a> is releasing version 1.1 today, featuring FPTaylor \n      support and expression export. Odyssey and supporting tools like \n      Herbie and FPTaylor can be installed and run locally through the \n      <a href=\"https://marketplace.visualstudio.com/items?itemName=herbie-fp.odyssey-fp\">\n      Odyssey VSCode extension</a>. New features include:\n  </p>\n  \n  <ul>\n    <li>Support for using FPTaylor to compute sound error bounds in\n    Odyssey. Select \"FPTaylor Analysis\" from the tool dropdown for an\n    expression. This is a part of a larger effort to combine different\n    floating point tools as parts of an analysis.</li>\n    <li>Odyssey now supports exporting expressions to different\n    languages using the new \"Expression Export\" tool.</li>\n    <li>Herbie has been updated with an HTTP API endpoint to support\n    Odyssey's expression export. Herbie's HTTP API endpoints are\n    documented <a href=\"https://herbie.uwplse.org/doc/2.1/api-endpoints.html\">here</a>.</li>\n    <li>Like the Herbie demo, Odyssey now shows the percent accuracy\n    of expressions, rather than bits of error.</li>\n    <li>The layout of the Odyssey interface has been updated and will\n    continue to see rolling updates.</li>\n  </ul>\n  \n  <p>\n    The <a href=\"https://github.com/herbie-fp/rival\">Rival\n    real-arithmetic package</a> is releasing version 2.0 today,\n    featuring the correct-rounding code from Herbie\n    (<a href=\"https://github.com/herbie-fp/herbie/pull/804\">#804</a>),\n    including the new precision tuning algorithm and a newly-build\n    profiling system.\n  </p>\n\n  <h2>Development Improvements</h2>\n  <ul>\n    <li>Herbie now supports the FPCore <code>:alt</code> field,\n      including multiple alternative expressions\n      (<a href=\"https://github.com/herbie-fp/herbie/pull/764\">#764</a>,\n      <a href=\"https://github.com/herbie-fp/herbie/pull/783\">#783</a>,\n      and <a href=\"https://github.com/herbie-fp/herbie/pull/805\">#805</a>).</li>\n    <li>Many of Herbie's oldest benchmarks have gained new preconditions\n      and human-written target programs\n      (<a href=\"https://github.com/herbie-fp/herbie/pull/693\">#693</a>,\n      <a href=\"https://github.com/herbie-fp/herbie/pull/697\">#697</a>),\n      which will drive Herbie development in the future.</li>\n    <li>Herbie's report page has been totally rewritten, and now uses\n      JavaScript. This has allowed us to sorting, filtration, and\n      diffing capabilities, which has really made development easier.\n      (<a href=\"https://github.com/herbie-fp/herbie/pull/641\">#641</a>,\n      <a href=\"https://github.com/herbie-fp/herbie/pull/651\">#651</a>,\n      <a href=\"https://github.com/herbie-fp/herbie/pull/687\">#687</a>).\n      However, this does mean that you need to run a local server to view\n      report pages saved on your local disk—this is a browser security policy\n      that we can't avoid. You'll see an error message explaning how\n      (<a href=\"https://github.com/herbie-fp/herbie/pull/863\">#863</a>).</li>\n    <li>Friends at Intel contributed benchmarks from the DirectX specification\n      (<a href=\"https://github.com/herbie-fp/herbie/pull/655\">#656</a>).</li>\n    <li>Caching has sped up Herbie's continuous integration\n      (<a href=\"https://github.com/herbie-fp/herbie/pull/663\">#663</a>).</li>\n  </ul>\n\n  <h2>Other improvements</h2>\n  <ul>\n    <li>We now build and publish macOS Arm64 packages\n      (<a href=\"https://github.com/herbie-fp/herbie/pull/787\">#787</a>,\n      <a href=\"https://github.com/herbie-fp/herbie/pull/826\">#862</a>).\n      Thank you to Github for hosting our build infrastructure.</li>\n    <li>We fixed a memory leak\n      (<a href=\"https://github.com/herbie-fp/herbie/pull/636\">#636</a>)\n      and segfault\n      (<a href=\"https://github.com/herbie-fp/herbie/pull/665\">#665</a>)\n      in Herbie's supporting Rust libraries. Eventually the egg folks\n      tracked\n      down <a href=\"https://github.com/egraphs-good/egg/pull/310\">the\n      root cause</a>, so this won't be a problem any more.</li>\n    <li>Some sources of non-determinism were tracked down and fixed\n      (<a href=\"https://github.com/herbie-fp/herbie/pull/661\">#661</a>).</li>\n    <li>Herbie's internals now distinguish between real and\n    floating-point expressions\n    (<a href=\"https://github.com/herbie-fp/herbie/pull/676\">#676</a>,\n      <a href=\"https://github.com/herbie-fp/herbie/pull/702\">#702</a>,\n      <a href=\"https://github.com/herbie-fp/herbie/pull/723\">#732</a>),\n    which has previously been an ad-hoc distinction.</li>\n    <li>Herbie's API endpoints now use an internal job astraction\n    (<a href=\"https://github.com/herbie-fp/herbie/pull/845\">#845</a>),\n    which should eventually allow them to be threaded and asynchronous.</li>\n  </ul>\n\n  <h2>Try it out!</h2>\n\n  <p>\n    We want Herbie to be more useful to scientists, engineers, and\n    programmers around the world. We've got a lot of features we're\n    excited to work on in the coming months. Please\n    <a href=\"https://github.com/herbie-fp/herbie/issues\">report bugs</a>\n    or <a href=\"https://github.com/herbie-fp/herbie\">contribute</a>.\n  </p>\n  <br>\n  <p style=\"font-weight: bold; text-align: center;\">If you find Herbie\n  useful, <a href=\"mailto:herbie@cs.washington.edu\">let us know!</p>\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.1/report.html",
    "content": "<!doctype html>\n<html>\n\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie reports</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n\n<body>\n  <header>\n    <h1>Herbie reports</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>When used <a href=\"using-web.html\">in the browser</a>, Herbie\n    generates HTML reports full of information about the accuracy and relative \n    speed of the initial and alternative expressions.</p>\n\n  <h2 id=\"links\">Summary and Additional links</h2>\n\n  <p>The top of the report page has a right-hand menu bar with\n    additional links. “Metrics” give you detailed internal information\n    about Herbie, while “Report”, if present, takes you back to the\n    full Herbie report.</p>\n\n  <p>Below the menu lies a brief summary of the results. Herbie can\n    produce multiple alternatives to the initial program, and this\n    summary gives their basic statistics.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-large.png\" />\n    <figcaption>Summary numbers from a Herbie report.</figcaption>\n  </figure>\n\n  <dl>\n    <dt>Percentage Accurate</dt>\n    <dd>The <a href=\"errors.html\">percentage accuracy</a> of the\n    initial program and what Herbie thinks is its most accurate\n    alternative.</dd>\n    <dt>Time</dt>\n    <dd>The time it took Herbie to generate all of the alternatives.</dd>\n    <dt>Alternatives</dt>\n    <dd>The number of alternatives found.</dd>\n    <dt>Speedup</dt>\n    <dd>The speed, relative to the initial program,\n    of the fastest alternative that improves accuracy.</dd>\n  </dl>\n\n  <h2 id=\"spec\">Specification</h2>\n\n  <p>Next, the specification that you gave to Herbie. This section is\n    closed by default. Typically, the specification is also the\n    initial program, but in some cases, like if\n    the <a href=\"input.html\"><kbd>:spec</kbd> property</a> is used,\n    they can differ. The specification also includes\n    any <a href=\"input.html#preconditions\">preconditions</a> given to\n    Herbie.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"specification.png\" />\n  </figure>\n\n  <p>You can use the drop-down in the top left to display the\n  specification in an alternative syntax.</p>\n\n  <p>The colored outcome bar summarizes the sampled floating-point\n    inputs that produce valid, unknown, or invalid outputs. Green\n    outcomes are valid, broken down into finite and infinite. Unknown\n    outputs are red. Blue outcomes are invalid (fail precondition or\n    domain errors) and are ignored by Herbie.</p>\n\n  <!-- Colors copied from src/web/resources/report.css -->\n  <h2 id=\"graph\">Local Percentage Accuracy graph</h2>\n\n  <p>\n    Next, the <em>Local Percentage Accuracy</em> graph compares the\n    accuracy of the initial program to Herbie's most accurate\n    alternative. This is helpful for understanding the sorts of inputs\n    Herbie is improving accuracy on. Sometimes, Herbie improved\n    accuracy on some inputs at the cost of accuracy on other inputs\n    that you care more about. You can add a\n    <a href=\"input.html#preconditions\">precondition</a> to restrict Herbie to \n    the more important inputs in that case.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-accuracy.png\" />\n  </figure>\n\n  <p>In the plot, each individual sampled point is shown with a faint\n    circle, and the thick line is moving average of those individual\n    samples. The red line is the initial program and the blue line is\n    Herbie's most accurate alternative.</p>\n  \n  <p>Accuracy is shown on the vertical axis, and higher is better. The\n    horizontal axis shows one of the variables in the input program;\n    the dropdown in the title switches between input variables. The\n    checkboxes below the graph toggle the red and blue lines on and\n    off.</p>\n\n  <p>If Herbie decided to insert an <code>if</code> statement into the\n    program, the locations of those <code>if</code> statements will be\n    marked with vertical bars.</p>\n\n  <h2 id=\"cost-accuracy\">Accuracy vs Speed</h2>\n  <p>Next, a Pareto graph and table list the alternatives Herbie\n    found.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-cost-accuracy.png\" />\n  </figure>\n\n  <p>Both the plot and the table show the same data. In the plot,\n  accuracy is on the vertical axis and speedup is on the horizontal\n  axis. Up and to the right is better. The initial program is shown\n  with a red square, while each of Herbie's alternatives is shown with\n  a blue circle. A faint line shows the Pareto frontier&mdash;that is,\n  it goes through all Herbie alternatives that maximize speed for\n  their level of accuracy. Some of Herbie's alternatives may not be on\n  the Pareto frontier due to differences between the training and test\n  set.</p>\n\n  <p>In the table, each alternative is shown along with its accuracy\n  and speed relative to the initial program. Values are green if they\n  are better than the initial program, and black otherwise. Each\n  alternative is linked to its description lower on the page.</p>\n\n  <h2 id=\"alternatives\">Initial program and Alternatives</h2>\n\n  <p>Below the table come a series of boxes detailing the initial\n    program and each of Herbie's alternatives, along with their\n    accuracy and relative speed.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-alternative.png\" />\n  </figure>\n\n  <p>The accuracy and relative speed of each alternative is given in\n    the title. Below the title, the alternative expression itself is\n    given. The dropdown in the top right can be used to change the\n    syntax used.</p>\n\n  <p>By definition, the speed of the initial program is 1.0×, and it\n    has no derivation since it was provided by the user.</p>\n\n  <p>Each alternative also has a derivation, which can be shown by\n    clicking on \"Derivation\". The derivation shows each step Herbie\n    took to transform the initial program into this alternative.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-alternative-derivation.png\" />\n  </figure>\n\n  <p>Each step in the derivation gives the accuracy after that step.\n    Sometimes you can use that to pick a less-complex and\n    not-substantially-less-accurate program. The derivation will also\n    call out any time the input is split into cases. When a part of\n    the step is colored blue, that identifies the changed part of the\n    expression.</p>\n\n  <p>Derivations may also contain \"step-by-step derivations\"; you can\n  click on those step-by-step derivations to expand them. Each step in\n  the step-by-step derivation names an arithmetic law from Herbie's\n  database, with <kbd>metadata-eval</kbd> meaning that Herbie used\n  direct computation in a particular step.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-step-by-step.png\" />\n  </figure>\n\n  <h2 id=\"reproduction\">Reproduction</h2>\n\n  <p>Finally, Herbie gives a command to reproduce that result. If you\n    find a Herbie bug, include this code snippet when\n    <a href=\"https://github.com/uwplse/herbie/issues\">filing an issue</a>.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-reproduce.png\" />\n  </figure>\n\n  <p>We expect the report to grow more informative with future\n    versions. Please <a href=\"mailto:herbie@cs.washington.edu\">get in\n      touch</a> if there is more information you'd like to see.</p>\n\n</body>\n\n</html>\n"
  },
  {
    "path": "www/doc/2.1/toc.js",
    "content": "function make_toc() {\n    var headings = document.querySelectorAll(\"h2\");\n    var toc = document.createElement(\"nav\");\n    toc.classList.add(\"toc\")\n    var list = document.createElement(\"ul\");\n    for (var i = 0; i < headings.length; i++) {\n        var li = document.createElement(\"li\");\n        var a = document.createElement(\"a\");\n        var h = headings[i];\n        if (! h.id) {\n            h.setAttribute(\"id\", \"heading-\" + i);\n        }\n        a.setAttribute(\"href\", \"#\" + h.id);\n        a.innerHTML = h.innerHTML;\n        li.appendChild(a);\n        list.appendChild(li);\n    }\n    toc.appendChild(list);\n    headings[0].parentNode.insertBefore(toc, headings[0]);\n}\n\nwindow.addEventListener(\"load\", make_toc);\n"
  },
  {
    "path": "www/doc/2.1/tutorial.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Tutorial</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Herbie Tutorial</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> rewrites floating-point expressions to\n      make them more accurate. Floating-point arithmetic is\n      <a href=\"error.html\">inaccurate</a>; even 0.1 + 0.2 ≠ 0.3 in\n      floating-point. Herbie helps find and fix these mysterious\n      inaccuracies.\n  </p>\n\n  <p>\n    To get started, <a href=\"installing.html\">download and install</a>\n    Herbie. You're then ready to begin using it.\n  </p>\n\n  <h2>Giving Herbie expressions</h2>\n\n  <p>Start Herbie with:</p>\n\n  <pre class=\"shell\">racket -l herbie web</pre>\n  \n  <p>Alternatively, if you added <code>herbie</code> to the path, you\n  can always replace <code>racket -l herbie</code> with\n  just <code>herbie</code>.</p>\n\n  <p>\n    After a brief wait, your web browser should open and show you\n    Herbie's main window. Re-check the\n    <a href=\"installing.html\">installation steps</a>\n    if this doesn&apos;t occur.\n  </p>\n\n  <p>The most important part of the page is this bit:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"web-input.png\" alt=\"The program input field in the Herbie web UI.\"/>\n  </figure>\n\n  <p>\n    Let's start by just looking at an example of Herbie running.\n    Click \"Show an example\". This will pre-fill the expression\n    <kbd>sqrt(x + 1) - sqrt(x)</kbd>\n    with <code>x</code> ranging from <kbd>0</kbd> to <kbd>1.79e308</kbd>.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"range-input.png\" alt=\"The input range field in the Herbie web UI.\"/>\n  </figure>\n\n  <p>\n    Now that you have an expression and a range for each variable,\n    click the \"Improve with Herbie\" button. You should see the entry\n    box gray out, and shortly thereafter some text should appear\n    describing what Herbie is doing. After a few seconds, you'll be\n    redirected to a page with Herbie's results.\n  </p>\n\n  <p>\n    The very top of this results page gives some quick statistics\n    about the alternative ways Herbie found for evaluating this\n    expression:\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-large.png\" alt=\"Statistics and error measures for this Herbie run.\" />\n  </figure>\n\n  <p>Note that Herbie's algorithm is randomized, so you likely won't\n  see the exact same thing; you might see more or fewer alternatives,\n  and they might be more or less accurate and fast.</p>\n\n  <p>\n    Here, you can see that Herbie's most accurate alternative has an\n    accuracy of 99.7%, much better than the initial program's 53.2%,\n    and that in total Herbie found 5 alternatives. One of those\n    alternatives is both more accurate than the original expression\n    and also 1.9&times; faster. The <a href=\"report.html\">rest of the\n    result page</a> shows each of these alternatives, including\n    details like how they were derived. These details are all\n    <a href=\"report.html\">documented</a>, but for the sake of the\n    tutorial let's move on to a more realistic example.\n  </p>\n\n  <p>\n    Herbie measures accuracy by comparing a program's result against\n    the exact answer calculated using high-precision arithmetic. The difference\n    between these two is then measured in \"bits of error\" which\n    counts how many of the most significant bits that the\n    approximate and exact result agree on. This error is then\n    averaged across many different sample inputs to determine\n    the program's overall accuracy. Herbie's\n    <a href=\"error.html\">error documentation</a>\n    describes the process in more detail.\n  </p>\n\n  <h2>Programming with Herbie</h2>\n\n  <p>\n    You can use Herbie on expressions from source code, mathematical\n    models, or debugging tools. But most users use Herbie as they\n    write code, asking it about any complex floating-point expression\n    they write. Herbie has <a href=\"options.html\">options</a> to log\n    all the expressions you enter so that you can refer to them later.\n  </p>\n\n  <p>But to keep the tutorial focused, let's suppose you're instead\n    tracking down a floating-point bug in existing code. Then you'll\n    need to start by identifying the problematic floating-point\n    expression.</p>\n\n  <p>To demonstrate the workflow, let's walk through\n    <a href=\"https://github.com/josdejong/mathjs/pull/208\">bug 208</a>\n    in <a href=\"http://mathjs.org\">math.js</a>, a math library for\n    JavaScript. The bug deals with inaccurate square roots for complex\n    numbers. (For a full write-up of the bug itself, check out\n    a <a href=\"https://pavpanchekha.com/blog/casio-mathjs.html\">blog\n    post</a> by one of the Herbie authors.)\n  </p>\n\n  <h2>Finding the problematic expression</h2>\n\n  <p>\n    In most programs, there's a small kernel that does the mathematical\n    computations, while the rest of the program sets up parameters,\n    handles control flow, visualizes or prints results, and so on. The\n    mathematical core is what Herbie will be interested in.\n  </p>\n\n  <p>\n    For our example, let's start\n    in <a href=\"https://github.com/josdejong/mathjs/tree/da306e26ed34272db44e35f07a3b015c0155d99a/lib/function\"><code>lib/function/</code></a>.\n    This directory contains many subdirectories; each file in each\n    subdirectory defines a collection of mathematical functions. We're\n    interested in the complex square root function, which is defined in\n    <a href=\"https://github.com/josdejong/mathjs/blob/da306e26ed34272db44e35f07a3b015c0155d99a/lib/function/arithmetic/sqrt.js\"><code>arithmetic/sqrt.js</code></a>.\n  </p>\n\n  <p>\n    This file handles argument checks, different types, and error\n    handling, for both real and complex square roots. None of that is\n    of interest to Herbie; we want to extract just the mathematical\n    core. So skip down to the <code>isComplex(x)</code> case:\n  </p>\n\n  <pre>var r = Math.sqrt(x.re * x.re + x.im * x.im);\nif (x.im &gt;= 0) {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}\nelse {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      -0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}</pre>\n\n  <p>This is the mathematical core that we want to send to Herbie.</p>\n\n  <h2>Converting problematic code to Herbie input</h2>\n\n  <p>\n    In this code, <code>x</code> is of type <code>Complex</code>, a\n    data structure with multiple fields. Herbie only deals with\n    floating-point numbers, not data structures, so we will treat the\n    input <code>x</code> as two separate inputs to\n    Herbie: <code>xre</code> and <code>xim</code>. We'll also pass\n    each field of the output to Herbie separately.\n  </p>\n\n  <p>\n    This code also branches between non-negative <code>x.im</code> and\n    negative <code>x.im</code>. It's usually better to send each\n    branch to Herbie separately. So in total, this code turns into four\n    Herbie inputs: two output fields, for each of the two branches.\n  </p>\n\n  <p>Let's focus on the first field of the output for the case of\n  non-negative <code>x.im</code>.</p>\n\n  <p>The variable <code>r</code> is an intermediate variable in this\n  code block. Intermediate variables provide Herbie with crucial\n  information that Herbie can use to improve accuracy, so you want to\n  expand or inline them. The result looks like this:</p>\n\n  <pre>0.5 * sqrt(2.0 * (sqrt(xre * xre + xim * xim) + xre))</pre>\n\n  <p>Recall that this code is only run when <code>x.im</code> is\n  non-negative (but it runs for all values of <code>x.re</code>). So, \n  select the full range of values for <code>x.re</code>, but restrict\n  the range of <code>x.im</code>, like this: \n  \n  <figure>\n    <img width=\"100%\" src=\"range-input-2.png\" alt=\"Restricting the input range to xim >= 0.\" />\n  </figure>\n  \n  This asks Herbie to consider only non-negative values\n  of <code>xim</code> when improving the accuracy of this expression.\n  The number <code>1.79e308</code> is approximately the largest\n  double-precision number, and will auto-complete.</p>\n  \n  <h2>Herbie's results</h2>\n\n  <p>Herbie will churn for a few seconds and produce a results page.\n    In this case, Herbie found 6 alternatives, and we're interested in\n    the most accurate one, which should have an\n    <a href=\"error.html\">accuracy of 84.6%:</a></p>\n\n  <figure>\n    <img width=\"100%\" src=\"problematic-highlight.png\" />\n  </figure>\n\n  <p>Below these summary statistics, we can see a graph of accuracy\n  versus input value. By default, it shows accuracy\n  versus <code>xim</code>; higher is better:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"problematic-xim.png\" />\n  </figure>\n\n<p>There's a really obvious drop in accuracy once <code>xim</code>\n  gets bigger than about <code>1e150</code>\n  (due to <a href=\"https://en.wikipedia.org/wiki/Floating-point_arithmetic#Dealing_with_exceptional_cases\">floating-point overflow</a>),\n  but you can also see that Herbie's alternative is more accurate\n  for smaller <code>xim</code> values, too. You can also change the\n  graph to plot accuracy versus <code>xre</code> instead:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"problematic-xre.png\" />\n  </figure>\n\n  <p>This plot makes it clear that Herbie's alternative is almost\n  perfectly accurate for positive <code>xre</code>, but still has some\n  error for negative <code>xre</code>.\n\n  <p>Herbie also found other alternatives, which are less accurate but\n  might be faster. You can see a summary in this table:</p>\n\n  <figure>\n    <figcaption></figcaption>\n    <img width=\"100%\" src=\"problematic-pareto-table.png\" />\n  </figure>\n\n  <p>Remember that Herbie's algorithm is randomized, so you likely\n  won't see the exact same thing. That said, the most accurate\n  alternative should be pretty similar.</p>\n\n  <p>That alternative itself is shown lower down on the page:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"problematic-improved-accuracy.png\" />\n  </figure>\n\n  <p>A couple features of this alternative stand out immediately.\n  First of all, Herbie inserted an <code>if</code> statement.\n  This <code>if</code> statement handles a phenomenon known as\n  <a href=\"https://en.wikipedia.org/wiki/Catastrophic_cancellation\">cancellation</a>,\n  and is part of why Herbie's alternative is more accurate. Herbie\n  also replaced the square root operation with the <code>hypot</code>\n  function, which computes distances more accurately than a direct\n  square root operation.</p>\n\n  <p>If you want to see more about how Herbie derived this result, you\n  could click on the word \"Derivation\" to see a detailed, step-by-step\n  explanation of how Herbie did it. For now, though, let's move on to\n  look at another alternative.</p>\n  \n  <p>The fifth alternative suggested by Herbie is much less accurate,\n  but it is about twice as fast as the original program:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"problematic-improved-speed.png\" />\n  </figure>\n  \n  <p>This alternative is kind of strange: it has two branches, and\n  each one only uses one of the two variables <code>xre</code>\n  and <code>xim</code>. That explains why it's fast, but it's still\n  more accurate than the initial program because it avoids\n  cancellation and overflow issues that plagued the original.</p>\n  \n  <h2>Using Herbie's alternatives</h2>\n  \n  <p>In this case, we were interested in the most accurate possible\n  implementation, so let's try to use Herbie's most accurate\n  alternative.</p>\n\n  <pre>\n// Herbie 2.1 for:\n//   0.5 * sqrt(2.0 * (sqrt(xre*xre + xim*xim) + xre))\nvar r = Math.hypot(x.re, x.im);\nvar re;\nif (xre + r <= 0) {\n    re = 0.5 * Math.sqrt(2 * (x.im / (x.re / x.im) * -0.5));\n} else {\n    re = 0.5 * Math.sqrt(2 * (x.re + r));\n}\nif (x.im &gt;= 0) {\n  return new Complex(\n      re,\n      0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}\nelse {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      -0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}</pre>\n\n  <p>Note that I&apos;ve left the Herbie query in a comment. As Herbie\n  gets better, you can re-run it on this original expression to see if\n  it comes up with improvements in accuracy.</p>\n\n  <p>Additionally, for some languages (e.g. JavaScript, Python,\n  Wolfram, etc) you can use the drop-down in the top-right corner\n  of the alternative block to translate Herbie&apos;s output to that\n  language. However, you will still probably need to refactor and\n  modify the results to fit your code structure, just like here.</p>\n\n  <h2>Next steps</h2>\n\n  <p>With this change, we&apos;ve made this part of the complex square\n  root function much more accurate, and we could repeat the same steps\n  for the other branches and other fields in this program. You now\n  have a pretty good understanding of Herbie and how to use it.\n  Please <a href=\"mailto:herbie@cs.washington.edu\">let us know</a> if\n  Herbie has helped you, and check out\n  the <a href=\"../../doc.html\">documentation</a> to learn more about\n  Herbie&apos;s various options and outputs.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.1/using-cli.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie from the Command Line</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Shell and Batch Mode</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>Herbie can be used from the command-line or\n  from <a href=\"using-web.html\">the browser</a>. This page covers\n  using Herbie from the command line.</p>\n\n  <h2 id=\"interactive\">The Herbie shell</h2>\n\n  <p>\n    The Herbie shell lets you interact with Herbie: you type in input\n    expressions and Herbie prints their more accurate versions. Run\n    the Herbie shell with this command:\n  </p>\n\n  <pre class=\"shell\">racket -l herbie shell\nHerbie 2.1 with seed 2098242187\nFind help on https://herbie.uwplse.org/, exit with Ctrl-D\n<strong>herbie&gt;</strong> </pre>\n\n\n  <p>\n    Herbie prints a seed, which you can <a href=\"options.html\">use to\n    reproduce</a> a Herbie run, and links you to documentation. Then,\n    it waits for inputs, which you can type directly into your\n    terminal in <a href=\"input.html\">FPCore format</a>:\n</p>\n\n  <pre><strong>herbie&gt;</strong> (FPCore (x) (- (+ 1 x) x))\n(FPCore\n  (x)\n  <var>...</var>\n  1)</pre>\n\n  <p>Herbie suggests that <code>1</code> is more accurate than the\n  original expression <code>(- (+ 1 x) x)</code>. The\n  the <var>...</var> elides \n  <a href=\"input.html#properties\">additional information</a> provided\n  by Herbie.</p>\n\n  <p>The Herbie shell only shows Herbie's most accurate variant.</p>\n\n  <h2 id=\"batch\">Batch processing FPCores</h2>\n\n  <p>\n    Alternatively, you can run Herbie on a file with multiple\n    expressions in it, writing Herbie's versions of each to a file.\n    This mode is intended for use by scripts.\n  </p>\n\n  <pre class=\"shell\">racket -l herbie improve bench/tutorial.fpcore out.fpcore\nStarting Herbie on 3 problems (seed: 1551571787)...\n  1/3\t[   0.882s]   30→ 0\tCancel like terms\nWarning: 24.7% of points produce a very large (infinite) output.\nYou may want to add a precondition.\nSee <a href=\"https://herbie.uwplse.org/doc/2.0/faq.html#inf-points\">&lt;https://herbie.uwplse.org/doc/2.0/faq.html#inf-points&gt;</a> for more.\n  2/3\t[   1.721s]   29→ 0\tExpanding a square\n  3/3\t[   2.426s]    0→ 0\tCommute and associate</pre>\n\n  <p>\n    The output file <code>out.fpcore</code> contains more accurate\n    versions of each program:\n  </p>\n\n  <pre>;; seed: 1551571787\n\n(FPCore (x) <var>...</var> 1)\n(FPCore (x) <var>...</var> (* x (- x -2)))\n(FPCore (x y z) <var>...</var> 0)</pre>\n\n  <p>\n    Note that output file is in the same order as the input file. For\n    more control over Herbie, see the documentation of\n    Herbie's <a href=\"options.html\">command-line options</a>.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.1/using-web.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie from the Browser</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>The Browser UI</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> rewrites floating point expressions to\n    make them more accurate. Herbie can be used\n    from <a href=\"using-cli.html\">the command-line</a> or from the\n    browser; this page is about using Herbie from the browser.</p>\n\n\n  <h2 id=\"interactive\">The Herbie web shell</h2>\n\n  <p>\n    The Herbie web shell lets you interact with Herbie through your\n    browser, featuring a convenient input format. The web shell is the\n    friendliest and easiest way to use Herbie. Run the Herbie web\n    shell with this command:\n  </p>\n\n  <pre class=\"shell\">racket -l herbie web</pre>\n\n  <p>After a few seconds, the web shell will rev up and direct your\n  browser to Herbie:</p>\n  \n  <pre class=\"shell\">racket -l herbie web\nHerbie 2.1 with seed 1003430182\nFind help on https://herbie.uwplse.org/, exit with Ctrl-C\nYour Web application is running at http://localhost:8000/.\nStop this program at any time to terminate the Web Server.</pre>\n\n  <figure>\n    <img width=\"100%\" src=\"web-main.png\" alt=\"A screenshot of the Herbie web shell main page.\"/>\n  </figure>\n\n  <p>You can type an input expressions in\n    <a href=\"input.html\">standard mathematical syntax</a>. After typing in an \n    expression, you will be asked to specify the range of values for each input \n    variable that Herbie should consider when trying to improve the expression. \n    Hit the \"Improve with Herbie\" button once you're done to run Herbie.\n  </p>\n  \n  <p>\n    The web shell reports Herbie's progress and redirects to a\n    <a href=\"report.html\">report</a> once Herbie is done.\n  </p>\n\n  <p>\n    The web shell can also automatically save the generated reports,\n    and has <a href=\"options.html\">many other options</a> you might\n    want to explore.\n  </p>\n\n\n  <h2 id=\"batch\">Batch report generation</h2>\n\n  <p>A <a href=\"report.html\">report</a> can also be generated directly\n  from a file of input expressions in <a href=\"input.html\">FPCore format</a>:</p>\n  \n  <pre class=\"shell\">racket -l herbie report bench/tutorial.fpcore output/ \nStarting Herbie on 3 problems (seed: 770126425)...\nWarning: 25.0% of points produce a very large (infinite) output. \nYou may want to add a precondition.\nSee <a href=\"faq.html#inf-points\">https://herbie.uwplse.org/doc/latest/faq.html#inf-points</a> for \nmore.\n  1/3   [   0.703s]   29→ 0     Expanding a square\n  2/3   [   1.611s]    0→ 0     Commute and associate\n  3/3   [   0.353s]   30→ 0     Cancel like terms</pre>\n\n  <p>\n    This command generates a report from the input expressions\n    in <code>bench/tutorial.fpcore</code> and saves the report in the\n    directory <code>output/</code>. It's best if that directory\n    doesn't exist before running this command, because otherwise\n    Herbie may overwrite files in that directory.\n  </p>\n\n  <p>\n    Occasionally you may also see Herbie emit warnings as shown above.\n    All of Herbie's warnings are listed, with explanations, in\n    the <a href=\"faq.html\">FAQ</a>.\n  </p>\n\n  <p>\n    The report Herbie generates is in HTML format so you'll need to\n    start a web server. If you have Python installed, that's\n    particularly convenient:\n  </p>\n\n  <pre class=\"shell\">python3 -m http.server -d output</pre>\n\n  <p>\n    Then go to <a href=\"http://localhost:8000/\">localhost:8000</a> in\n    your favorite browser. The report summarizes Herbie's results for\n    all expression in your input file, and you can click on individual\n    expressions to see Herbie's output for them.\n  </p>\n\n  <p>Batch report generation is the most informative way to run Herbie\n  on a large collection of inputs. Like the web shell, it can be\n  customized through <a href=\"options.html\">command-line options</a>,\n  including parallelizing Herbie with multiple threads.</p>\n\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.2/api-endpoints.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Herbie HTTP API Endpoints</title>\n    <link rel='stylesheet' type='text/css' href='../../main.css'>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <script type=\"text/javascript\" src=\"toc.js\"></script>\n  </head>\n  <body>\n    <header>\n      <h1>HTTP API</h1>\n      <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n      <nav>\n        <ul>\n          <li><a href=\"../../demo/\">Try</a></li>\n          <li><a href=\"installing.html\">Install</a></li>\n          <li><a href=\"tutorial.html\">Learn</a></li>\n        </ul>\n      </nav>\n    </header>\n\n    <p>The <a href=\"../../\">Herbie</a> API allows applications to\n    interface with Herbie using HTTP requests. The API is designed to\n    be stateless: the order in which endpoints are called shouldn't\n    matter.</p>\n\n    <h2 id=\"all-endpoints-info\">Format for all endpoints</h2>\n\n    <p>All the endpoints listed below respond to POST requests unless\n    otherwise specified. A typical example of sending a POST request\n    to a running Herbie server is:</p>\n\n    <pre class=\"shell\">curl -d \\\n  '{\"formula\": \"(FPCore (x) (- (sqrt (+ x 1))))\", \"seed\": 5}' \\\n  -H 'Content-Type: application/json' \\\n  http://127.0.0.1:8000/api/sample\n    </pre>\n\n    <h2 id=\"sample\">/api/sample</h2>\n\n    <details>\n    <summary>Example input &amp; output</summary>\n\n    <p>Request:</p>\n\n    <pre>{\n    formula: &lt;FPCore expression&gt;,\n    seed: &lt;random seed for point generation&gt;\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n    points: [[point, exact], ... ]\n}</pre>\n    </details>\n\n    <p>The <code>sample</code> endpoint allows the user to request a\n    sample of points given the FPCore expression and a seed.</p>\n\n    <p>Returns a collection of points and the exact evaluation of each\n    point with the given spec. The results are returned through the\n    \"points\" field and are represented by an array of point-exact\n    pairs with the first value representing the point and the second\n    value representing the exact evaluation; the exact value of\n    point <code>n</code> is <code>points[n][1]</code>.</p>\n\n    <p>Herbie calculates the \"ground truth\" by calculating the values\n    with more precise numbers. This can be slow.</p>\n\n    <h2 id=\"exacts\">/api/exacts</h2>\n\n    <details>\n    <summary>Example input & output</summary>\n\n    <p>Request:</p>\n\n    <pre>{\n    formula: &lt;FPCore expression&gt;,\n    sample: [point, ... ]\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n    points: [[point, exact], ... ]\n}</pre>\n    </details>\n\n    <p>The <code>exacts</code> endpoint allows the user to request the\n    exact value of a set of points evaluated at a real number\n    specification given as an FPCore expression.</p>\n\n    <p>Some points may not be calculable given the FPCore\n    expression.</p>\n\n    <p>Returns a collection of points and the exact evaluation of each\n    point with the given spec. The results are returned through the\n    \"points\" field and are represented by an array of point-exact\n    pairs with the first value representing the point and the second\n    value representing the exact evaluation; the exact value of\n    point <code>n</code> is <code>points[n][1]</code>.</p>\n\n    <p>Herbie calculates the \"ground truth\" by calculating the values\n    with more precise numbers. This can be slow.</p>\n\n    <h2 id=\"calculate\">/api/calculate</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n\n    <p>Request:</p>\n\n    <pre>{\n    formula: &lt;FPCore expression&gt;,\n    sample: [point ... ]\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n    points: [[point, exact], ... ]\n}</pre>\n    </details>\n\n    <p>The <code>calculate</code> endpoint allows the user to request\n    the evaluation of a set of points evaluated at a floating-point\n    implementation given as an FPCore expression.</p>\n\n    <p>Some points may not be calculable given the FPCore expression.</p>\n\n    <p>Returns a collection of points and the evaluation of each point\n    using the given FPCore as a floating-point implementation. The\n    results are returned through the \"points\" field and are\n    represented by an array of point-exact pairs with the first value\n    representing the point and the second value representing the\n    evaluated value; the evaluated value of point <code>n</code>\n    is <code>points[n][1]</code>.</p>\n\n    <h2 id=\"analyze\">/api/analyze</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n\n    <p>Request:</p>\n\n    <pre>{\n  formula: &lt;FPCore expression&gt;,\n  sample: [[point, exact], ... ]\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n  points: [[point, error], ... ]\n}</pre>\n    </details>\n\n    <p>The <code>analyze</code> endpoint allows the user to request\n    error analysis of a set of point-exact pairs and a given\n    floating-point implementation.</p>\n\n    <p>Given a collection of points, their exact values, and an FPCore\n    expression to analyze on, the <code>analyze</code> endpoint\n    returns the error for each point for that expression. The error\n    value returned is Herbie's internal error heuristic.</p>\n\n    <h2 id=\"alternatives\">/api/alternatives</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n    <p>Request:</p>\n\n    <pre>{\n  formula: &lt;FPCore expression&gt;,\n  sample: [[point, exact], ... ]\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n  alternatives: [alt, ... ],\n  histories: [history, ... ],\n  splitpoints: [splitpoint, ... ]\n}</pre>\n    </details>\n\n    <p>The <code>alternatives</code> endpoint allows the user to\n    request rewrites from Herbie given an expression to rewrite and a\n    set of point-exact pairs.</p>\n\n    <p>Returns a list of alternatives represented by FPCore\n    expressions through the \"alternatives\" field.</p>\n\n    <p>Returns a list of derivations of each alternative through the\n    \"histories\" field where <code>history[n]</code> corresponds\n    to <code>alternatives[n]</code>.</p>\n\n    <p>Returns a list of splitpoints for each alternative through the\n    \"splitpoints\" field where <code>splitpoints[n]</code> corresponds\n    to <code>alternatives[n]</code>. <code>splitpoints[n]</code> will\n    only contain information about the corresponding alternative.s\n    splitpoints if the alternative is a branch-expression.</p>\n\n    <h2 id=\"mathjs\">/api/mathjs</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n    <p>Request:</p>\n\n    <pre>{\n  formula: &lt;FPCore expression&gt;\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n  mathjs: &lt;mathjs expression&gt;\n}</pre>\n    </details>\n\n    <p>The <code>mathjs</code> endpoint allows the user to translate\n    FPCore expressions into mathjs expressions.</p>\n\n\n    <h2 id=\"cost\">/api/cost</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n\n    <p>Request:</p>\n\n  <pre>{\n    formula: &lt;FPCore expression&gt;,\n    sample: [point ... ]\n}</pre>\n\n    <p>Response:</p>\n\n  <pre>{\n    cost: cost\n}</pre>\n\n    <p><b>Specific Example: sqrt(x+1)-sqrt(x)</b></p>\n\n    <p>Request:</p>\n\n  <pre>{\n    formula: &lt;(FPCore (x) (- (sqrt (+ x 1)) (sqrt x)))&gt;,\n    sample: [ [[1], -1.4142135623730951] ]\n}</pre>\n\n    <p>Response:</p>\n\n  <pre>{\n    cost: 13120\n}</pre>\n\n    <p><b>Lower-Cost Example: (x+1)-(x)</b></p>\n\n    <p>Request:</p>\n\n  <pre>{\n    formula: &lt;(FPCore (x) (- (+ x 1 ) x))&gt;,\n    sample: [ [[1], -1.4142135623730951] ]\n}</pre>\n\n    <p>Response:</p>\n\n  <pre>{\n    cost: 320\n}</pre>\n\n    </details>\n\n    <p>The <code>cost</code> endpoint allows the user to request\n    the evaluation of an expression's overall cost. Cost is \n    calculated depending on the complexity of operations contained\n    in the expression. </p>\n\n    <p>Given an FPCore expression and a collection of points,\n    returns the cost of the expression. The cost value returned \n    is calculated internally by Herbie.</p> \n    \n    <p>The points should be of the same format as the points \n    generated in the sample endpoint. Refer to /api/sample \n    for more details. </p>\n\n    <p>Note the sample points are not used in the cost calculation.\n    The contents of the points do not matter as long as they are\n    in the correct format as mentioned above.</p>\n\n    <!-- Translate Endpoint -->\n\n    <h2 id=\"translate\">/api/translate</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n\n    <p>Request:</p>\n\n  <pre>{\n    formula: &lt;FPCore expression&gt;,\n    language: \"language\"\n}</pre>\n\n    <p>Response:</p>\n\n  <pre>{\n    result: \"translated expression\"\n}</pre>\n\n    <p><b>Specific Example: sqrt(x+1)-sqrt(x)</b></p>\n\n    <p>Request:</p>\n\n  <pre>{\n    formula: &lt;(FPCore (x) (- (sqrt (+ x 1)) (sqrt x)))&gt;,\n    language: \"python\"\n}</pre>\n\n    <p>Response:</p>\n\n  <pre>{\n    result: \"def expr(x): return math.sqrt((x + 1.0)) - math.sqrt(x)\"\n}</pre>\n\n    </details>\n\n    <p>The <code>translate</code> endpoint allows users to translate\n    FPCore expressions into equivalent expressions in various programming\n    languages.</p>\n\n    <p>Given an FPCore expression and a target language, this endpoint\n      returns the translated expression in the specified language.\n      The language parameter should be a string representing the desired\n      programming language. The response includes the translated expression.</p>\n\n    <p>Currently supported languages are: <code>python</code>, <code>c</code>,\n    <code>fortran</code>, <code>java</code>, <code>julia</code>, <code>matlab</code>,\n    <code>wls</code>, <code>tex</code>, and <code>js</code>.</p>\n  <h2>⚠️ Beta endpoints</h2>\n    <p>The endpoints below are currently a work in progress.</p>\n  <h2 id=\"localerror\">/api/localerror</h2>\n    <!--TODO--> Forthcoming.\n  <h2 id=\"timeline\">/api/timeline/{job-id}</h2>\n  <p>Retrieves the <code>timeline</code> data for a given API call. You may find the job id in either the JSON response or in the headers of the HTTP response for of the endpoints in Herbie.</p>\n  <p>The timeline is an exception to the others in that it uses a GET request. Below is a sample of what the request might look like. You may consult the <code>/infra/testApi.mjs</code> file for current examples of how to use this API.</p>\n  <pre class=\"shell\">curl -X GET \\\n  http://127.0.0.1:8000/api/timeline/0b95161a77fc3e29376bbb013d96c2827e2a1cd7\n      </pre>\n  </body>\n</html>\n"
  },
  {
    "path": "www/doc/2.2/diagrams.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Diagrams</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <script src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML\"></script>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Diagrams</h1>\n    <a href=\"../..\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>This page contains systems diagrams for Herbie.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"system-2.2.png\" alt=\"System diagram of Herbie\" />\n    <figcaption>\n    High-level system diagram of Herbie.\n    It highlights Herbie's core architecture,\n      key external libraries (egg and Rival), and user input/output.\n    Basic flow: Herbie passes user input (specification, precondition, etc.)\n      to a <dfn>sampler</dfn> which computes the exact output\n      for uniformly random input points.\n    Herbie uses these exact outputs to compute\n      the <a href=\"error.html\">accuracy</a> of candidate programs.\n    The mainloop (scheduler) then alternates between generate and prune phases,\n      maintaining and improving a set of accurate expressions at each iteration.\n    Once the generate-and-prune loop is complete,\n      Herbie extracts either output expressions using <dfn>regime inference</dfn>,\n      which combines multiple candidate programs using conditionals.\n    The resulting programs are summarized in a report.\n    </figcaption>\n  </figure>\n  \n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.2/docker.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie on Docker</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Installing with Docker</h1>\n    <a href=\"../..\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> is available\n    through <a href=\"https://www.docker.com/\">Docker</a>, which is\n    sort of like a virtual machine. This page describes how to install\n    the <a href=\"https://hub.docker.com/r/uwplse/herbie\">official Docker\n    image</a> for Herbie.\n  </p>\n  \n  <p>\n    We recommend most users <a href=\"installing.html\">install Herbie\n    from package or source</a>. Herbie via Docker is only recommended\n    if you already have Docker experience.\n  </p>\n  \n  <h2>Installing Herbie via Docker</h2>\n\n  <p>\n    First, <a href=\"https://docs.docker.com/installation/\">install\n    Docker</a>. Docker supports Windows, macOS, and Linux. Depending\n    on how you install Docker, you may need to prefix\n    the <code>docker</code> commands with <code>sudo</code> or run them\n    as the administrative user.\n  </p>\n\n  <p>With Docker installed, you can run the <a href=\"using-cli.html\">Herbie shell</a> with:</p>\n\n  <pre>docker run -it uwplse/herbie shell</pre>\n  \n  <p>This will download the Herbie image and then run\n  its <a href=\"options.html\">shell tool</a>.</p>\n\n  <h2>Running the web interface</h2>\n\n  <p>You can run the Herbie web server locally with</p>\n\n  <pre class=\"shell\">docker run -it --rm -p 8000:80 uwplse/herbie</pre>\n\n  <p>and access the server\n  at <a href=\"http://localhost:8000\">http://localhost:8000</a>.</p>\n\n  <p>(Herbie's Docker image binds to the container's port 80 by\n  default; this command uses the <code>-p 8000:80</code> option to\n  expose that container port as the host's port 8000.)</p>\n\n  <p>If you want to pass custom flags to the Herbie web server, make\n  sure to also pass the <code>--public</code>\n  and <code>--port=80</code> flags to enable the Dockerized Herbie to\n  talk to your computer. Make sure to access the server using HTTP,\n  not HTTPS.</p>\n\n  <p>If you are using the <code>--log</code>\n  or <code>--save-session</code> flags for the web shell, you will\n  also need to mount the relevant directories into the Docker\n  container using the <code>-v</code> Docker option, as in the\n  examples below.</p>\n\n  <h2>Generating files and reports</h2>\n\n  <p>To use Herbie in <a href=\"using-cli.html\">batch mode</a>, you\n  will need to mount the input in the Docker container. Do that\n  with:</p>\n  \n  <pre class=\"shell\">docker run -it --rm \\\n    -v <var>in-dir</var>:/in \\\n    -v <var>out-dir</var>:/out \\\n    -u $USER \\\n    uwplse/herbie improve /in/<var>in-file</var> /out/<var>out-file</var></pre>\n\n  <p>In this command, you are asking Herbie to read input\n  from <var>in-file</var> in <var>in-dir</var>, and write output\n  to <var>out-file</var> in <var>out-dir</var>. The command looks the\n  same if you want Herbie to read input from a directory; just\n  leave <var>in-file</var> blank.</p>\n\n  <p>To generate reports from Herbie, you can run:</p>\n\n  <pre class=\"shell\">docker run -it --rm \\\n    -v <var>in-dir</var>:/in \\\n    -v <var>out-dir</var>:/out \\\n    -u $USER \\\n    uwplse/herbie report /in/<var>in-file</var> /out/</pre>\n\n  <p>As before, the input and output directories must be mounted inside\n  the Docker container. Note that both here and above, the user is\n  set to the current user. This is to ensure that the files Herbie creates\n  have the correct permissions set.</p>\n\n  <h2>Loading custom platforms</h2>\n\n  <p>If you'd like to write and use <a href=\"platforms.html\">custom\n  platforms</a> with Herbie in Docker, you'll need to mount the\n  platform directory as well:</p>\n\n  <pre class=\"shell\">docker run -it --rm \\\n    -v <var>platform-dir</var>:/platform \\\n    -u $USER \\\n    uwplse/herbie shell \\\n    --platform /platform/<var>platform.rkt</var></pre>\n\n  <p>You can use custom platforms for the web interface or in batch\n  mode using a similar approach.</p>\n\n  <h2>Building the Docker image</h2>\n\n  <p>This section is primarily of interest the Herbie developers.</p>\n\n  <p>Clone the repo and confirm that Herbie builds correctly\n  with <code>make install</code>. Next, examine the Dockerfile and\n  Makefile together. The Dockerfile should follow a process exactly\n  like the Makefile, except a clean initial environment is\n  assumed.</p>\n\n  <p>The build is split into 2 or more stages to limit the size of the\n  resulting image. Each stage consists of a <code>FROM</code> command\n  and a series of further commands to build up the desired\n  environment, and later stages can refer to earlier stages by\n  name&mdash;for example, <code>COPY --from=earlier-stage ...</code>\n  can copy files compiled in earlier images.</p>\n\n  <p>Before building the official image, bump the version of Rust used\n  for binary compilation and the version of Racket used in production,\n  and adjusting paths to match the newest version of the repo.</p>\n\n  <p>Once you are ready, run this from the repository root:</p>\n\n  <pre class=\"shell\">docker build -t uwplse/herbie:test .</pre>\n\n  <p>This builds a new test image and tags\n  it <code>uwplse/herbie:test</code>. You can run this image with:</p>\n\n  <pre class=\"shell\">docker run -p 8000:80 -it uwplse/herbie:test</pre>\n\n  <p>The web demo should now be visible at <code>http://localhost:8000</code>.</p>\n  \n  <p>To open a shell in a running container for testing, first get the\n  container ID with:</p>\n\n  <pre class=\"shell\">docker ps</pre>\n\n  <p>Then open a root shell in that container with</p>\n\n  <pre class=\"shell\">docker exec -it &lt;CONTAINER ID&gt; sh</pre>\n  \n  <p>The code and <code>egg-herbie</code> binaries should be\n  under <code>/src</code>.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.2/error.html",
    "content": "<!doctype html>\n<meta charset=\"utf-8\" />\n<title>What is Error?</title>\n<link rel='stylesheet' type='text/css' href='../../main.css'>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<script type=\"text/javascript\" src=\"toc.js\"></script>\n\n<header>\n  <h1>What is Error?</h1>\n  <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n  <nav>\n    <ul>\n      <li><a href=\"../../demo/\">Try</a></li>\n      <li><a href=\"installing.html\">Install</a></li>\n      <li><a href=\"tutorial.html\">Learn</a></li>\n    </ul>\n  </nav>\n</header>\n\n<p>\n  <a href=\"../../\">Herbie</a> helps you identify and correct floating\n  point error in your numeric programs. But what is floating point\n  error, and how does Herbie measure it?\n</p>\n\n<h2>The summary</h2>\n\n<p>When Herbie reports a \"percentage accuracy\" number like 92.3%, it's\nusually best to think of that as the percentage of floating-point\ninputs where the expression is reasonably accurate.</p>\n\n<p>The impact of this error on your application will depend a lot\non <em>which</em> 7.7% of inputs are inaccurate, and what kind of\nerror that is. You can find this out using\nthe <a href=\"report.html\">accuracy graph in Herbie reports</a>. You\ncan also use preconditions to restrict the inputs Herbie is\nconsidering.</p>\n\n<h2>Why rounding matters</h2>\n\n<p>In mathematics, we work with real numbers, but on a computer, we\ntypically use floating-point numbers. Because there are infinitely\nmany real numbers, but only finitely many floating-point numbers, some\nreal numbers can't be accurately represented. This means that every\ntime you do an operation, the true result will be <em>rounded</em> to\na representable one.</p>\n\n<p>Take an extreme example: the code <code>1e100 + 1</code>, which\nincrements a huge number in IEEE 754 double-precision floating-point.\nThere's an exact real-number answer, a one followed by 99 zeros and\nthen another 1, but the closest <em>floating-point</em> value is the\nsame as <code>1e100</code>.</p>\n\n  <p>Errors like this can cause problems. In the example above, the\n  answers differ by one part per googol, which is pretty small. But the\n  error can grow. For example, since <code>1e100 + 1</code> rounds to\n  the same value as <code>1e100</code>, the larger computation</p>\n\n  <pre>(1e100 + 1) - 1e100</pre>\n\n  <p>returns <code>0</code> instead of the correct answer, <code>1</code>.\n  Now the difference is pretty stark, and can grow even bigger through\n  later operations.</p>\n\n<h2>Bits of error</h2>\n\n<p>There are lots of ways to <em>measure</em> how much rounding error\nthere is in a computation. Most people find the notions of absolute\nand relative error most intuitive, but Herbie internally uses a more\ncomplex notion called <em>bits of error</em>.</p>\n\n<p>The bits of error metric imagines you have a list of all of the\npossible floating-point numbers, from largest to smallest. In that\nlist, compare the floating-point value you computed to the one closest\nto the true answer. If they are the same, that's called 0 bits of\nerror; if they are one apart, that's called one bit of error; three\napart is two bits of error; seven apart is three bits; and so on.</p>\n\n<p>In general, if the two floating-point values are <var>n</var> items\napart, Herbie says they have <code>log2(n + 1)</code> bits of error.\nValues like <code>0</code> and <code>-0</code> are treated as having 0\nbits of error, and NaN is considered to have the maximum number of\nbits of error against non-NaN values. While there's all sorts of\ntheoretical justifications, Herbie mainly uses this error metric\nbecause we've found it to give the best results. </p>\n\n<p>On a single input, the best way to interpret the \"bits of error\"\nmetric is that it tells you roughly how many bits of the answer,\nstarting at the end, are useless. With zero bits of error, you have\nthe best answer possible. With four bits, that's still pretty good\nbecause it's four out of 64. But with 40 or 50 bits of error, you're\ngetting less accuracy out of the computation than even a\nsingle-precision floating-point value. And it's even possible to have\nsomething like 58 or 60 bits of error, in which case even the sign and\nexponent bits (which in double-precision floating-point the the most\nsignificant 12 bits) are incorrect.</p>\n\n<h2>Percentage accuracy</h2>\n\n<p>Because different number representations have different numbers of\nbits, Herbie shows the percentage of bits that are accurate instead of\nthe bits of error. With double-precision floats, for example, 75%\naccurate means 16 bits of error.</p>\n\n<p>Bits of error measures the error of a computation for some specific\ninput. But usually you're interested in the error of a computation\nacross many possible inputs. Herbie therefore averages the accuracy\npercentage across many randomly-sampled valid inputs.</p>\n\n<p>Typically, input points are either very accurate or not accurate at\nall. So when computing percentage accuracy, Herbie's averaging a lot\nof points with near-100% accuracy and a lot of points with near-0%\naccuracy. In that sense, you can think of percentage accuracy as\nmeasuring mostly what percentage <em>of inputs</em> are accurate. If\nHerbie says your computation is 75% accurate what it's really saying\nis that about a quarter of inputs produce usable outputs.</p>\n\n<h2>Valid inputs</h2>\n\n<p>When Herbie computes this average, it's over <em>valid</em>,\nuniformly distributed input points.</p>\n\n<p>Herbie considers an input valid if it is a floating-point value in\nthe appropriate precision and its true, real-number output 1) exists;\n2) satisfies the user's precondition; and 3) can be computed. Let's\ndive into each requirement.</p>\n\n<ol>\n  <li>An output can fail to exist for an input if something like a\n    division by zero or square root of a negative number\n    happens <em>even with exact, real-number computation</em>. Then\n    there's no exact answer to compare against and the point is\n    considered invalid.</li>\n  <li>An input can fail to satisfy the user's precondition, which are\n    usually a range of inputs. For example, if the precondition\n    is <code>(&lt; 1 x 2)</code>, then the input <code>x = 3</code> is\n    invalid.</li>\n  <li>Finally, and most rarely, Herbie can fail to compute the output\n    for a particular input. For example, the computation <code>(/ (exp\n    1e9) (exp 1e9))</code>, which divides two identical but gargantuan\n    numbers, does have an exact real-number answer (one), but Herbie\n    can't compute that exact answer because the intermediate values\n    are too large. This input is also invalid, but you'll\n    get <a href=\"faq.html#ground-truth\">a warning</a> if this\n    happens.</li>\n</ol>\n\n<p>Herbie's percentage accuracy metric only averages over valid\npoints. This means that when you change your precondition, you change\nwhich points are valid, and that can change the percentage accuracy\nreported by Herbie. This is useful: if you've observed a\nfloating-point error, you can tailor your precondition to focus on\ninputs near the one you've observed.</p>\n\n<p>Infinite outputs can be valid. For example, consider <code>(exp\nx)</code> for <code>x = 1e100</code>. The true real-number result is\nsome very large finite number. That real number, whatever it is,\nrounds to infinity in double-precision floating point. Herbie thus\nconsiders this input valid. Since you might find this surprising,\nHerbie issues <a href=\"faq.html#inf-points\">a warning</a> if too many\noutputs are infinite.</p>\n\n<h2>Sampling inputs</h2>\n\n<p>When randomly sampling inputs, Herbie considers each valid input\nequally likely. Importantly, this does not mean that it uses a uniform\ndistribution, because floating-point values themselves are not\nuniformly distributed.</p>\n\n<p>For example, there are as many floating-point values between 1 and\n2 as there are between one and one half, because floating-point values\nuse an exponential encoding. But that means that, in the\ninterval <kbd>[0.5, 2]</kbd>, Herbie will sample from the first third\nof that range twice as often as from the other two thirds.</p>\n\n<p>This can produce unintuitive results, especially for intervals that\ncross 0. For example, in the interval <kbd>[0, 1]</kbd>, the second\nhalf of that interval (from one half to one) has a tiny proportion of\nthe weight (in double-precision floating-point, about 0.1%). If Herbie\ncan improve accuracy by a little bit between zero and one half, while\ndramatically reducing accuracy between one half and one, it will think\nthat that's an accuracy improvement. For this reason, Herbie prompts\nyou to add a minimum absolute value for ranges that cross zero. Even a\ntrivial minimum absolute value, like <code>1e-10</code>, can\ndramatically improve Herbie's results.</p>\n\n<p>Unfortunately, there's no way for Herbie to intuit exactly what you\nmean, so understanding this error distribution is essential to\nunderstanding Herbie's outputs. For example, if Herbie reports that\naccuracy improved from 75% to 76%, it's essential to know: is the\nimprovement happening on inputs between one half and one, or\nbetween <code>1e-100</code> and <code>2e-100</code>? To answer this\nquestion, it's important to look over\nthe <a href=\"report.html\">reports and graphs</a> generated by\nHerbie.</p>\n"
  },
  {
    "path": "www/doc/2.2/faq.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Warnings and Errors</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Common Warnings and Errors</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p><a href=\"../../\">Herbie</a> issues a variety of warnings and\n  errors when something unexpected happens during compilation.</p>\n\n\n  <h2>Common warnings</h2>\n\n  <h3 id=\"inf-points\"><var>N</var>% of points produce a very large (infinite) output.</h3>\n  \n  <p>\n    Sometimes, an input to your expression produces an output so large\n    that it's best represented by a floating-point infinity. For\n    example, <code>(exp 1000)</code> is over 10<sup>434</sup>, so it's\n    much larger than the largest floating-point value. Herbie raises\n    this warning when too many inputs (more than 20% of them) are this\n    large. When you see this warning, you should usually set a more\n    restrictive precondition.\n  </p>\n\n  <h3 id=\"ground-truth\">Could not determine a ground truth</h3>\n\n  <p>\n    Herbie raises this warning when some inputs require more than\n    10,000 bits to compute an exact ground truth. For example, to\n    compute <code>(/ (exp x) (exp x))</code> for <code>x =\n    1e100</code>, absurdly large numbers would be required. Herbie\n    discards these inputs and raises this warning. When you see this\n    warning, you should usually set a more restrictive precondition.\n  </p>\n\n  <h3 id=\"value-to-string\">Could not uniquely print <var>val</var></h3>\n\n  <p>\n    Herbie will raise this warning when it needs more than 10,000 bits\n    to produce a unique decimal representation for a given value. This\n    is likely the result of a bug in a custom platform, likely in\n    a <a href=\"plugins.html\">representation definition</a>. The\n    platform needs to be fixed.\n  </p>\n\n  <h3 id=\"unused-variable\">Unused variable <var>var</var></h3>\n  \n  <p>\n    The input FPCore contains a variable that is not used in the body\n    expression. You should remove the unused variable.\n  </p>\n\n  <h3 id=\"strange-variable\">Unusual variable <var>var</var></h3>\n  \n  <p>\n    The input expression contains a variable that is named similar to\n    some named constant, like <var>e</var> instead of <var>E</var>.\n    You should use a different variable name.\n  </p>\n\n  <h2>Common errors</h2>\n\n  <h3 id=\"invalid-syntax\">Invalid syntax</h3>\n\n  <p>This error means you mis-formatted Herbie's input. Common errors\n  include misspelled function names and parenthesized expressions that\n  should not be parenthesized. For example, in <code>(- (exp (x))\n  1)</code>, the expression <code>x</code> is a variable so shouldn't\n  be parenthesized; <code>(- (exp x) 1)</code> is correct. Follow\n  the <a href=\"input.html\">input format</a> more carefully.\n  </p>\n\n  <h3 id=\"sample-valid-points\">Cannot sample enough valid points</h3>\n\n  <p>This error occurs when Herbie is unable to find enough valid\n  points. For example, the expression <code>(acos (+ 1000 x))</code>\n  is invalid unless <code>(&lt;= -1001 x -999)</code>, a rather narrow\n  range. You can specify a more restrictive precondition or pass a\n  larger value for\n  the <a href=\"options.html\"><code>--num-analysis</code> flag</a>.\n  </p>\n\n  <h3 id=\"no-valid-values\">No valid values</h3>\n\n  <p>This error indicates that your input has no valid inputs, usually\n  due to an overly restriction precondition. For example, the\n  precondition <code>(&lt; 3 x 2)</code> excludes all inputs. You\n  should fix either the precondition or the input program.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.2/input.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Input Format</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>The Input Format</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> uses\n    the <a href=\"http://fpbench.org\">FPCore</a> format to specify an\n    input program, and has extensive options for precisely describing\n    its context.\n  </p>\n\n  <h2>Math format</h2>\n\n  <p>The Herbie web shell takes input in standard math syntax. More\n  specifically, it uses a subset of\n  the <a href=\"https://mathjs.org/docs/expressions/syntax.html\">math.js\n  syntax</a>. The web shell automatically checks for syntax errors,\n  and provides a graphical user interface for specifying the input\n  domain. The web shell converts the mathematical expression and input\n  ranges into FPCore before sending it to Herbie.</p>\n  \n  <h2 id=\"sec1\">FPCore format</h2>\n\n  <p>Herbie's command-line and batch-mode tools\n  use <a href=\"http://fpbench.org\">FPCore</a> format to describe\n  mathematical expressions. FPCore looks like this:</p>\n\n  <pre>(FPCore (<var>inputs ...</var>) <var>properties ...</var> <var>expression</var>)</pre>\n\n  <p>\n    Each <var>input</var> is a variable name, like <code>x</code>,\n    used in the <var>expression</var>. Properties are used to specify\n    additional information about the <var>expression</var>'s context.\n  </p>\n\n  <p>\n    The expression is written in prefix form, with every function call\n    parenthesized, as in Lisp. For example, the formula for the\n    hypotenuse of a triangle with legs <i>a</i> and <i>b</i> is:\n  </p>\n\n  <pre>(FPCore (a b) (sqrt (+ (* a a) (* b b))))</pre>\n\n  <p>\n    The semicolon (<kbd>;</kbd>) character introduces a line comment.\n    We recommend the <code>.fpcore</code> file extension for FPCore files.\n  </p>\n  \n  <h2>Supported functions</h2>\n  \n  <p>FPCore expressions can use any of the following functions:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>, <code>fabs</code></dt>\n    <dd>The usual arithmetic functions</dd>\n    <dt><code>sqrt</code>, <code>cbrt</code></dt>\n    <dd>Square and cube roots</dd>\n    <dt><code>pow</code>, <code>exp</code>, <code>log</code></dt>\n    <dd>Various exponentiations and logarithms</dd>\n    <dt><code>sin</code>, <code>cos</code>, <code>tan</code></dt>\n    <dd>The trigonometric functions</dd>\n    <dt><code>asin</code>, <code>acos</code>, <code>atan</code>, <code>atan2</code></dt>\n    <dd>The inverse trigonometric functions</dd>\n    <dt><code>sinh</code>, <code>cosh</code>, <code>tanh</code></dt>\n    <dd>The hyperbolic functions</dd>\n    <dt><code>asinh</code>, <code>acosh</code>, <code>atanh</code></dt>\n    <dd>The inverse hyperbolic functions</dd>\n    <dt><code>fma</code>, <code>expm1</code>, <code>log1p</code>, <code>hypot</code></dt>\n    <dd>Specialized numeric functions</dd>\n  </dl>\n\n  <p>Herbie also supports the constants <code>PI</code>\n  and <code>E</code>. Use <code>-</code> for both subtraction and\n  negation.</p>\n\n  <p>However, how Herbie evaluates these functions, their cost, and\n  what additional functions are available depends on\n  the <a href=\"platforms.rkt\">platform</a> you select.</p>\n\n  <h2 id=\"conditionals\">Conditionals</h2>\n  \n  <p>FPCore uses <code>if</code> for conditional expressions:</p>\n\n  <pre>(if <var>cond</var> <var>if-true</var> <var>if-false</var>)</pre>\n\n  <p>\n    The conditional <code><var>cond</var></code> may use:\n  </p>\n  \n  <dl class=\"function-list\">\n    <dt><code>==</code>, <code>!=</code>, <code>&lt;</code>, <code>&gt;</code>, <code>&lt;=</code>, <code>&gt;=</code></dt>\n    <dd>The usual comparison operators</dd>\n    <dt><code>and</code>, <code>or</code>, <code>not</code></dt>\n    <dd>The usual logical operators</dd>\n    <dt><code>TRUE</code>, <code>FALSE</code></dt>\n    <dd>The two boolean values</dd>\n  </dl>\n\n  <p>The comparison operators support chained comparisons with more than two arguments;\n    for example <code>(&lt; 1 x 10)</code> means <code>1 < x < 10</code>.</p>\n\n  <h2 id=\"intermediates\">Intermediate variables</h2>\n  \n  <p>Intermediate variables can be defined\n    using <code>let</code> and <code>let*</code>:</p>\n\n  <pre>(let ([<var>variable</var> <var>value</var>] <var>...</var>) <var>body</var>)</pre>\n  <pre>(let* ([<var>variable</var> <var>value</var>] <var>...</var>) <var>body</var>)</pre>\n\n  <p>In both <code>let</code> and <code>let*</code>,\n  each <var>variable</var> is bound to its <var>value</var> and can be\n  used in the <var>body</var>. The difference between <code>let</code>\n  and <code>let*</code> is what order the values are\n  evaluated in:</p>\n\n  <dl>\n    <dt><code>let</code> expressions</dt>\n    <dd>In a <code>let</code> expression, all the values are evaluated\n      in parallel, before they are bound to their variables. This\n      means that later values can't refer to earlier variables in the\n      same <code>let</code> block.</dd>\n\n    <dt><code>let*</code> expressions</dt>\n    <dd>A <code>let*</code> block looks the same as a <code>let</code>\n      block, except the values are evaluated one at a time, and later\n      values can refer to earlier variables.</dd>\n  </dl>\n\n  <p>Unless you have a lot of Lisp experience, you'll probably\n  find <code>let*</code> more intuitive.</p>\n\n  <p>Internally, Herbie treats intermediate values only as a\n  notational convenience, and inlines their values before improving\n  the formula&apos;s accuracy. Using intermediate variables will\n  therefore not produce a more accurate result or help Herbie run\n  faster.</p>\n\n  <h2 id=\"specs\">Specifications</h2>\n\n  <p>In some cases, your input program is an approximation of some\n  more complex mathematical expression. The <code>:spec</code> (for\n  “specification”) lets you specify the more complex ideal case.\n  Herbie will then try to modify the input program to make it more\n  accurately evaluate the specification.</p>\n\n  <p>For example, suppose you want to evaluate <code>sin(1/x)</code>\n  via a series expansion. Write:</p>\n\n  <pre>(FPCore (x)\n  :spec (sin (/ 1 x))\n  (+ (/ 1 x) (/ 1 (* 6 (pow x 3)))))</pre>\n\n  <p>Herbie will use the <code>:spec</code> expression to evaluate\n  error, but use body expression as a starting-point for finding\n  more accurate expressions.</p>\n\n  <h2 id=\"preconditions\">Preconditions</h2>\n\n  <p>By default, the arguments to formulas are assumed to be\n  arbitrarily large or small floating-point numbers. However, in most\n  programs a smaller range of argument values is possible.\n  The <code>:pre</code> property (for “precondition”) describes this\n  smaller range.</p>\n\n  <p>Preconditions use comparison and boolean operators, just\n  like <a href=\"#conditionals\">conditional statements</a>:</p>\n\n  <pre>(FPCore (x) :pre (&lt; 1 x 10) (/ 1 (- x 1)))</pre>\n\n  <p>Herbie is particularly efficient when when the precondition is\n  an <code>and</code> of ranges for each variable, but more complex\n  preconditions also work.</p>\n\n  <h2 id=\"precisions\">Precisions</h2>\n\n  <p>Herbie supports both single- and double-precision values; you can\n  specify the precision with the <code>:precision</code> property:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>binary32</code></dt>\n    <dd>Single-precision IEEE-754 floating point</dd>\n    <dt><code>binary64</code></dt>\n    <dd>Double-precision IEEE-754 floating point</dd>\n  </dl>\n\n  <p><a href=\"platforms.html\">Platforms</a> can also add additional\n  precisions.</p>\n\n  <h2 id=\"properties\">Miscellaneous Input Properties</h2>\n\n  <p>A <var>name</var> can be provided before the argument list to\n  name an FPCore. That FPCore can then be called in other, later\n  FPCores.</p>\n\n  <p>Herbie uses the <code>:name</code> property to name FPCores in\n  its UI. Its value ought to be a string.</p>\n\n  <p>Herbie allows <code>:alt</code> properties to specify additional\n  \"developer targets\"; these might be other alternatives you&apos;ve\n  tried that you want to compare against.</p>\n\n  <p>Herbie&apos;s benchmark suite also uses properties for continuous\n  integration, but these are not officially supported and their use is\n  discouraged.</p>\n  \n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.2/installing.html",
    "content": "<!doctype html>\n<html>\n\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Installing Herbie</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n\n<body>\n  <header>\n    <h1>Installing Herbie</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> supports Linux, macOS, and Windows. To\n    start, install <a href=\"https://racket-lang.org\">Racket</a>. Then\n    install Herbie, either from a package, from source, or via\n    a <a href=\"docker.html\">Docker image</a>.\n  </p>\n\n  <h2>Installing Racket</h2>\n\n  <p>\n    Install Racket either using\n    the <a href=\"http://download.racket-lang.org/\">official\n    installer</a> or distro-provided packages. Versions as old as 8.10\n    are supported, but more recent versions are faster.\n  </p>\n\n  <p>\n    On Linux, we recommend against installing Racket via Snap. If you\n    must install Racket from Snap, install from source and store that\n    source directory in your home directory or another allow-listed\n    directory.\n  </p>\n\n  <p>\n    Test that Racket is installed correctly and has a correct version:\n  </p>\n\n  <pre class=\"shell\">racket\nWelcome to Racket v8.17 [cs].\n> (exit)</pre>\n\n  <h2>Installing Herbie from a package</h2>\n\n  <p>Herbie can be installed as a binary package on x86 Windows and\n  Linux and on x86 or ARM macOS. If you are on a more obscure\n  platform, please install from source instead.</p>\n\n  <p>After installing Racket, install Herbie from a package with:</p>\n\n  <pre class=\"shell\">raco pkg install --auto herbie</pre>\n\n  <p>Then check that Herbie works by running:</p>\n\n  <pre class=\"shell\">racket -l herbie -- --version\nHerbie 2.2</pre>\n\n  <p>If you'd like, you can run Herbie with the <code>herbie</code>\n  command by adding the following directory to your PATH (example\n  paths for Racket 8.17):</p>\n\n  <ul>\n    <li>On Windows, <code>AppData\\Roaming\\Racket\\8.17\\bin</code> in your user folder.</li>\n    <li>On macOS, <code>Library/Racket/8.17/bin</code> in your home folder.</li>\n    <li>On Linux, <code>.local/share/racket/8.17/bin</code> in your home directory.</li>\n  </ul>\n\n  <p>Once Herbie is installed and working correctly, check out\n  the <a href=\"tutorial.html\">tutorial</a>.</p>\n\n  <h2>Installing Herbie from source</h2>\n  \n  <p>Installing Herbie from source is best if you are a Herbie\n  developer, or if you use a more obscure hardware/OS combination. The\n  instructions assume a standard Unix userland; on Windows, you may\n  have to install tools like Make separately, or use WSL.\n  </p>\n\n  <p>\n    Install Racket as described above. Then install Rust 1.60.0 or\n    later using <a href=\"https://rustup.rs/\">rustup</a> or some other\n    means.\n  </p>\n\n  <p>\n    Once Racket and Rust are installed, download the Herbie source\n    <a href=\"https://github.com/uwplse/herbie\">from GitHub</a> with:\n  </p>\n\n  <pre class=\"shell\">git clone https://github.com/herbie-fp/herbie</pre>\n\n  <p>Change to the <code>herbie</code> directory; you should see\n  a <code>README.md</code> file, a directory named <code>src</code>, a\n  directory named <code>bench/</code>, and a few other files and\n  directories. Install Herbie with:</p>\n\n  <pre class=\"shell\">make install</pre>\n\n  <p>This command installs Herbie and its dependencies and compiles it\n  for faster startup. Check that Herbie works by running:</p>\n\n  <pre class=\"shell\">racket -l herbie -- --version\nHerbie 2.2</pre>\n\n  <p>You can add <code>herbie</code> to your path, as described in the\n  package-install instructions. Once Herbie is installed and working\n  correctly, check out the <a href=\"tutorial.html\">tutorial</a>.</p>\n\n  <h2>Installing Herbie with Docker</h2>\n\n  <p><a href=\"https://docker.com\">Docker</a> is a container manager,\n  which is sort of like a virtual machine. We do not recommend using\n  Herbie in Docker without prior Docker experience.</p>\n\n  <p>The <a href=\"docker.html\">Docker documentation</a> describes how\n  to install and run our <code>uwplse/herbie</code> image.</p>\n\n</body>\n\n</html>\n"
  },
  {
    "path": "www/doc/2.2/options.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Command-line Options</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Command-line Options</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>The <a href=\"../../\"><code>herbie</code></a> command has\n  subcommands and options that influence both its user interface and\n  the quality of its output.</p>\n\n  <h2>Herbie commands</h2>\n\n  <p>Herbie provides several subcommands, which offer interactive and\n    batch modes for both the <a href=\"using-cli.html\">command line</a>\n    and the <a href=\"using-web.html\">web interface</a>:</p>\n\n  <dl>\n    <dt><code>racket -l herbie web</code></dt>\n    <dd>Use Herbie <a href=\"using-web.html\">through your browser</a>\n      using a local server. This server can also be used\n      from <a href=\"https://github.com/herbie-fp/odyssey\">Odyssey</a>.</dd>\n\n    <dt><code>racket -l herbie shell</code></dt>\n    <dd>Use Herbie <a href=\"using-cli.html\">via a command-line shell</a>.\n    Enter an <a href=\"input.html\">FPCore expression</a> and Herbie\n    prints faster and more accurate alternatives.</dd>\n\n    <dt><code>racket -l herbie improve <var>input</var> <var>output</var></code></dt>\n    <dd>Run Herbie on the expressions in the file or\n    directory <var>input</var>. The results are written\n    to <var>output</var>, a single file in FPCore format.</dd>\n\n    <dt><code>racket -l herbie report <var>input</var> <var>output</var></code></dt>\n    <dd>Run Herbie on the expressions in the file or\n    directory <var>input</var>. The results are written\n    to <var>output</var>, a directory of\n    HTML <a href=\"report.html\">reports</a>. Viewing these requires a\n    web server.</dd>\n  </dl>\n\n  <p>We recommend the <code>web</code> subcommand for interactive use\n  with detailed <a href=\"report.html\">reports</a> that include graphs\n  of error versus input values and plots comparing cost and accuracy.\n  This can help you understand whether Herbie's improvements matter\n  for your use case.</p>\n\n  <p>Use <code>herbie <var>subcommand</var> --help</code> to view\n  available command-line options for a subcommand. This command also\n  shows undocumented subcommands not listed on this page.</p>\n\n  <h2>General options</h2>\n\n  <p>\n    General options apply to all subcommands and are passed after the\n    subcommand name but before other arguments, like this:\n  </p>\n\n  <pre class=\"shell\">racket -l herbie report --timeout 60 in.fpcore out/</pre>\n\n  <p>Options must go before subcommand arguments like input and output\n  paths.</p>\n\n  <dl>\n    <dt><code>--platform <var>P</var></code></dt>\n    <dd>Herbie's backend <a href=\"platforms.html\">platform</a>, which\n      affects the operations available to Herbie, their accuracies,\n      and their costs. The platform name is either one of the built-in\n      platforms, or the path to a <a href=\"platforms.html\">custom\n      platform</a>. In general, it's best to select the platform that\n      most closely matches the programming language and hardware where\n      you will be running floating-point code.</dd>\n\n    <dt><code>--seed <var>S</var></code></dt>\n    <dd>The random seed, which changes the randomly-selected points\n      that Herbie evaluates candidate expressions on. The seed is a\n      number between 0 and 2<sup>31</sup> (not including the latter).\n      Two runs of Herbie with the same seed should produce identical\n      results. By default, a random seed is chosen.</dd>\n\n    <dt><code>--timeout <var>T</var></code></dt>\n    <dd>The timeout to use per-input, in seconds. A fractional number\n      of seconds can be given. By default, no timeout is used.</dd>\n\n    <dt><code>--threads <var>N</var></code></dt>\n    <dd>Enables multi-threaded operation. By default, no threads are\n      used. The argument is the number of threads to use,\n      or <code>yes</code> to use all of the hardware threads.</dd>\n\n    <dt><code>--num-points <var>N</var></code></dt>\n    <dd>The number of input points Herbie uses to evaluate candidate\n      expressions. The default, 256, is a good balance for most\n      programs. Increasing this option, say to 512 or 1024, will slow\n      Herbie down but may make its results more consistent.</dd>\n\n    <dt><code>--num-iters <var>N</var></code></dt>\n    <dd>The number of attempts Herbie makes to improve accuracy. The\n      default, 4, suffices for most programs, and more iterations are\n      rarely beneficial. But increase this option, say to 6, can\n      sometimes lead to more accurate or faster results.</dd>\n\n    <dt><code>--num-analysis <var>N</var></code></dt>\n    <dd>The number of input subdivisions to use when searching for\n      valid input points. The default is 12. Increasing this option\n      will slow Herbie down, but may fix a\n      \"<a href=\"faq.html#sample-valid-points\">Cannot sample enough\n      valid points</a>\" error.</dd>\n    \n    <dt><code>--num-enodes <var>N</var></code></dt>\n    <dd>The number of equivalence graph nodes to use when doing\n      algebraic reasoning. The default is 4000. Increasing this option\n      will slow Herbie down, but may improve results slightly.</dd>\n    \n  </dl>\n\n  <h2>Web shell options</h2>\n  \n  <p>The <code>web</code> tool runs Herbie and connects to it from\n  your browser. It has options to control the underlying web\n  server.</p>\n  \n  <dl>\n    <dt><code>--port N</code></dt>\n    <dd>The port the Herbie server runs on. The default port is 8000.</dd>\n\n    <dt><code>--save-session dir</code></dt>\n    <dd>Save all the reports to this directory. The directory also\n    caches previously-computed expressions.</dd>\n\n    <dt><code>--log file</code></dt>\n    <dd>Write an access log to this file, formatted like an Apache\n    log. This log does <em>not</em> contain crash tracebacks.</dd>\n\n    <dt><code>--quiet</code></dt>\n    <dd>By default, but not when this option is set, a browser is\n    automatically started to show the Herbie page. This option also\n    shrinks the text printed on start up.</dd>\n\n    <dt><code>--no-browser</code></dt>\n    <dd>This flag disables the default behavior of opening the Herbie page in your default browser.</dd>\n\n    <dt><code>--public</code></dt>\n    <dd>When set, users on other computers can connect to the demo and\n    use it. (In other words, the server listens\n    on <code>0.0.0.0</code>.) Essential when Herbie is run\n    from <a href=\"docker.html\">Docker</a>.</dd>\n  </dl>\n\n  <h2>Rulesets</h2>\n\n  <p>\n    Herbie uses rewrite rules to change programs and improve accuracy.\n    The <code>--disable rules:<var>group</var></code>\n    and <code>--enable rules:<var>group</var></code> options turn rule\n    sets on and off. In general, turning a ruleset on makes Herbie\n    produce more accurate programs.\n  </p>\n\n  <p>The full list of rule groups is:</p>\n\n  <table class=\"function-list\">\n    <thead><tr><th>Rule Group</th><th>Topic of rewrite rules</th></tr></thead>\n    <tr><td>arithmetic</td><td>Basic arithmetic facts</td></tr>\n    <tr><td>polynomials</td><td>Factoring and powers</td></tr>\n    <tr><td>fractions</td><td>Fraction arithmetic</td></tr>\n    <tr><td>exponents</td><td>Exponentiation identities</td></tr>\n    <tr><td>trigonometry</td><td>Trigonometric identities</td></tr>\n    <tr><td>hyperbolic</td><td>Hyperbolic trigonometric identities</td></tr>\n  </table>\n\n  <h2>Search options</h2>\n\n  <p>These options enable or disable transformations that Herbie uses\n    to find candidate programs. We recommend sticking to the\n    defaults.</p>\n\n  <p>\n    Each option can be turned off with the <code>-o</code>\n    or <code>--disable</code> command-line flag and on with\n    <code>+o</code> or <code>--enable</code>. Turning an option off\n    typically results in less-accurate results, while turning a option\n    on typically results in more confusing output expressions.\n  </p>\n\n  <dl>\n    <dt><code>setup:search</code></dt>\n    <dd>This option, on by default, uses interval subdivision search\n    to help compute ground truth for complicated expressions. If\n    turned off, Herbie will be slightly faster, but may hit the\n    \"<a href=\"faq.html#sample-valid-points\">Cannot sample enough valid\n    points</a>\" error more often. Instead of turning this option off,\n    try adjusting the <kbd>--num-analysis</kbd> flag.</dd>\n\n    <dt><code>generate:rr</code></dt>\n    <dd>This option, on by default, uses algebraic rewriting to\n    generate candidate programs. This is Herbie's primary method of\n    improving accuracy, and we do not recommend turning off this\n    option.</dd>\n\n    <dt><code>generate:taylor</code></dt>\n    <dd>This option, on by default, uses series expansion to generate\n    candidate programs. If turned off, Herbie will not use series\n    expansion, which may help accuracy in some ranges while leaving\n    Herbie unable to solve certain under- and overflow issues.</dd>\n\n    <dt><code>generate:evaluate</code></dt>\n    <dd>This option, on by default, uses arbitrary-precision\n    arithmetic to generate candidate programs, specifically by exactly\n    computing some constant expressions. If turned off, these exact\n    computations won't be performed and Herbie won't be able to\n    improve accuracy in those cases.</dd>\n\n    <dt><code>generate:proofs</code></dt>\n    <dd>This option, on by default, generates step-by-step derivations\n    for HTML reports. If turned off, the step-by-step derivations will\n    be absent, and Herbie will be slightly faster.</dd>\n\n    <dt><code>reduce:regimes</code></dt>\n    <dd>This option, on by default, uses Herbie's regime inference\n    algorithm to branch between several program candidates. If turned\n    off, branches will not be inferred and the output program will be\n    straight-line code (if the input was). Instead of turning this\n    option off, consider increasing your platform's\n    <a href=\"platforms.html\"><code>if</code> cost</a> to discourage\n    branches.</dd>\n\n    <dt><code>reduce:binary-search</code></dt>\n    <dd>This option, on by default, uses binary search to refine the\n    values used in inferred branches. If turned off, different runs of\n    Herbie will be less consistent, and accuracy near branches will\n    suffer.</dd>\n\n    <dt><code>reduce:branch-expressions</code></dt>\n    <dd>This option, on by default, allows Herbie to branch on\n      expressions, not just variables. This slows Herbie down,\n      particularly for large programs. If turned off, Herbie will only\n      try to branch on variables.</dd>\n  </dl>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.2/platforms.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Platforms</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Writing a Herbie Platform</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>Platforms define <a href=\"../../\">Herbie</a> compilation targets.\n  A platform might be specific to a programming language, to a math\n  library, or to a hardware ISA. Writing a custom platforms can help\n  Herbie produce faster and more accurate programs.</p>\n\n  <h2>Platform Concepts</h2>\n  \n  <p>Herbie operates on mathematical specifications and floating-point\n  expressions.</p>\n\n  <p><dfn>Specifications</dfn> are built from rational numbers,\n  variables, and <dfn>functions</dfn> like <code>+</code>,\n  <code>sin</code>, <code>&lt;</code>, and <code>if</code>. A\n  specification has a <dfn>type</dfn>, which is\n  either <code>real</code> or <code>bool</code>.</p>\n\n  <p>Types, functions, and specifications have floating-point\n  analogs.</p>\n  \n  <p><dfn>Representations</dfn> are the floating-point analogs of\n  types, and Herbie comes with three built in:\n  <code>&lt;binary32&gt;</code> and <code>&lt;binary64&gt;</code> are\n  reprentations of <code>real</code> and correspond to single- and\n  double-precision IEEE-754 arithmetic. There's also\n  a <code>&lt;bool&gt;</code> representation for booleans. It's\n  possible to define new representations, described\n  on <a href=\"plugins.html\">another page</a>.</p>\n\n  <p><dfn>Operations</dfn> are the floating-point analog of functions\n  and represent the actual floating-point operation the compilation\n  target can perform. There are typically several operations for each\n  supported function; for example, in the C standard library\n  <a href=\"https://en.cppreference.com/w/c/numeric/math/cos.html\">provides</a>\n  <code>cosf</code> and <code>cos</code>, both of which correspond to\n  the <code>cos</code> function but for different representations\n  (<code>&lt;binary32&gt;</code> and <code>&lt;binary64&gt;</code>).</p>\n  \n  <p><dfn>Expressions</dfn> are the floating-point analog of\n  specifications and represent target-specific floating-point\n  computations. Platforms, to put it simply, just define the set of\n  representations and operations that expressions are allowed to use.\n  Herbie then searches for a fast and accurate expression that\n  corresponds to the user's input specification.</p>\n\n  <p>Each representation, operation, and thus expression has a\n  <dfn>cost</dfn>, which is a non-negative real number. Generally, the\n  cost of a representation is the time it takes to read a value of\n  that representation from memory and the cost of an operation is the\n  time it takes to execute that operation. However, in principle,\n  platforms can use cost to represent another metric like area or\n  latency. Only relative costs matter. If you're not sure, just\n  putting \"<code>1</code>\" for all the costs is not a bad place to\n  start.</p>\n  \n  <h2>Defining a Platform</h2>\n\n  <p>A platform definition is a text file that starts with:</p>\n\n  <pre>#lang herbie/platform</pre>\n  \n  <p>Herbie can then be informed to use this platform by passing\n  the <code>--platform <var>path/to/file</var></code> <a href=\"options.html\">command-line\n  argument</a>.</p>\n\n  <p>The file contains <a href=\"https://racket-lang.org/\">Racket</a>\n  code. That code can define the platform's representations and\n  operations using <code>define-representation</code>\n  and <code>define-operation</code>. It can also define variables and\n  helper functions, import external packages, or anything else Racket\n  can do. If necessary, it can define new representations.</p>\n  \n  <p>Herbie's <a href=\"https://github.com/herbie-fp/herbie/tree/main/src/platforms\">built-in\n  platforms</a> are good example platforms to study or modify. If you\n  use them as an example, you'll need to change the <code>#lang</code>\n  line at the top of the file to be <code>herbie/platforms</code>; the\n  built-in platforms are different because they are built in to Herbie\n  and can't assume Herbie is installed.</p>\n\n  <h2>Defining Representations</h2>\n\n  <p>The typical platform starts by defining the representations it\n  uses and their costs with <code>define-representation</code>:</p>\n\n  <pre>(define-representation &lt;bool&gt; #:cost 1)\n(define-representation &lt;binary64&gt; #:cost 1.5)</pre>\n\n  <p>This cost is the cost for reading a variable or literal of that\n  representation. Note that platforms must explicitly define a cost\n  for the <code>&lt;bool&gt;</code> representation if it uses\n  booleans. If the platform forgets to define a representation that it\n  uses, Herbie will produce an error when loading the platform.</p>\n\n  <p>If the same cost is used repeatedly, it can be convenient to\n  define a variable:</p>\n\n  <pre>(define cost 1)\n(define-representation &lt;bool&gt; #:cost cost)</pre>\n  \n  <p>After defining the representations it uses, a platform then\n  defines all the operations it supports.</p>\n  \n  <h2>Defining Operations</h2>\n\n  <p>An operation is defined by four fields:</p>\n\n  <ul>\n    <li>A <dfn>signature</dfn>, which gives the operation's name and\n    its input and output representations.</li>\n\n    <li>A <dfn>specification</dfn> for the operation's mathematical\n    behavior.</li>\n\n    <li>An <dfn>implementation</dfn> that computes the operation's\n    output given concrete inputs.</li>\n\n    <li>A <dfn>cost</dfn> for using the operation in an\n    expression.</li>\n  </ul>\n  \n  <p>The <code>define-operation</code> construct requires exactly\n  these four fields:</p>\n\n  <pre>(define-operation (recip [x &lt;binary32&gt;]) &lt;binary32&gt;\n  #:spec (/ 1 x) #:impl (lambda (x) ...) #:cost 3)</pre>\n\n  <p>The first line gives the operation's signature: it is\n  named <code>recip</code>, it has one single-precision\n  input <code>x</code>, and it outputs a single-precision float.</p>\n\n  <p>The <code>#:spec</code> field gives this operation's\n  specification as <code>(/ 1 x)</code>, one divided\n  by <code>x</code>. In other words, this operation computes a\n  number's reciprocal.</p>\n\n  <p>The <code>#:impl</code> field gives this operation's\n  implementation, as a Racket function (defined\n  with <code>lambda</code>). An operation's implementation is a Racket\n  function with as many arguments as the operation. It is called with\n  concrete inputs in the corresponding input representations, and must\n  return an output in the output representation. It can be defined\n  using a <code>lambda</code>, a <code>define</code> block, or any\n  other function-defining Racket construct.</p>\n\n  <p>When an implementation function is called,\n  <code>&lt;binary64&gt;</code> and <code>&lt;binary32&gt;</code>\n  arguments are passed as Racket\n  <a href=\"https://docs.racket-lang.org/guide/performance.html#%28tech._flonum%29\">flonums</a>,\n  while <code>&lt;bool&gt;</code> arguments are passed as Racket\n  <a href=\"https://docs.racket-lang.org/reference/booleans.html#%28def._%28%28quote._~23~25kernel%29._boolean~3f%29%29\">booleans</a>.\n  Single-precision numbers aren't a separate type in Racket. instead,\n  you create them from double-precision floats by\n  calling <a href=\"https://docs.racket-lang.org/reference/flonums.html#%28def._%28%28lib._racket%2Fflonum..rkt%29._flsingle%29%29\"><code>flsingle</code></a>.</p>\n\n  <p>For this example, to compute a 32-bit reciprocal for a 32-bit\n  input, one could use <code>(flsingle (/ 1.0 x))</code> for the body\n  of the <code>lambda</code>.</p>\n\n  <p>The <code>#:cost</code> field gives this operation's cost, 3.</p>\n\n  <h2>Defining Multiple Operations</h2>\n  \n  <p>Realistic platform usually have a lot of similar operations:\n  addition, subtraction, multiplication, and division, or sine,\n  cosine, tangent, and so on. The <code>define-operations</code>\n  construct defines multiple operations at a time, as long as they\n  have the same input and output representations:</p>\n\n  <pre>(define-operations ([x &lt;binary64&gt;] [y &lt;binary64&gt;]) &lt;binary64&gt;\n    [+ #:spec (+ x y) #:impl + #:cost 0.200]\n    [- #:spec (- x y) #:impl - #:cost 0.200]\n    [* #:spec (* x y) #:impl * #:cost 0.250]\n    [/ #:spec (/ x y) #:impl / #:cost 0.350])</pre>\n\n  <p>This block defines four functions, each with their own name,\n  specification, implementation, and cost. Note that in this case\n  the <code>#:impl</code> column refers to the Racket\n  functions <code>+</code>, <code>-</code>, <code>*</code>,\n  and <code>/</code>.</p>\n\n  <h2>Common Kinds of Operations</h2>\n\n  <p>This section lists common kinds of operations and notes things\n  you should keep in mind when defining them.</p>\n\n  <h3>Math Library Functions</h3>\n\n  <p>Most operating systems have a standard <code>libm</code> library\n  that provides elementary functions like <code>cos</code>. You can\n  use Herbie's <code>from-libm</code> helper to load implementations\n  from <code>libm</code>:</p>\n\n  <pre>(define-operation (fabs.f32 [x &lt;binary32&gt;]) &lt;binary32&gt;\n  #:spec (fabs x) #:impl (from-libm 'fabsf) #:cost 0.125)</pre>\n\n  <p>The <code>from-libm</code> uses dynamic linking to\n  load <code>libm</code>, extracts the symbol passed\n  to <code>from-libm</code>, and then uses the operation's signature\n  to call into the dynamically-linked library from Racket. Must make\n  sure to pass the correct symbol name; for single-precision\n  functions, make sure to add the \"<code>f</code>\" suffix.</p>\n\n  <h3>Numeric Variations</h3>\n\n  <p>Some platforms provide numeric variations like <code>log1p</code>\n  or <code>cosd</code> for common functions. You can define operations\n  for them using complex specifications:</p>\n\n  <pre>(define-operation (cosd [x &lt;binary64&gt;]) &lt;binary64&gt;\n  #:spec (cos (* x (/ (PI) 180))) #:impl (lambda (x) ...) #:cost 4)</pre>\n\n  <p>The <code>#:spec</code> in this example explains to Herbie\n  that <code>cosd</code> is the cosine of <code>x</code> in degrees.\n  Herbie will then use <code>cosd</code> when that improves\n  accuracy.</p>\n\n  <p>Other common numeric variations\n  include <code>fma</code>, <code>log1p</code>, <code>expm1</code>,\n  and <code>hypot</code>. If they're available on your target,\n  we <em>strongly</em> recommend defining operations for them; they\n  often improve accuracy by quite a bit!</p>\n\n  <h3>Conversions</h3>\n\n  <p>A conversion or cast operation uses mixed representations:</p>\n\n  <pre>(define-operation (64-&gt;32 [x &lt;binary64&gt;]) &lt;binary32&gt;\n  #:spec x #:impl flsingle #:cost 1)</pre>\n\n  <p>This operation has a 64-bit input and a 32-bit output. Its\n  specification is just <code>x</code>, which means it doesn't\n  actually do anything mathematically. The implementation is the\n  standard Racket <code>flsingle</code> function (which converts from\n  double- to single-precision) and it has a cost of 1.</p>\n\n  <p>Herbie will use this conversion operation for casting between the\n  two types.</p>\n\n  <h3>Comparisons</h3>\n\n  <p>Comparison operations return <code>&lt;bool&gt;</code>:</p>\n\n  <pre>(define-operations ([x &lt;binary64&gt;] [y &lt;binary64&gt;]) &lt;bool&gt;\n  [==.f64 #:spec (== x y) #:impl =          #:cost 1]\n  [!=.f64 #:spec (!= x y) #:impl (negate =) #:cost 1]\n  [&lt;.f64  #:spec (&lt; x y)  #:impl &lt;          #:cost 1]\n  [&gt;.f64  #:spec (&gt; x y)  #:impl &gt;          #:cost 1]\n  [&lt;=.f64 #:spec (&lt;= x y) #:impl &lt;=         #:cost 1]\n  [&gt;=.f64 #:spec (&gt;= x y) #:impl &gt;=         #:cost 1])</pre>\n  \n  <p>Here, <code>negate</code> is\n  a <a href=\"https://docs.racket-lang.org/reference/procedures.html#%28def._%28%28lib._racket%2Ffunction..rkt%29._negate%29%29\">Racket\n  function</a> that negates a comparison function.</p>\n\n  <p>A platform only needs to provide the comparison functions\n  available on the target. However, Herbie's \"regimes\" pass uses\n  the <code>&lt;=</code> operation, so it's best to provide one if one\n  is available.</p>\n\n  <p>A platform that uses both representation needs to define\n  separate <code>&lt;binary32&gt;</code>\n  and <code>&lt;binary64&gt;</code> comparison operations. They can\n  have different costs.</p>\n\n  <h3>Conditionals</h3>\n\n  <p>Conditionals can be defined as operations with a boolean argument:</p>\n\n  <pre>(define-operation (if-f64 [c &lt;bool&gt;] [t &lt;binary64&gt;] [f &lt;binary64&gt;]) &lt;binary64&gt;\n  #:spec (if c t f) #:impl if-impl\n  #:cost (if-cost 14) )</pre>\n\n  <p>Here <code>if-impl</code> is a Herbie-provided Racket function\n  that wraps a standard <code>if</code> statement, while\n  the <code>if</code> inside the <code>#:spec</code> is how\n  specifications refer to mathematical conditional expressions.</p>\n\n  <p>Conditional operations usually pass a procedure to\n  <code>#:cost</code>. The helper <code>if-cost</code> returns a procedure\n  that receives the costs of the arguments and combines them into a\n  total cost. It computes the cost of evaluating the condition plus the\n  larger of the two branch costs. In this example we add a constant cost\n  of 14 to that value.</p>\n\n  <p>A platform needs to define both <code>&lt;binary32&gt;</code>\n  and <code>&lt;binary64&gt;</code> conditional operations if it uses\n  both representations. They can have different costs. There's\n  typically no need to define conditional operations\n  for <code>&lt;bool&gt;</code> as Herbie does not rewrite boolean\n  expressions.</p>\n\n  <h3>Constants</h3>\n\n  <p>Mathematical constants like <code>E</code> and <code>PI</code>\n  are considered operations in Herbie; they just have no inputs. For\n  example, to define a 64-bit inverse-&pi; constant, write:</p>\n\n  <pre>(define-operation (INVPI) &lt;binary64&gt;\n  #:spec (/ 1 (PI)) #:impl (lambda () ...) #:fpcore PI #:cost 0.5)</pre>\n\n  <p>Note the parentheses in various fields. The\n  name <code>INVPI</code> has parentheses around it like all operation\n  signatures; it just doesn't have any arguments after the name. In\n  the <code>#:spec</code>, the <code>PI</code> constant is also\n  wrapped in parentheses because it is also treated as a zero-argument\n  function. And in the <code>#:impl</code>, the implementation is\n  given by a Racket function of no arguments. You can also use\n  the <a href=\"https://docs.racket-lang.org/reference/procedures.html#%28def._%28%28lib._racket%2Ffunction..rkt%29._const%29%29\">Racket <code>const</code>\n  function</a> to construct these no-argument functions.</p>\n\n  <p>But in the <code>#:fpcore</code> field the <code>PI</code> value\n  doesn't use parentheses, because FPCore treats constants as\n  constants, not zero-argument functions.</p>\n\n  <p>Constants can be defined in any precision. If you want the same\n  constant to be available in multiple precisions, you have to define\n  multiple constant operations.</p>\n\n  <h3>Negation</h3>\n\n  <p>Herbie's specification language has a negation function, and it's\n  usually a good idea to define a negation operation if your target\n  has one. Define it like this:</p>\n\n  <pre>(define-operation (neg.f32 [x &lt;binary64&gt;]) &lt;binary64&gt;\n    #:spec (neg x) #:impl - #:fpcore (- x) #:cost 0.125)</pre>\n\n  <p>Here, in the <code>#:spec</code>, <code>(neg x)</code> refers to\n  the negation function in Herbie's specification language, while\n  the <code>-</code> symbol after <code>#:impl</code> refers to\n  Racket's subtraction function, which also acts as a negation\n  function.</p>\n\n  <p>There is also an <code>#:fpcore</code> field. This field tells\n  Herbie how to represent this operation in FPCore (for user input and\n  output). The default <code>#:fpcore</code> is the operation's\n  <code>#:spec</code> but there are a few functions (like negation)\n  where Herbie's specification language uses a different syntax from\n  FPCore and <code>#:fpcore</code> needs to be specified manually.</p>\n\n  <h3>Precision-specific Variations</h3>\n\n  <p>If a platform supports both <code>&lt;binary32&gt;</code>\n  and <code>&lt;binary64&gt;</code>, they often support similar\n  operations:</p>\n\n  <pre>(define-operations ([x &lt;binary32&gt;]) &lt;binary32&gt;\n    #:fpcore (! :precision binary32 _)\n    [fabs.f32 #:spec (fabs x) #:impl (from-libm 'fabsf) #:cost 0.125]\n    [sin.f32  #:spec (sin x)  #:impl (from-libm 'sinf)  #:cost 4.250]\n    ...)\n  (define-operations ([x &lt;binary64&gt;]) &lt;binary64&gt;\n    #:fpcore (! :precision binary64 _)\n    [fabs.f64 #:spec (fabs x) #:impl (from-libm 'fabs)  #:cost 0.125]\n    [sin.f64  #:spec (sin x)  #:impl (from-libm 'sin)   #:cost 4.200]\n    ...)</pre>\n\n  <p>Here, two <code>define-operations</code> blocks define two sets\n  of functions with different signatures but identical specifications.\n  To disambiguate these functions in FPCore output,\n  the <code>#:fpcore</code> argument to <code>define-operations</code>\n  defines <a href=\"input.html\">different FPCore properties</a> for\n  each set of operations. In that argument, the underscore is replaced\n  by each operation's <code>#:spec</code>.</p>\n\n  <h3>Hard-to-emulate Operations</h3>\n\n  <p>Sometimes a platform will offer an operation that's difficult to\n  implement accurately. In this case, Herbie's <code>from-rival</code>\n  helper can provide a slow but correctly-rounded implementation:</p>\n\n  <pre>(define-opertion (dotprod [a &lt;binary64&gt;] [b &lt;binary64&gt;]\n                            [c &lt;binary64&gt;] [d &lt;binary64&gt;]) &lt;binary64&gt;\n  #:spec (+ (* a b) (* c d)) #:impl (from-rival) #:cost 1.25)</pre>\n\n  <p>The <code>from-rival</code> helper uses\n  the <a href=\"https://www.mpfr.org/\">MPFR</a> library to evaluate the\n  operation's specification. Compilation is usually <em>much</em>\n  slower than with a native floating-point implementation, but for\n  unusual operations that are difficult to implement otherwise, it can\n  still allow compilation to proceed.</p>\n\n  <p>Note that <code>from-rival</code> implementations are always\n  \"correctly-rounded\", meaning as accurate as possible. Most targets\n  don't actually offer correctly-rounded operations, which can mean\n  that Herbie's outputs won't be as accurate as Herbie assumes. It's\n  always better to execute the actual operation on the actual target\n  if possible, so as to precisely emulate its actual behavior.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.2/plugins.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Other APIs</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Other Herbie APIs</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p><a href=\"../../\">Herbie</a> <a href=\"platforms.html\">platforms</a>\n  are the main way to customize Herbie's behavior. The typical\n  platform just defines the set of representations and operations that\n  available to Herbie when compiling. However, platform files can\n  technically contain arbitrary Racket code, and thus can call other\n  Herbie APIs, including importing external libraries, defining new\n  representations, and so on. This page documents such APIs. Note that\n  a level of comfort with Racket is assumed.</p>\n\n  <p>Please note that all of the APIs on this page are considered\n  unstable and may change version to version. If you run into issues,\n  please\n  <a href=\"https://github.com/uwplse/herbie/issues\">file a\n  bug</a>.</p>\n\n  <h2>Defining representations</h2>\n\n  <p><dfn>Representations</dfn> what Herbie calls different number\n  formats. They play a central role\n  in <a href=\"platforms.html\">platforms</a>. Concretely, a\n  representation is a set of Racket values that represent both real\n  numbers and bit patterns.</p>\n\n  <p>Specifically, a representation value needs to be convertible to\n  Racket <a href=\"https://docs.racket-lang.org/math/bigfloat.html\"><code>bigfloat</code></a>\n  values (which are basically MPFR floats) and also\n  to <em>ordinals</em>, meaning integers between\n  -2<sup><var>w</var>&minus;1</sup> and\n  2<sup><var>w</var>&minus;1</sup>&minus;1 for some bit width <var>w</var>.</p>\n\n  <p>Create representations with <code>make-representation</code>:</p>\n\n  <code>\n  <table>\n    <tr><td colspan=2>(<b>make-representation</b></td></tr>\n    <tr><td></td><td>#:name <var>name</var></td></tr>\n    <tr><td></td><td>#:total-bits <var>width</var></td></tr>\n    <tr><td></td><td>#:bf->repr <var>bf->repr</var></td></tr>\n    <tr><td></td><td>#:repr->bf <var>repr->bf</var></td></tr>\n    <tr><td></td><td>#:ordinal->repr <var>ordinal->repr</var></td></tr>\n    <tr><td></td><td>#:repr->ordinal <var>repr->ordinal</var></td></tr>\n    <tr><td></td><td>#:special-value? <var>special?</var>)</td></tr>\n  </table>\n  </code>\n\n  <p>The <code>#:name</code> should be either a symbol, or a list\n  containing symbols and integers. The <code>#:total-bits</code> value\n  should be a positive integer. The <code>#:total-bits</code>\n  parameter determines the total ordinal range your format takes up,\n  not just its significand range, so for example for double-precision\n  floats you need a <code>#:total-bits</code> of 64.</p>\n\n  <p>The <code>#:bf->repr</code> and <code>#:repr->bf</code> values\n  should be that convert between representation values and Racket\n  bigfloats. The <code>repr->bf</code> function should use as large a\n  bigfloat precision as needed to exactly represent the value, while\n  the <code>bf->repr</code> function should round as per the current\n  value of\n  the <a href=\"https://docs.racket-lang.org/math/bigfloat.html#%28def._%28%28lib._math%2Fbigfloat..rkt%29._bf-rounding-mode%29%29\">bf-rounding-mode</a>\n  parameter.</p>\n\n  <p>All non-NaN bigfloat values should result in non-NaN\n  representation values. For example, <code>(bf->repr (bf\n  \"1e1000000\"))</code> should yield the largest real value in the\n  representation. Infinite values, as in <code>(bf->repr\n  +inf.bf)</code>, should be interpreted as really large real values,\n  not as infinite values. For example,\n  the <a href=\"https://posithub.org/\">posit</a> format has an\n  \"infinite\" value, but it behaves more like a NaN, so converting\n  bigfloat infinity to a posit should yield its largest real value\n  instead.</p>\n\n  <p>The <code>#:ordinal->repr</code> and <code>#:repr->ordinal</code>\n  functions represent ordinals as Racket integers between\n  -2<sup><var>width</var>&minus;1</sup> (inclusive) and\n  2<sup><var>width</var>&minus;1</sup> (exclusive). Ordinals\n  must be in real-number order; that is, if <code>(repr->bf x)</code>\n  is less than <code>(repr->bf y)</code>, then <code>(repr->ordinal\n  x)</code> should be less than <code>(repr->ordinal y)</code>.</p>\n\n  <p>The <code>#:special</code> function should return true for NaN\n  values (or whatever your representation calls values that don't\n  represent any real number) and false for all other values. Special\n  values can be anywhere in the ordinal range, and you can have as\n  many or as few of them as you want.</p>\n\n  <p><code>make-representation</code> returns a representation object,\n  which you can then use\n  in <a href=\"platforms.html\"><code>define-representation</code>\n  and <code>define-operation</code></a>.</p>\n\n  <h2>Defining Generators</h2>\n\n  <p><dfn>Generators</dfn> are helper functions for generating\n  implementations in <code>define-operation</code>. For\n  example, <a href=\"platforms.html\"><code>from-libm</code>\n  and <code>from-rival</code></a> are generators.</p>\n\n  <p>To define a generator, use <code>define-generator</code>:</p>\n\n  <code><table>\n  <tr><td colspan=2>(<b>define-generator</b> ((from-<var>foo</var> <var>args</var> ...) spec ctx)</td></tr>\n  <tr><td></td><td><var>body</var> ...)</td></tr>\n  </table></code>\n\n  <p>Here, <code>from-<var>foo</var></code> is the name of your\n  generator, and <var>args</var> are any additional arguments the\n  generator takes. For example, <code>from-libm</code> takes one\n  argument, the symbol name.</p>\n\n  <p>Then, inside the <var>body</var>, you can use those arguments as\n  well as <code>spec</code> and <code>ctx</code>, to construct an\n  actual implementation function.</p>\n\n  <p>The specification <code>spec</code> is a Racket tree made up of\n  lists and symbols and numbers.</p>\n\n  <p>The signature <code>ctx</code> is \"context\" object; you can\n  access its <code>context-repr</code> to get the operation's output\n  representation, its <code>context-vars</code> to access its variable\n  names (as a list of symbols), and its <code>context-var-reprs</code>\n  to access its input representations (as a parallel list of\n  representations). The <code>context-lookup</code> function can be\n  used to look up a input argument's representation by name.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.2/release-notes.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie 2.2 Release Notes</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <script src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML\"></script>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <style>\n    .showcase { margin: 1em 0; }\n    .showcase.side-by-side { display: flex; gap: 1em; }\n    .showcase.side-by-side :nth-child(1) { width: 60%; }\n    .showcase.side-by-side :nth-child(2) { flex-grow: 1; hyphens: auto; }\n    #team {\n        display: block; box-sizing: border-box; width: 100%;\n        border-radius: 2em; border: 3px solid black;\n    }\n  </style>\n</head>\n<body>\n  <header>\n    <h1>Herbie 2.2 Release Notes</h1>\n    <a href=\"../..\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>The <a href=\"../..\">Herbie</a> developers are excited to announce\n  Herbie 2.2! This release focuses extensible compilation targets\n  using <i>platforms</i>.</p>\n\n  <p><b>What is Herbie?</b> Herbie compiles mathematical expressions\n  to fast and accurate floating point programs, avoiding the bugs,\n  errors, and surprises of floating point arithmetic.\n  Visit <a href=\"../..\">the main page</a> to learn more.</p>\n  \n  <!--<img src=\"team.png\" id=\"team\" alt=\"The Herbie 2.2 team at UW and U of U\" />-->\n\n  <h2>Releasing the Platforms API</h2>\n\n  <figure class=\"showcase\">\n    <pre>(define-operation (cosd [x &lt;binary64&gt;]) &lt;binary64&gt;\n          #:spec (cos (* x (/ (PI) 180)))\n          #:impl (from-rival)\n          #:cost 12.5)</pre>\n\n    <figcaption>\n      Herbie 2.2's <a href=\"platforms.html\">platforms</a> allow you to\n      define custom compilation targets, including novel hardware\n      (CPUs, GPUs, FPGAs, TPUs), programming languages (Julia, Matlab,\n      Fortran), or software libraries (Numpy, Eigen, cuBLAS).\n      Platforms can define new number formats, new floating-point\n      operations on those formats, and new cost models for those\n      operations. Herbie will automatically optimize its results for\n      your platform.\n    </figcaption>\n  </figure>\n\n  <p>\n  Last year, <a href=\"../2.1/release-notes.html\">Herbie 2.1</a>\n  included the beginnings of <i>platforms</i>, Herbie's API for\n  multiple backends. We've simplified and improved this API, and are\n  now ready to release it.</p>\n  \n  <p>In short, platforms allow you define the functions Herbie is\n  allowed to use when compiling floating-point programs. A platform\n  can expose Python's <code>fsum</code>, Julia's <code>cosd</code>, or\n  AVX's <code>rcpps</code> to Herbie, which can then use those\n  functions to produce even faster and more accurate output.\n  Our <a href=\"../papers.html\">recent publications</a> demonstrate\n  dramatic accuracy and performance improvements using platforms.</p>\n\n  <p>Platforms are a large change, and we invite users to try it out.\n  The <a href=\"platforms.html\">platforms documentation</a> explains\n  how to select different built-in platforms, or even how to write\n  your own.</p>\n  \n  <p>Besides the new feature, platforms allow us to deprecate a\n  variety of now-superseded features:</p>\n\n  <ul>\n    <li>The default platform now uses a realistic, auto-tuned cost\n    model which should lead to faster code in practice.</li>\n\n    <li>The Herbie 2.0 and 2.1 cost models are replaced by\n    the <code>herbie20</code> platform.</li>\n\n    <li>The <code>--no-pareto</code> flag is replaced by\n    the <code>herbie10</code> platform.</li>\n\n    <li>Plugins are now replaced by ordinary Racket libraries imported\n    directly by plugins.</li>\n    \n    <li>Preprocessing is now replaced by standard platform-provided\n    functions such\n    as <code>fmin</code>, <code>fmax</code>, <code>fabs</code>,\n    and <code>copysign</code>.</li>\n  </ul>\n\n  <h2>Restructuring the Main Loop</h2>\n  \n  <figure class=\"showcase\">\n    <img src=\"system-2.2.png\"\n         alt=\"The new Herbie main loop.\n              The simplify step and patch table have been removed,\n              while the compute phase has been added.\">\n    <figcaption>\n      The Herbie main loop is dramatically simplified, with no\n      separate simplify or localize phase and a new compute phase that\n      aid with hard-to-compute constants.\n    </figcaption>\n  </figure>\n\n  <p>We've overhauled the Herbie main loop, which is the high-level\n  algorithm that invokes different Herbie sub-systems to generate and\n  filter different candidate programs. This overhaul both introduces\n  new systems, which should make Herbie more capable, and reduce\n  duplicative work, dramatically speeding up Herbie. Specifically:</p>\n\n  <ul>\n    <li>A new compute phase was added, which replaces variable-free\n      subexpressions with constants. The constants are computed using\n      high-precision arithmetic and are guaranteed to be exact.</li>\n    <li>The simplification phase was removed. This phase mostly\n      duplicated work already done by the rewrite phase, so removing it\n      had very little impact on performance and accuracy of generated\n      code, but reduced Herbie runtime significantly.</li>\n    <li>The localize phase was also removed. This phase existed to\n      reduce duplicate work in other phases; batches deduplicate the\n      work automatically so localize is no longer needed. Removing this\n      phase also significantly sped up Herbie.</li>\n    <li>Minor phases like initial and final simplify were removed as\n      well. Most importantly, this allowed replacing the existing,\n      complex \"accelerator\" API (never fully released) and replace it\n      with the much simpler \"platform\" API.</li>\n    <li>Herbie more correctly tracks Taylor approximations inside\n      Herbie, and will now avoid making \"approximations to\n      approximations\" leading to runaway error in rare cases.</li>\n  </ul>\n      \n\n  <h2>Flattening Expressions to Batches</h2>\n\n  <figure class=\"showcase side-by-side\">\n    <pre>%0 = x\n%1 = (literal 1)\n%2 = (+ %0 %1)\n%3 = (* %2 %2)\n%4 = (- %3 %1)\n%5 = (neg %2)\n%6 = (* %5 %5)\n%7 = (- %6 %1))</pre>\n    <figcaption>\n      An example of a batch, containing two expressions (and their\n      subexpressions): <code>(x + 1)<sup>2</sup> - 1</code>\n      and <code>(-(x + 1))<sup>2</sup> - 1</code>. Shared\n      subexpressions are only represented once in the batch, and are\n      only processed once by Herbie.\n    </figcaption>\n  </figure>\n\n  <p>We have also changed Herbie's main data structure for\n  representing programs. Until now, Herbie represented programs via\n  their abstract syntax tree. While simple and effective, this\n  representation lead to processing identical subexpressions\n  repeatedly. This was especially problematic for larger programs,\n  which can sometimes have the same subexpression appear exponentially\n  many times.</p>\n\n  <p>The batch data structure instead uses a flat array with\n  back-references to represent programs, which means that duplicate\n  subexpressions appear and are processed just once. This lead to\n  significant speedups throughout Herbie:</p>\n\n  <ul>\n    <li>Batches automatically deduplicates identical candidate\n      programs, which occur when multiple Herbie phases produce the\n      same output. There were a lot more of these than we thought; in\n      some cases as much as 25&times; deduplication occurs.</li>\n    <li>The series phase, now uses batches internally, allowing Herbie\n      to consider many more series expansions.</li>\n    <li>Herbie's FFI layer for interacting with\n      the <a href=\"https://egraphs-good.github.io/\">egg</a> library now\n      leverages batches to reduce time spent copying data in and out of\n      egg.</li>\n    <li> In some cases, one batch is shared across multiple phases\n      (like evaluation and pruning), reducing duplication even\n      further.</li>\n    <li>The derivations phase was dramatically sped up by caching\n      proof objects across multiple candidate programs. Additionally,\n      a debugging pass called \"soundiness\" was removed entirely, since\n      the problems it was built to debug no longer occur. Thanks to\n      both changes, derivations take almost no time at all any\n      more.</li>\n  </ul>\n\n  <h2>Sister Projects</h2>\n  \n  <p>\n    The <a href=\"https://github.com/herbie-fp/odyssey\">Odyssey\n      numerics workbench</a> is releasing version 1.2 today, featuring\n      a new \"local error\" component and various design tweaks and\n      improvements. Odyssey can be tried from\n      its <a href=\"https://herbie-fp.github.io/odyssey/\">online\n      demo</a> or installed locally from\n      the <a href=\"https://marketplace.visualstudio.com/items?itemName=herbie-fp.odyssey-fp\">VS\n      Code Marketplace</a>.\n  </p>\n  \n  <p>\n    The <a href=\"https://github.com/herbie-fp/rival\">Rival\n    real-arithmetic package</a> is releasing version 2.2 today,\n    including various tweaks, optimizations, and improvements. Most\n    significantly, a new \"hints\" feature significantly speeds up\n    sampling expressions that\n    use <code>fmin</code>, <code>fmax</code>, and <code>if</code>.\n  </p>\n\n  <h2>Other improvements</h2>\n\n  <ul>\n    <li>Herbie now offers a basic <a href=\"api-endpoints.html\">HTTP\n        API</a>, including both synchronous and asynchronous jobs and\n      access to various internal Herbie features. This HTTP API is a\n      work in progress and is primarily built to support Odyssey.\n      However, our work on the API has also enabled the\n      standard <a href=\"using-web.html\">Herbie web interface</a> to\n      support <a href=\"options.html\">threads</a>, which should make\n      Herbie faster in a lot of common use cases.</li>\n    <li>Small quality-of-life changes have been made to the Herbie\n      reports, including hiding duplicate alternatives, updating\n      various dependencies, and generating the reports more\n      quickly.</li>\n    <li>Optional, off-by-default support for\n      the <a href=\"https://github.com/egraphs-good/egglog\">egglog</a>\n      rewriting engine has been added. We are excited about growth and\n      competition among rewrite engines and hope to continue driving\n      forward this research area.</li>\n    <li>Fixing a variety of small bugs, such as nondeterminism due to\n      an incorrect type signature for <code>fma</code> and new rewrite\n      rules to unlock more accurate results.</li>\n    <li>Many general-purpose cleanups, including removing a lot of\n      now-unnecessary nightly infrastructure, adoption of a new\n      formatting guideline, reorganization of the source code, and new\n      debug infrastructure.</li>\n  </ul>\n\n  <h2>Try it out!</h2>\n\n  <p>\n    We want Herbie to be more useful to scientists, engineers, and\n    programmers around the world. We've got a lot of features we're\n    excited to work on in the coming months. Please\n    <a href=\"https://github.com/herbie-fp/herbie/issues\">report bugs</a>\n    or <a href=\"https://github.com/herbie-fp/herbie\">contribute</a>.\n  </p>\n  <br>\n  <p style=\"font-weight: bold; text-align: center;\">If you find Herbie\n  useful, <a href=\"mailto:herbie@cs.washington.edu\">let us know!</p>\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.2/report.html",
    "content": "<!doctype html>\n<html>\n\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie reports</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n\n<body>\n  <header>\n    <h1>Herbie reports</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>When used <a href=\"using-web.html\">in the browser</a>, Herbie\n    generates HTML reports full of information about the accuracy and relative \n    speed of the initial and alternative expressions.</p>\n\n  <h2 id=\"links\">Summary and Additional links</h2>\n\n  <p>The top of the report page has a right-hand menu bar with\n    additional links. “Metrics” give you detailed internal information\n    about Herbie, while “Report”, if present, takes you back to the\n    full Herbie report.</p>\n\n  <p>Below the menu lies a brief summary of the results. Herbie can\n    produce multiple alternatives to the initial program, and this\n    summary gives their basic statistics.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-large.png\" />\n    <figcaption>Summary numbers from a Herbie report.</figcaption>\n  </figure>\n\n  <dl>\n    <dt>Percentage Accurate</dt>\n    <dd>The <a href=\"errors.html\">percentage accuracy</a> of the\n    initial program and what Herbie thinks is its most accurate\n    alternative.</dd>\n    <dt>Time</dt>\n    <dd>The time it took Herbie to generate all of the alternatives.</dd>\n    <dt>Alternatives</dt>\n    <dd>The number of alternatives found.</dd>\n    <dt>Speedup</dt>\n    <dd>The speed, relative to the initial program,\n    of the fastest alternative that improves accuracy.</dd>\n  </dl>\n\n  <h2 id=\"spec\">Specification</h2>\n\n  <p>Next, the specification that you gave to Herbie. This section is\n    closed by default. Typically, the specification is also the\n    initial program, but in some cases, like if\n    the <a href=\"input.html\"><kbd>:spec</kbd> property</a> is used,\n    they can differ. The specification also includes\n    any <a href=\"input.html#preconditions\">preconditions</a> given to\n    Herbie.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"specification.png\" />\n  </figure>\n\n  <p>You can use the drop-down in the top left to display the\n  specification in an alternative syntax.</p>\n\n  <!-- Colors copied from src/web/resources/report.css -->\n  <h2 id=\"graph\">Local Percentage Accuracy graph</h2>\n\n  <p>\n    Next, the <em>Local Percentage Accuracy</em> graph compares the\n    accuracy of the initial program to Herbie's most accurate\n    alternative. This is helpful for understanding the sorts of inputs\n    Herbie is improving accuracy on. Sometimes, Herbie improved\n    accuracy on some inputs at the cost of accuracy on other inputs\n    that you care more about. You can add a\n    <a href=\"input.html#preconditions\">precondition</a> to restrict Herbie to \n    the more important inputs in that case.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-accuracy.png\" />\n  </figure>\n\n  <p>In the plot, each individual sampled point is shown with a faint\n    circle, and the thick line is moving average of those individual\n    samples. The red line is the initial program and the blue line is\n    Herbie's most accurate alternative.</p>\n  \n  <p>Accuracy is shown on the vertical axis, and higher is better. The\n    horizontal axis shows one of the variables in the input program;\n    the dropdown in the title switches between input variables. The\n    checkboxes below the graph toggle the red and blue lines on and\n    off.</p>\n\n  <p>If Herbie decided to insert an <code>if</code> statement into the\n    program, the locations of those <code>if</code> statements will be\n    marked with vertical bars.</p>\n\n  <h2 id=\"cost-accuracy\">Accuracy vs Speed</h2>\n  <p>Next, a Pareto graph and table list the alternatives Herbie\n    found.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-cost-accuracy.png\" />\n  </figure>\n\n  <p>Both the plot and the table show the same data. In the plot,\n  accuracy is on the vertical axis and speedup is on the horizontal\n  axis. Up and to the right is better. The initial program is shown\n  with a red square, while each of Herbie's alternatives is shown with\n  a blue circle. A faint line shows the Pareto frontier&mdash;that is,\n  it goes through all Herbie alternatives that maximize speed for\n  their level of accuracy. Some of Herbie's alternatives may not be on\n  the Pareto frontier due to differences between the training and test\n  set.</p>\n\n  <p>In the table, each alternative is shown along with its accuracy\n  and speed relative to the initial program. Values are green if they\n  are better than the initial program, and black otherwise. Each\n  alternative is linked to its description lower on the page.</p>\n\n  <h2 id=\"alternatives\">Initial program and Alternatives</h2>\n\n  <p>Below the table come a series of boxes detailing the initial\n    program and each of Herbie's alternatives, along with their\n    accuracy and relative speed.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-alternative.png\" />\n  </figure>\n\n  <p>The accuracy and relative speed of each alternative is given in\n    the title. Below the title, the alternative expression itself is\n    given. The dropdown in the top right can be used to change the\n    syntax used. If Herbie could not come up with anything better than\n    the initial program, no alternatives are displayed.</p>\n\n  <p>Each alternative also has a derivation, which can be shown by\n    clicking on \"Derivation\". The derivation shows each step Herbie\n    took to transform the initial program into this alternative. The\n    initial program has no derivation.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-alternative-derivation.png\" />\n  </figure>\n\n  <p>Each step in the derivation gives the accuracy after that step.\n    Sometimes you can use that to pick a less-complex and\n    not-substantially-less-accurate program. The derivation will also\n    call out any case splits. When a part of the step is colored blue,\n    that identifies the changed part of the expression.</p>\n\n  <p>Derivations may also contain \"step-by-step derivations\"; you can\n  click on those step-by-step derivations to expand them. Each step in\n  the step-by-step derivation names an arithmetic law from Herbie's\n  database, with <kbd>metadata-eval</kbd> meaning that Herbie used\n  direct computation in a particular step.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-step-by-step.png\" />\n  </figure>\n\n  <p>Derivations are intended to give you more confidence in Herbie's\n  results and are not guaranteed to be an accurate reflection of\n  Herbie's internal process of constructing an alternative.</p>\n\n  <h2 id=\"reproduction\">Reproduction</h2>\n\n  <p>Finally, Herbie gives a command you can run to reproduce its\n    result. If you find a Herbie bug, include this code snippet when\n    <a href=\"https://github.com/uwplse/herbie/issues\">filing an issue</a>.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-reproduce.png\" />\n  </figure>\n\n  <p>We expect the report to grow more informative with future\n    versions. Please <a href=\"mailto:herbie@cs.washington.edu\">get in\n      touch</a> if there is more information you'd like to see.</p>\n\n</body>\n\n</html>\n"
  },
  {
    "path": "www/doc/2.2/toc.js",
    "content": "function make_toc() {\n    var headings = document.querySelectorAll(\"h2\");\n    var toc = document.createElement(\"nav\");\n    toc.classList.add(\"toc\")\n    var list = document.createElement(\"ul\");\n    for (var i = 0; i < headings.length; i++) {\n        var li = document.createElement(\"li\");\n        var a = document.createElement(\"a\");\n        var h = headings[i];\n        if (! h.id) {\n            h.setAttribute(\"id\", \"heading-\" + i);\n        }\n        a.setAttribute(\"href\", \"#\" + h.id);\n        a.innerHTML = h.innerHTML;\n        li.appendChild(a);\n        list.appendChild(li);\n    }\n    toc.appendChild(list);\n    headings[0].parentNode.insertBefore(toc, headings[0]);\n}\n\nwindow.addEventListener(\"load\", make_toc);\n"
  },
  {
    "path": "www/doc/2.2/tutorial.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Tutorial</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Herbie Tutorial</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> rewrites floating point expressions to\n      make them more accurate. Floating point arithmetic is\n      <a href=\"error.html\">inaccurate</a>; even 0.1 + 0.2 ≠ 0.3 in\n      floating-point. Herbie helps find and fix these mysterious\n      inaccuracies.\n  </p>\n\n  <p>\n    To get started, <a href=\"installing.html\">download and install</a>\n    Herbie. You're then ready to begin using it.\n  </p>\n\n  <h2>Giving Herbie expressions</h2>\n\n  <p>Start Herbie with:</p>\n\n  <pre class=\"shell\">racket -l herbie web</pre>\n  \n  <p>Alternatively, if you added <code>herbie</code> to the path, you\n  can always replace <code>racket -l herbie</code> with\n  just <code>herbie</code>.</p>\n\n  <p>\n    After a brief wait, your web browser should open and show you\n    Herbie's main window. The most important part of the page is this\n    bit:\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"web-input.png\" alt=\"The program input field in the Herbie web UI.\"/>\n  </figure>\n\n  <p>\n    Let's start by just looking at an example of Herbie running.\n    Click \"Show an example\". This will pre-fill the expression\n    <kbd>sqrt(x + 1) - sqrt(x)</kbd>\n    with <code>x</code> ranging from to <kbd>0</kbd> and <kbd>1.79e308</kbd>.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"range-input.png\" alt=\"The input range field in the Herbie web UI.\"/>\n  </figure>\n\n  <p>\n    Now that you have an expression and a range for each variable,\n    click the \"Improve with Herbie\" button. You should see the entry\n    box gray out, and shortly thereafter some text should appear\n    describing what Herbie is doing. After a few seconds, you'll be\n    redirected to a page with Herbie's results.\n  </p>\n\n  <p>\n    The very top of this results page gives some quick statistics\n    about the alternative ways Herbie found for evaluating this\n    expression:\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-large.png\" alt=\"Statistics and error measures for this Herbie run.\" />\n  </figure>\n\n  <p>\n    Here, you can see that Herbie's most accurate alternative has an\n    accuracy of 99.7%, much better than the initial program's 53.2%,\n    and that in total Herbie found 5 alternatives. One of those\n    alternatives is both more accurate than the original expression\n    and also 1.9&times; faster. The <a href=\"report.html\">rest of the\n    result page</a> shows each of these alternatives, including\n    details like how they were derived. These details are all\n    <a href=\"report.html\">documented</a>, but for the sake of the\n    tutorial let's move on to a more realistic example.\n  </p>\n\n  <h2>Programming with Herbie</h2>\n\n  <p>\n    You can use Herbie on expressions from source code, mathematical\n    models, or debugging tools. But most users use Herbie as they\n    write code, asking it about any complex floating-point expression\n    they write. Herbie has <a href=\"options.html\">options</a> to log\n    all the expressions you enter so that you can refer to them later.\n  </p>\n\n  <p>But to keep the tutorial focused, let's suppose you're instead\n    tracking down a floating-point bug in existing code. Then you'll\n    need to start by identifying the problematic floating-point\n    expression.</p>\n\n  <p>To demonstrate the workflow, let's walk through\n    <a href=\"https://github.com/josdejong/mathjs/pull/208\">bug 208</a>\n    in <a href=\"http://mathjs.org\">math.js</a>, a math library for\n    JavaScript. The bug deals with inaccurate square roots for complex\n    numbers. (For a full write-up of the bug itself, check out\n    a <a href=\"https://pavpanchekha.com/blog/casio-mathjs.html\">blog\n    post</a> by one of the Herbie authors.)\n  </p>\n\n  <h2>Finding the problematic expression</h2>\n\n  <p>\n    In most programs, there's a small kernel that does the mathematical\n    computations, while the rest of the program sets up parameters,\n    handles control flow, visualizes or prints results, and so on. The\n    mathematical core is what Herbie will be interested in.\n  </p>\n\n  <p>\n    For our example, let's start\n    in <a href=\"https://github.com/josdejong/mathjs/tree/master/lib/function\"><code>lib/function/</code></a>.\n    This directory contains many subdirectories; each file in each\n    subdirectory defines a collection of mathematical functions. We're\n    interested in the complex square root function, which is defined in\n    <a href=\"https://github.com/josdejong/mathjs/blob/da306e26ed34272db44e35f07a3b015c0155d99a/lib/function/arithmetic/sqrt.js\"><code>arithmetic/sqrt.js</code></a>.\n  </p>\n\n  <p>\n    This file handles argument checks, different types, and error\n    handling, for both real and complex square roots. None of that is\n    of interest to Herbie; we want to extract just the mathematical\n    core. So skip down to the <code>isComplex(x)</code> case:\n  </p>\n\n  <pre>var r = Math.sqrt(x.re * x.re + x.im * x.im);\nif (x.im &gt;= 0) {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}\nelse {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      -0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}</pre>\n\n  <p>This is the mathematical core that we want to send to Herbie.</p>\n\n  <h2>Converting problematic code to Herbie input</h2>\n\n  <p>\n    In this code, <code>x</code> is of type <code>Complex</code>, a\n    data structure with multiple fields. Herbie only deals with\n    floating-point numbers, not data structures, so we will treat the\n    input <code>x</code> as two separate inputs to\n    Herbie: <code>xre</code> and <code>xim</code>. We'll also pass\n    each field of the output to Herbie separately.\n  </p>\n\n  <p>\n    This code also branches between non-negative <code>x.im</code> and\n    negative <code>x.im</code>. It's usually better to send each\n    branch to Herbie separately. So in total, this code turns into four\n    Herbie inputs: two output fields, for each of the two branches.\n  </p>\n\n  <p>Let's focus on the first field of the output for the case of\n  non-negative <code>x.im</code>.</p>\n\n  <p>The variable <code>r</code> is an intermediate variable in this\n  code block. Intermediate variables provide Herbie with crucial\n  information that Herbie can use to improve accuracy, so you want to\n  expand or inline them. The result looks like this:</p>\n\n  <pre>0.5 * sqrt(2.0 * (sqrt(xre * xre + xim * xim) + xre))</pre>\n\n  <p>Recall that this code is only run when <code>x.im</code> is\n  non-negative (but it runs for all values of <code>x.re</code>). So, \n  select the full range of values for <code>x.re</code>, but restrict\n  the range of <code>x.im</code>, like this: \n  \n  <figure>\n    <img width=\"100%\" src=\"range-input-2.png\" alt=\"Restricting the input range to xim >= 0.\" />\n  </figure>\n  \n  This asks Herbie to consider only non-negative values\n  of <code>xim</code> when improving the accuracy of this expression.\n  The number <code>1.79e308</code> is approximately the largest\n  double-precision number, and will auto-complete.</p>\n  \n  <h2>Herbie's results</h2>\n\n  <p>Herbie will churn for a few seconds and produce a results page.\n    In this case, Herbie found 4 alternatives, and we're interested in\n    the most accurate one, which should have an\n    <a href=\"error.html\">accuracy of 84.6%:</a></p>\n\n  <figure>\n    <img width=\"100%\" src=\"problematic-highlight.png\" />\n  </figure>\n\n  <p>Below these summary statistics, we can see a graph of accuracy\n  versus input value. By default, it shows accuracy\n  versus <code>xim</code>; higher is better:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"problematic-xim.png\" />\n  </figure>\n\n  <p>The drop in accuracy once <code>xim</code> is bigger than\n  about <code>1e150</code> really stands out, but you can also see\n  that Herbie's alternative more accurate for smaller <code>xim</code>\n  values, too. You can also change the graph to plot accuracy\n  versus <code>xre</code> instead:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"problematic-xre.png\" />\n  </figure>\n\n  <p>This plot makes it clear that Herbie's alternative is almost\n  perfectly accurate for positive <code>xre</code>, but still has some\n  error for negative <code>xre</code>.\n\n  <p>Herbie also found other alternatives, which are less accurate but\n  might be faster. You can see a summary in this table:</p>\n\n  <figure>\n    <figcaption></figcaption>\n    <img width=\"100%\" src=\"problematic-pareto-table.png\" />\n  </figure>\n\n  <p>Herbie's algorithm is randomized, so you likely won't see the\n  exact same thing; you might see more or fewer alternatives, and they\n  might be more or less accurate and fast. That said, the most\n  accurate alternative should be pretty similar.</p>\n\n  <p>That alternative itself is shown lower down on the page:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"problematic-improved-accuracy.png\" />\n  </figure>\n\n  <p>A couple features of this alternative stand out immediately.\n  First of all, Herbie inserted an <code>if</code> statement.\n  This <code>if</code> statement handles a phenomenon known as\n  cancellation, and is part of why Herbie's alternative is more\n  accurate. Herbie also replaced the square root operation with\n  the <code>hypot</code> function, which computes distances more\n  accurately than a direct square root operation.</p>\n\n  <p>If you want to see more about how Herbie derived this result, you\n  could click on the word \"Derivation\" to see a detailed, step-by-step\n  explanation of how Herbie did it. For now, though, let's move on to\n  look at another alternative.</p>\n  \n  <p>The fifth alternative suggested by Herbie is much less accurate,\n  but it is about twice as fast as the original program:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"problematic-improved-speed.png\" />\n  </figure>\n  \n  <p>This alternative is kind of strange: it has two branches, and\n  each one only uses one of the two variables <code>xre</code>\n  and <code>xim</code>. That explains why it's fast, but it's still\n  more accurate than the initial program because it avoids\n  cancellation and overflow issues that plagued the original.</p>\n  \n  <h2>Using Herbie's alternatives</h2>\n  \n  <p>In this case, we were interested in the most accurate possible\n  implementation, so let's try to use Herbie's most accurate\n  alternative.</p>\n\n  <pre>\n// Herbie 2.1 for:\n//   0.5 * sqrt(2.0 * (sqrt(xre*xre + xim*xim) + xre))\nvar r = Math.hypot(x.re, x.im);\nvar re;\nif (xre + r <= 0) {\n    re = 0.5 * Math.sqrt(2 * (x.im / (x.re / x.im) * -0.5));\n} else {\n    re = 0.5 * Math.sqrt(2 * (x.re + r));\n}\nif (x.im &gt;= 0) {\n  return new Complex(\n      re,\n      0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}\nelse {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      -0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}</pre>\n\n  <p>Note that I&apos;ve left the Herbie query in a comment. As Herbie\n  gets better, you can re-run it on this original expression to see if\n  it comes up with improvements in accuracy.</p>\n\n  <p>By the way, for some languages, including JavaScript, you can use\n  the drop-down in the top-right corner of the alternative block to\n  translate Herbie&apos;s output to that language. However, you will\n  still probably need to refactor and modify the results to fit your\n  code structure, just like here.</p>\n\n  <h2>Next steps</h2>\n\n  <p>With this change, we&apos;ve made this part of the complex square\n  root function much more accurate, and we could repeat the same steps\n  for the other branches and other fields in this program. You now\n  have a pretty good understanding of Herbie and how to use it.\n  Please <a href=\"mailto:herbie@cs.washington.edu\">let us know</a> if\n  Herbie has helped you, and check out\n  the <a href=\"../../doc.html\">documentation</a> to learn more about\n  Herbie&apos;s various options and outputs.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.2/using-cli.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie from the Command Line</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Shell and Batch Mode</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>Herbie can be used from the command-line or\n  from <a href=\"using-web.html\">the browser</a>. This page covers\n  using Herbie from the command line.</p>\n\n  <h2 id=\"interactive\">The Herbie shell</h2>\n\n  <p>The Herbie shell lets you interact with Herbie: you type in input\n  expressions and Herbie prints their more accurate versions. Run the\n  Herbie shell with this command:</p>\n\n  <pre class=\"shell\">racket -l herbie shell\nStarting Herbie 2.2 with seed 2098242187\nFind help on https://herbie.uwplse.org/, exit with Ctrl-D\n<strong>herbie&gt;</strong> </pre>\n\n\n  <p>Herbie prints a seed, which you can <a href=\"options.html\">use to\n  reproduce</a> a Herbie run, and links you to documentation. Then, it\n  waits for inputs, which you can type directly into your terminal\n  in <a href=\"input.html\">FPCore format</a>:</p>\n\n  <pre><strong>herbie&gt;</strong> (FPCore (x) (- (+ 1 x) x))\n(FPCore (x)\n  <var>...</var>\n  1.0)</pre>\n\n  <p>Herbie suggests that <code>1.0</code> is more accurate than the\n  original expression <code>(- (+ 1 x) x)</code>. The\n  the <var>...</var> elides\n  <a href=\"input.html#properties\">additional information</a> provided\n  by Herbie.</p>\n\n  <p>The Herbie shell only shows Herbie's most accurate variant.</p>\n\n  <h2 id=\"batch\">Batch processing FPCores</h2>\n\n  <p>Alternatively, you can run Herbie on a file with multiple\n  expressions in it, writing Herbie's versions of each to a file. This\n  mode is intended for use by scripts.</p>\n\n  <pre class=\"shell\">racket -l herbie improve bench/tutorial.fpcore out.fpcore\nStarting Herbie 2.2 with seed 1139794558...\nWarning: 75.2% of points produce a very large (infinite) output. You may want to add a precondition.\nSee &lt;<a href=\"https://herbie.uwplse.org/doc/2.0/faq.html#inf-points\">https://herbie.uwplse.org/doc/2.0/faq.html#inf-points</a>&gt; for more.</pre>\n\n  <p>The output file <code>out.fpcore</code> contains more accurate\n  versions of each program:</p>\n\n  <pre>;; seed: 1139794558\n\n(FPCore (x)\n  :name \"Cancel like terms\"\n  <var>...</var>\n  1.0)\n\n(FPCore (x)\n  :name \"Expanding a square\"\n  <var>...</var>\n  (fma x x (+ x x)))\n\n(FPCore (x y z)\n  :name \"Commute and associate\"\n  <var>...</var>\n  0.0)</pre>\n\n  <p>\n    Note that output file is in the same order as the input file. For\n    more control over Herbie, see the documentation of\n    Herbie's <a href=\"options.html\">command-line options</a>.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.2/using-web.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie from the Browser</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>The Browser UI</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p><a href=\"../../\">Herbie</a> rewrites floating point expressions\n  to make them more accurate. Herbie can be used\n  from <a href=\"using-cli.html\">the command-line</a> or from the\n  browser; this page is about using Herbie from the browser.</p>\n\n\n  <h2 id=\"interactive\">The Herbie web shell</h2>\n\n  <p>The Herbie web shell lets you interact with Herbie through your\n  browser, featuring a convenient input format. The web shell is the\n  friendliest and easiest way to use Herbie.</p>\n\n  <p>Start the Herbie web shell by running:</p>\n\n  <pre class=\"shell\">racket -l herbie web</pre>\n\n  <p>After a few seconds, the web shell will start up and direct your\n  browser to Herbie:</p>\n  \n  <pre class=\"shell\">racket -l herbie web\nStarting Herbie 2.2 with seed 1003430182\nYour Web application is running at http://localhost:8000/.\nStop this program at any time to terminate the Web Server.</pre>\n\n  <figure>\n    <img width=\"100%\" src=\"web-main.png\" alt=\"A screenshot of the Herbie web shell main page.\"/>\n  </figure>\n\n  <p>You can type an input expressions in\n  <a href=\"input.html\">standard mathematical syntax</a>. After typing\n  in an expression, you will be asked to specify the range of values\n  for each input variable. Once you're done, hit the \"Improve with\n  Herbie\" button to run Herbie.</p>\n  \n  <p>The web shell reports Herbie's progress and redirects to a\n  <a href=\"report.html\">report</a> once Herbie is done.</p>\n\n  <p>The web shell can also automatically save the generated reports,\n  and has <a href=\"options.html\">many other options</a> you might want\n  to explore.</p>\n\n\n  <h2 id=\"batch\">Batch report generation</h2>\n\n  <p>A <a href=\"report.html\">report</a> can also be generated directly\n  from an input file in <a href=\"input.html\">FPCore format</a>:</p>\n  \n  <pre class=\"shell\">racket -l herbie report bench/tutorial.fpcore output/ \nStarting Herbie 2.2 with seed 770126425...\nWarning: 25.0% of points produce a very large (infinite) output. You may want to add a precondition.\nSee &lt;<a href=\"faq.html#inf-points\">https://herbie.uwplse.org/doc/latest/faq.html#inf-points</a>&gt; for more.\n  1/3\t[   0.8s]   55% → 100%\tExpanding a square\n  2/3\t[   0.8s]  100% → 100%\tCommute and associate\n  3/3\t[   0.9s]   53% → 100%\tCancel like terms</pre>\n\n  <p>This command generates a report from the input expressions\n  in <code>bench/tutorial.fpcore</code> and saves the report in the\n  directory <code>output/</code>. It's best if that directory doesn't\n  exist before running this command, because otherwise Herbie may\n  overwrite files in that directory.</p>\n\n  <p>Occasionally Herbie will emit warnings, just like in the example\n  above. All of Herbie's warnings\n  are <a href=\"faq.html\">documented</a>, with explanations and\n  suggested fixes.</p>\n\n  <p>The report Herbie generates is in HTML format so you'll need to\n  start a web server. If you have Python installed, that's\n  particularly convenient:</p>\n\n  <pre class=\"shell\">python3 -m http.server -d output</pre>\n\n  <p>Then go to <a href=\"http://localhost:8000/\">localhost:8000</a> in\n  your favorite browser. The report summarizes Herbie's results for\n  all expression in your input file, and you can click on individual\n  expressions to see Herbie's output for them.</p>\n\n  <p>Batch report generation is the best way to run Herbie on a large\n  collection of inputs. Like the web shell, it can be customized\n  through <a href=\"options.html\">command-line options</a>, including\n  parallelizing Herbie with multiple threads.</p>\n\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.3/api-endpoints.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Herbie HTTP API Endpoints</title>\n    <link rel='stylesheet' type='text/css' href='../../main.css'>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <script type=\"text/javascript\" src=\"toc.js\"></script>\n  </head>\n  <body>\n    <header>\n      <h1>HTTP API</h1>\n      <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n      <nav>\n        <ul>\n          <li><a href=\"../../demo/\">Try</a></li>\n          <li><a href=\"installing.html\">Install</a></li>\n          <li><a href=\"tutorial.html\">Learn</a></li>\n        </ul>\n      </nav>\n    </header>\n\n    <p>The <a href=\"../../\">Herbie</a> API allows applications to\n    interface with Herbie using HTTP requests. The API is designed to\n    be stateless: the order in which endpoints are called shouldn't\n    matter.</p>\n\n    <h2 id=\"all-endpoints-info\">Format for all endpoints</h2>\n\n    <p>All the endpoints listed below respond to POST requests unless\n    otherwise specified. A typical example of sending a POST request\n    to a running Herbie server is:</p>\n\n    <pre class=\"shell\">curl -d \\\n  '{\"formula\": \"(FPCore (x) (- (sqrt (+ x 1))))\", \"seed\": 5}' \\\n  -H 'Content-Type: application/json' \\\n  http://127.0.0.1:8000/api/sample\n    </pre>\n\n    <h2 id=\"sample\">/api/sample</h2>\n\n    <details>\n    <summary>Example input &amp; output</summary>\n\n    <p>Request:</p>\n\n    <pre>{\n    formula: &lt;FPCore expression&gt;,\n    seed: &lt;random seed for point generation&gt;\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n    points: [[point, exact], ... ]\n}</pre>\n    </details>\n\n    <p>The <code>sample</code> endpoint allows the user to request a\n    sample of points given the FPCore expression and a seed.</p>\n\n    <p>Returns a collection of points and the exact evaluation of each\n    point with the given spec. The results are returned through the\n    \"points\" field and are represented by an array of point-exact\n    pairs with the first value representing the point and the second\n    value representing the exact evaluation; the exact value of\n    point <code>n</code> is <code>points[n][1]</code>.</p>\n\n    <p>Herbie calculates the \"ground truth\" by calculating the values\n    with more precise numbers. This can be slow.</p>\n\n    <h2 id=\"exacts\">/api/exacts</h2>\n\n    <details>\n    <summary>Example input & output</summary>\n\n    <p>Request:</p>\n\n    <pre>{\n    formula: &lt;FPCore expression&gt;,\n    sample: [point, ... ]\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n    points: [[point, exact], ... ]\n}</pre>\n    </details>\n\n    <p>The <code>exacts</code> endpoint allows the user to request the\n    exact value of a set of points evaluated at a real number\n    specification given as an FPCore expression.</p>\n\n    <p>Some points may not be calculable given the FPCore\n    expression.</p>\n\n    <p>Returns a collection of points and the exact evaluation of each\n    point with the given spec. The results are returned through the\n    \"points\" field and are represented by an array of point-exact\n    pairs with the first value representing the point and the second\n    value representing the exact evaluation; the exact value of\n    point <code>n</code> is <code>points[n][1]</code>.</p>\n\n    <p>Herbie calculates the \"ground truth\" by calculating the values\n    with more precise numbers. This can be slow.</p>\n\n    <h2 id=\"calculate\">/api/calculate</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n\n    <p>Request:</p>\n\n    <pre>{\n    formula: &lt;FPCore expression&gt;,\n    sample: [point ... ]\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n    points: [[point, exact], ... ]\n}</pre>\n    </details>\n\n    <p>The <code>calculate</code> endpoint allows the user to request\n    the evaluation of a set of points evaluated at a floating-point\n    implementation given as an FPCore expression.</p>\n\n    <p>Some points may not be calculable given the FPCore expression.</p>\n\n    <p>Returns a collection of points and the evaluation of each point\n    using the given FPCore as a floating-point implementation. The\n    results are returned through the \"points\" field and are\n    represented by an array of point-exact pairs with the first value\n    representing the point and the second value representing the\n    evaluated value; the evaluated value of point <code>n</code>\n    is <code>points[n][1]</code>.</p>\n\n    <h2 id=\"analyze\">/api/analyze</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n\n    <p>Request:</p>\n\n    <pre>{\n  formula: &lt;FPCore expression&gt;,\n  sample: [[point, exact], ... ]\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n  points: [[point, error], ... ]\n}</pre>\n    </details>\n\n    <p>The <code>analyze</code> endpoint allows the user to request\n    error analysis of a set of point-exact pairs and a given\n    floating-point implementation.</p>\n\n    <p>Given a collection of points, their exact values, and an FPCore\n    expression to analyze on, the <code>analyze</code> endpoint\n    returns the error for each point for that expression. The error\n    value returned is Herbie's internal error heuristic.</p>\n\n    <h2 id=\"alternatives\">/api/alternatives</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n    <p>Request:</p>\n\n    <pre>{\n  formula: &lt;FPCore expression&gt;,\n  sample: [[point, exact], ... ]\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n  alternatives: [alt, ... ],\n  histories: [history, ... ],\n  splitpoints: [splitpoint, ... ]\n}</pre>\n    </details>\n\n    <p>The <code>alternatives</code> endpoint allows the user to\n    request rewrites from Herbie given an expression to rewrite and a\n    set of point-exact pairs.</p>\n\n    <p>Returns a list of alternatives represented by FPCore\n    expressions through the \"alternatives\" field.</p>\n\n    <p>Returns a list of derivations of each alternative through the\n    \"histories\" field where <code>history[n]</code> corresponds\n    to <code>alternatives[n]</code>.</p>\n\n    <p>Returns a list of splitpoints for each alternative through the\n    \"splitpoints\" field where <code>splitpoints[n]</code> corresponds\n    to <code>alternatives[n]</code>. <code>splitpoints[n]</code> will\n    only contain information about the corresponding alternative.s\n    splitpoints if the alternative is a branch-expression.</p>\n\n    <h2 id=\"mathjs\">/api/mathjs</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n    <p>Request:</p>\n\n    <pre>{\n  formula: &lt;FPCore expression&gt;\n}</pre>\n\n    <p>Response:</p>\n\n    <pre>{\n  mathjs: &lt;mathjs expression&gt;\n}</pre>\n    </details>\n\n    <p>The <code>mathjs</code> endpoint allows the user to translate\n    FPCore expressions into mathjs expressions.</p>\n\n\n    <h2 id=\"cost\">/api/cost</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n\n    <p>Request:</p>\n\n  <pre>{\n    formula: &lt;FPCore expression&gt;,\n    sample: [point ... ]\n}</pre>\n\n    <p>Response:</p>\n\n  <pre>{\n    cost: cost\n}</pre>\n\n    <p><b>Specific Example: sqrt(x+1)-sqrt(x)</b></p>\n\n    <p>Request:</p>\n\n  <pre>{\n    formula: &lt;(FPCore (x) (- (sqrt (+ x 1)) (sqrt x)))&gt;,\n    sample: [ [[1], -1.4142135623730951] ]\n}</pre>\n\n    <p>Response:</p>\n\n  <pre>{\n    cost: 13120\n}</pre>\n\n    <p><b>Lower-Cost Example: (x+1)-(x)</b></p>\n\n    <p>Request:</p>\n\n  <pre>{\n    formula: &lt;(FPCore (x) (- (+ x 1 ) x))&gt;,\n    sample: [ [[1], -1.4142135623730951] ]\n}</pre>\n\n    <p>Response:</p>\n\n  <pre>{\n    cost: 320\n}</pre>\n\n    </details>\n\n    <p>The <code>cost</code> endpoint allows the user to request\n    the evaluation of an expression's overall cost. Cost is \n    calculated depending on the complexity of operations contained\n    in the expression. </p>\n\n    <p>Given an FPCore expression and a collection of points,\n    returns the cost of the expression. The cost value returned \n    is calculated internally by Herbie.</p> \n    \n    <p>The points should be of the same format as the points \n    generated in the sample endpoint. Refer to /api/sample \n    for more details. </p>\n\n    <p>Note the sample points are not used in the cost calculation.\n    The contents of the points do not matter as long as they are\n    in the correct format as mentioned above.</p>\n\n    <!-- Translate Endpoint -->\n\n    <h2 id=\"translate\">/api/translate</h2>\n\n    <details>\n    <summary>Example inputs & outputs</summary>\n\n    <p>Request:</p>\n\n  <pre>{\n    formula: &lt;FPCore expression&gt;,\n    language: \"language\"\n}</pre>\n\n    <p>Response:</p>\n\n  <pre>{\n    result: \"translated expression\"\n}</pre>\n\n    <p><b>Specific Example: sqrt(x+1)-sqrt(x)</b></p>\n\n    <p>Request:</p>\n\n  <pre>{\n    formula: &lt;(FPCore (x) (- (sqrt (+ x 1)) (sqrt x)))&gt;,\n    language: \"python\"\n}</pre>\n\n    <p>Response:</p>\n\n  <pre>{\n    result: \"def expr(x): return math.sqrt((x + 1.0)) - math.sqrt(x)\"\n}</pre>\n\n    </details>\n\n    <p>The <code>translate</code> endpoint allows users to translate\n    FPCore expressions into equivalent expressions in various programming\n    languages.</p>\n\n    <p>Given an FPCore expression and a target language, this endpoint\n      returns the translated expression in the specified language.\n      The language parameter should be a string representing the desired\n      programming language. The response includes the translated expression.</p>\n\n    <p>Currently supported languages are: <code>python</code>, <code>c</code>,\n    <code>fortran</code>, <code>java</code>, <code>julia</code>, <code>matlab</code>,\n    <code>wls</code>, <code>tex</code>, and <code>js</code>.</p>\n  <h2>⚠️ Beta endpoints</h2>\n    <p>The endpoints below are currently a work in progress.</p>\n  <h2 id=\"localerror\">/api/localerror</h2>\n    <!--TODO--> Forthcoming.\n  <h2 id=\"timeline\">/api/timeline/{job-id}</h2>\n  <p>Retrieves the <code>timeline</code> data for a given API call. You may find the job id in either the JSON response or in the headers of the HTTP response for of the endpoints in Herbie.</p>\n  <p>The timeline is an exception to the others in that it uses a GET request. Below is a sample of what the request might look like. You may consult the <code>/infra/testApi.mjs</code> file for current examples of how to use this API.</p>\n  <pre class=\"shell\">curl -X GET \\\n  http://127.0.0.1:8000/api/timeline/0b95161a77fc3e29376bbb013d96c2827e2a1cd7\n      </pre>\n  </body>\n</html>\n"
  },
  {
    "path": "www/doc/2.3/diagrams.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Diagrams</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <script src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML\"></script>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Diagrams</h1>\n    <a href=\"../..\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>This page contains systems diagrams for Herbie.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"system-2.2.png\" alt=\"System diagram of Herbie\" />\n    <figcaption>\n    High-level system diagram of Herbie.\n    It highlights Herbie's core architecture,\n      key external libraries (egg and Rival), and user input/output.\n    Basic flow: Herbie passes user input (specification, precondition, etc.)\n      to a <dfn>sampler</dfn> which computes the exact output\n      for uniformly random input points.\n    Herbie uses these exact outputs to compute\n      the <a href=\"error.html\">accuracy</a> of candidate programs.\n    The mainloop (scheduler) then alternates between generate and prune phases,\n      maintaining and improving a set of accurate expressions at each iteration.\n    Once the generate-and-prune loop is complete,\n      Herbie extracts either output expressions using <dfn>regime inference</dfn>,\n      which combines multiple candidate programs using conditionals.\n    The resulting programs are summarized in a report.\n    </figcaption>\n  </figure>\n  \n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.3/docker.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie on Docker</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Installing with Docker</h1>\n    <a href=\"../..\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> is available\n    through <a href=\"https://www.docker.com/\">Docker</a>, which is\n    sort of like a virtual machine. This page describes how to install\n    the <a href=\"https://hub.docker.com/r/uwplse/herbie\">official Docker\n    image</a> for Herbie.\n  </p>\n  \n  <p>\n    We recommend most users <a href=\"installing.html\">install Herbie\n    from package or source</a>. Herbie via Docker is only recommended\n    if you already have Docker experience.\n  </p>\n  \n  <h2>Installing Herbie via Docker</h2>\n\n  <p>\n    First, <a href=\"https://docs.docker.com/installation/\">install\n    Docker</a>. Docker supports Windows, macOS, and Linux. Depending\n    on how you install Docker, you may need to prefix\n    the <code>docker</code> commands with <code>sudo</code> or run them\n    as the administrative user.\n  </p>\n\n  <p>With Docker installed, you can run the <a href=\"using-cli.html\">Herbie shell</a> with:</p>\n\n  <pre>docker run -it uwplse/herbie shell</pre>\n  \n  <p>This will download the Herbie image and then run\n  its <a href=\"options.html\">shell tool</a>.</p>\n\n  <h2>Running the web interface</h2>\n\n  <p>You can run the Herbie web server locally with</p>\n\n  <pre class=\"shell\">docker run -it --rm -p 8000:80 uwplse/herbie</pre>\n\n  <p>and access the server\n  at <a href=\"http://localhost:8000\">http://localhost:8000</a>.</p>\n\n  <p>(Herbie's Docker image binds to the container's port 80 by\n  default; this command uses the <code>-p 8000:80</code> option to\n  expose that container port as the host's port 8000.)</p>\n\n  <p>If you want to pass custom flags to the Herbie web server, make\n  sure to also pass the <code>--public</code>\n  and <code>--port=80</code> flags to enable the Dockerized Herbie to\n  talk to your computer. Make sure to access the server using HTTP,\n  not HTTPS.</p>\n\n  <p>If you are using the <code>--log</code>\n  or <code>--save-session</code> flags for the web shell, you will\n  also need to mount the relevant directories into the Docker\n  container using the <code>-v</code> Docker option, as in the\n  examples below.</p>\n\n  <h2>Generating files and reports</h2>\n\n  <p>To use Herbie in <a href=\"using-cli.html\">batch mode</a>, you\n  will need to mount the input in the Docker container. Do that\n  with:</p>\n  \n  <pre class=\"shell\">docker run -it --rm \\\n    -v <var>in-dir</var>:/in \\\n    -v <var>out-dir</var>:/out \\\n    -u $USER \\\n    uwplse/herbie improve /in/<var>in-file</var> /out/<var>out-file</var></pre>\n\n  <p>In this command, you are asking Herbie to read input\n  from <var>in-file</var> in <var>in-dir</var>, and write output\n  to <var>out-file</var> in <var>out-dir</var>. The command looks the\n  same if you want Herbie to read input from a directory; just\n  leave <var>in-file</var> blank.</p>\n\n  <p>To generate reports from Herbie, you can run:</p>\n\n  <pre class=\"shell\">docker run -it --rm \\\n    -v <var>in-dir</var>:/in \\\n    -v <var>out-dir</var>:/out \\\n    -u $USER \\\n    uwplse/herbie report /in/<var>in-file</var> /out/</pre>\n\n  <p>As before, the input and output directories must be mounted inside\n  the Docker container. Note that both here and above, the user is\n  set to the current user. This is to ensure that the files Herbie creates\n  have the correct permissions set.</p>\n\n  <h2>Loading custom platforms</h2>\n\n  <p>If you'd like to write and use <a href=\"platforms.html\">custom\n  platforms</a> with Herbie in Docker, you'll need to mount the\n  platform directory as well:</p>\n\n  <pre class=\"shell\">docker run -it --rm \\\n    -v <var>platform-dir</var>:/platform \\\n    -u $USER \\\n    uwplse/herbie shell \\\n    --platform /platform/<var>platform.rkt</var></pre>\n\n  <p>You can use custom platforms for the web interface or in batch\n  mode using a similar approach.</p>\n\n  <h2>Building the Docker image</h2>\n\n  <p>This section is primarily of interest the Herbie developers.</p>\n\n  <p>Clone the repo and confirm that Herbie builds correctly\n  with <code>make install</code>. Next, examine the Dockerfile and\n  Makefile together. The Dockerfile should follow a process exactly\n  like the Makefile, except a clean initial environment is\n  assumed.</p>\n\n  <p>The build is split into 2 or more stages to limit the size of the\n  resulting image. Each stage consists of a <code>FROM</code> command\n  and a series of further commands to build up the desired\n  environment, and later stages can refer to earlier stages by\n  name&mdash;for example, <code>COPY --from=earlier-stage ...</code>\n  can copy files compiled in earlier images.</p>\n\n  <p>Before building the official image, bump the version of Rust used\n  for binary compilation and the version of Racket used in production,\n  and adjusting paths to match the newest version of the repo.</p>\n\n  <p>Once you are ready, run this from the repository root:</p>\n\n  <pre class=\"shell\">docker build -t uwplse/herbie:test .</pre>\n\n  <p>This builds a new test image and tags\n  it <code>uwplse/herbie:test</code>. You can run this image with:</p>\n\n  <pre class=\"shell\">docker run -p 8000:80 -it uwplse/herbie:test</pre>\n\n  <p>The web demo should now be visible at <code>http://localhost:8000</code>.</p>\n  \n  <p>To open a shell in a running container for testing, first get the\n  container ID with:</p>\n\n  <pre class=\"shell\">docker ps</pre>\n\n  <p>Then open a root shell in that container with</p>\n\n  <pre class=\"shell\">docker exec -it &lt;CONTAINER ID&gt; sh</pre>\n  \n  <p>The code and <code>egg-herbie</code> binaries should be\n  under <code>/src</code>.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.3/error.html",
    "content": "<!doctype html>\n<meta charset=\"utf-8\" />\n<title>What is Error?</title>\n<link rel='stylesheet' type='text/css' href='../../main.css'>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<script type=\"text/javascript\" src=\"toc.js\"></script>\n\n<header>\n  <h1>What is Error?</h1>\n  <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n  <nav>\n    <ul>\n      <li><a href=\"../../demo/\">Try</a></li>\n      <li><a href=\"installing.html\">Install</a></li>\n      <li><a href=\"tutorial.html\">Learn</a></li>\n    </ul>\n  </nav>\n</header>\n\n<p>\n  <a href=\"../../\">Herbie</a> helps you identify and correct floating\n  point error in your numeric programs. But what is floating point\n  error, and how does Herbie measure it?\n</p>\n\n<h2>The summary</h2>\n\n<p>When Herbie reports a \"percentage accuracy\" number like 92.3%, it's\nusually best to think of that as the percentage of floating-point\ninputs where the expression is reasonably accurate.</p>\n\n<p>The impact of this error on your application will depend a lot\non <em>which</em> 7.7% of inputs are inaccurate, and what kind of\nerror that is. You can find this out using\nthe <a href=\"report.html\">accuracy graph in Herbie reports</a>. You\ncan also use preconditions to restrict the inputs Herbie is\nconsidering.</p>\n\n<h2>Why rounding matters</h2>\n\n<p>In mathematics, we work with real numbers, but on a computer, we\ntypically use floating-point numbers. Because there are infinitely\nmany real numbers, but only finitely many floating-point numbers, some\nreal numbers can't be accurately represented. This means that every\ntime you do an operation, the true result will be <em>rounded</em> to\na representable one.</p>\n\n<p>Take an extreme example: the code <code>1e100 + 1</code>, which\nincrements a huge number in IEEE 754 double-precision floating-point.\nThere's an exact real-number answer, a one followed by 99 zeros and\nthen another 1, but the closest <em>floating-point</em> value is the\nsame as <code>1e100</code>.</p>\n\n  <p>Errors like this can cause problems. In the example above, the\n  answers differ by one part per googol, which is pretty small. But the\n  error can grow. For example, since <code>1e100 + 1</code> rounds to\n  the same value as <code>1e100</code>, the larger computation</p>\n\n  <pre>(1e100 + 1) - 1e100</pre>\n\n  <p>returns <code>0</code> instead of the correct answer, <code>1</code>.\n  Now the difference is pretty stark, and can grow even bigger through\n  later operations.</p>\n\n<h2>Bits of error</h2>\n\n<p>There are lots of ways to <em>measure</em> how much rounding error\nthere is in a computation. Most people find the notions of absolute\nand relative error most intuitive, but Herbie internally uses a more\ncomplex notion called <em>bits of error</em>.</p>\n\n<p>The bits of error metric imagines you have a list of all of the\npossible floating-point numbers, from largest to smallest. In that\nlist, compare the floating-point value you computed to the one closest\nto the true answer. If they are the same, that's called 0 bits of\nerror; if they are one apart, that's called one bit of error; three\napart is two bits of error; seven apart is three bits; and so on.</p>\n\n<p>In general, if the two floating-point values are <var>n</var> items\napart, Herbie says they have <code>log2(n + 1)</code> bits of error.\nValues like <code>0</code> and <code>-0</code> are treated as having 0\nbits of error, and NaN is considered to have the maximum number of\nbits of error against non-NaN values. While there's all sorts of\ntheoretical justifications, Herbie mainly uses this error metric\nbecause we've found it to give the best results. </p>\n\n<p>On a single input, the best way to interpret the \"bits of error\"\nmetric is that it tells you roughly how many bits of the answer,\nstarting at the end, are useless. With zero bits of error, you have\nthe best answer possible. With four bits, that's still pretty good\nbecause it's four out of 64. But with 40 or 50 bits of error, you're\ngetting less accuracy out of the computation than even a\nsingle-precision floating-point value. And it's even possible to have\nsomething like 58 or 60 bits of error, in which case even the sign and\nexponent bits (which in double-precision floating-point the the most\nsignificant 12 bits) are incorrect.</p>\n\n<h2>Percentage accuracy</h2>\n\n<p>Because different number representations have different numbers of\nbits, Herbie shows the percentage of bits that are accurate instead of\nthe bits of error. With double-precision floats, for example, 75%\naccurate means 16 bits of error.</p>\n\n<p>Bits of error measures the error of a computation for some specific\ninput. But usually you're interested in the error of a computation\nacross many possible inputs. Herbie therefore averages the accuracy\npercentage across many randomly-sampled valid inputs.</p>\n\n<p>Typically, input points are either very accurate or not accurate at\nall. So when computing percentage accuracy, Herbie's averaging a lot\nof points with near-100% accuracy and a lot of points with near-0%\naccuracy. In that sense, you can think of percentage accuracy as\nmeasuring mostly what percentage <em>of inputs</em> are accurate. If\nHerbie says your computation is 75% accurate what it's really saying\nis that about a quarter of inputs produce usable outputs.</p>\n\n<h2>Valid inputs</h2>\n\n<p>When Herbie computes this average, it's over <em>valid</em>,\nuniformly distributed input points.</p>\n\n<p>Herbie considers an input valid if it is a floating-point value in\nthe appropriate precision and its true, real-number output 1) exists;\n2) satisfies the user's precondition; and 3) can be computed. Let's\ndive into each requirement.</p>\n\n<ol>\n  <li>An output can fail to exist for an input if something like a\n    division by zero or square root of a negative number\n    happens <em>even with exact, real-number computation</em>. Then\n    there's no exact answer to compare against and the point is\n    considered invalid.</li>\n  <li>An input can fail to satisfy the user's precondition, which are\n    usually a range of inputs. For example, if the precondition\n    is <code>(&lt; 1 x 2)</code>, then the input <code>x = 3</code> is\n    invalid.</li>\n  <li>Finally, and most rarely, Herbie can fail to compute the output\n    for a particular input. For example, the computation <code>(/ (exp\n    1e9) (exp 1e9))</code>, which divides two identical but gargantuan\n    numbers, does have an exact real-number answer (one), but Herbie\n    can't compute that exact answer because the intermediate values\n    are too large. This input is also invalid, but you'll\n    get <a href=\"faq.html#ground-truth\">a warning</a> if this\n    happens.</li>\n</ol>\n\n<p>Herbie's percentage accuracy metric only averages over valid\npoints. This means that when you change your precondition, you change\nwhich points are valid, and that can change the percentage accuracy\nreported by Herbie. This is useful: if you've observed a\nfloating-point error, you can tailor your precondition to focus on\ninputs near the one you've observed.</p>\n\n<p>Infinite outputs can be valid. For example, consider <code>(exp\nx)</code> for <code>x = 1e100</code>. The true real-number result is\nsome very large finite number. That real number, whatever it is,\nrounds to infinity in double-precision floating point. Herbie thus\nconsiders this input valid. Since you might find this surprising,\nHerbie issues <a href=\"faq.html#inf-points\">a warning</a> if too many\noutputs are infinite.</p>\n\n<h2>Sampling inputs</h2>\n\n<p>When randomly sampling inputs, Herbie considers each valid input\nequally likely. Importantly, this does not mean that it uses a uniform\ndistribution, because floating-point values themselves are not\nuniformly distributed.</p>\n\n<p>For example, there are as many floating-point values between 1 and\n2 as there are between one and one half, because floating-point values\nuse an exponential encoding. But that means that, in the\ninterval <kbd>[0.5, 2]</kbd>, Herbie will sample from the first third\nof that range twice as often as from the other two thirds.</p>\n\n<p>This can produce unintuitive results, especially for intervals that\ncross 0. For example, in the interval <kbd>[0, 1]</kbd>, the second\nhalf of that interval (from one half to one) has a tiny proportion of\nthe weight (in double-precision floating-point, about 0.1%). If Herbie\ncan improve accuracy by a little bit between zero and one half, while\ndramatically reducing accuracy between one half and one, it will think\nthat that's an accuracy improvement. For this reason, Herbie prompts\nyou to add a minimum absolute value for ranges that cross zero. Even a\ntrivial minimum absolute value, like <code>1e-10</code>, can\ndramatically improve Herbie's results.</p>\n\n<p>Unfortunately, there's no way for Herbie to intuit exactly what you\nmean, so understanding this error distribution is essential to\nunderstanding Herbie's outputs. For example, if Herbie reports that\naccuracy improved from 75% to 76%, it's essential to know: is the\nimprovement happening on inputs between one half and one, or\nbetween <code>1e-100</code> and <code>2e-100</code>? To answer this\nquestion, it's important to look over\nthe <a href=\"report.html\">reports and graphs</a> generated by\nHerbie.</p>\n"
  },
  {
    "path": "www/doc/2.3/faq.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Warnings and Errors</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Common Warnings and Errors</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p><a href=\"../../\">Herbie</a> issues a variety of warnings and\n  errors when something unexpected happens during compilation.</p>\n\n\n  <h2>Common warnings</h2>\n\n  <h3 id=\"inf-points\"><var>N</var>% of points produce a very large (infinite) output.</h3>\n  \n  <p>\n    Sometimes, an input to your expression produces an output so large\n    that it's best represented by a floating-point infinity. For\n    example, <code>(exp 1000)</code> is over 10<sup>434</sup>, so it's\n    much larger than the largest floating-point value. Herbie raises\n    this warning when too many inputs (more than 20% of them) are this\n    large. When you see this warning, you should usually set a more\n    restrictive precondition.\n  </p>\n\n  <h3 id=\"ground-truth\">Could not determine a ground truth</h3>\n\n  <p>\n    Herbie raises this warning when some inputs require more than\n    10,000 bits to compute an exact ground truth. For example, to\n    compute <code>(/ (exp x) (exp x))</code> for <code>x =\n    1e100</code>, absurdly large numbers would be required. Herbie\n    discards these inputs and raises this warning. When you see this\n    warning, you should usually set a more restrictive precondition.\n  </p>\n\n  <h3 id=\"value-to-string\">Could not uniquely print <var>val</var></h3>\n\n  <p>\n    Herbie will raise this warning when it needs more than 10,000 bits\n    to produce a unique decimal representation for a given value. This\n    is likely the result of a bug in a custom platform, likely in\n    a <a href=\"plugins.html\">representation definition</a>. The\n    platform needs to be fixed.\n  </p>\n\n  <h3 id=\"unused-variable\">Unused variable <var>var</var></h3>\n  \n  <p>\n    The input FPCore contains a variable that is not used in the body\n    expression. You should remove the unused variable.\n  </p>\n\n  <h3 id=\"strange-variable\">Unusual variable <var>var</var></h3>\n  \n  <p>\n    The input expression contains a variable that is named similar to\n    some named constant, like <var>e</var> instead of <var>E</var>.\n    You should use a different variable name.\n  </p>\n\n  <h3 id=\"unsound-egraph\">Unsoundness detected in the egraph</h3>\n  \n  <p>\n    Herbie raises this warning when its algebraic rewriting phase\n    fails. This indicates a bug in Herbie itself and should be\n    reported to the developers.\n  </p>\n\n  <h2>Common errors</h2>\n\n  <h3 id=\"invalid-syntax\">Invalid syntax</h3>\n\n  <p>This error means you mis-formatted Herbie's input. Common errors\n  include misspelled function names and parenthesized expressions that\n  should not be parenthesized. For example, in <code>(- (exp (x))\n  1)</code>, the expression <code>x</code> is a variable so shouldn't\n  be parenthesized; <code>(- (exp x) 1)</code> is correct. Follow\n  the <a href=\"input.html\">input format</a> more carefully.\n  </p>\n\n  <h3 id=\"sample-valid-points\">Cannot sample enough valid points</h3>\n\n  <p>This error occurs when Herbie is unable to find enough valid\n  points. For example, the expression <code>(acos (+ 1000 x))</code>\n  is invalid unless <code>(&lt;= -1001 x -999)</code>, a rather narrow\n  range. You can specify a more restrictive precondition or pass a\n  larger value for\n  the <a href=\"options.html\"><code>--num-analysis</code> flag</a>.\n  </p>\n\n  <h3 id=\"no-valid-values\">No valid values</h3>\n\n  <p>This error indicates that your input has no valid inputs, usually\n  due to an overly restriction precondition. For example, the\n  precondition <code>(&lt; 3 x 2)</code> excludes all inputs. You\n  should fix either the precondition or the input program.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.3/input.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Input Format</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>The Input Format</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> uses\n    the <a href=\"http://fpbench.org\">FPCore</a> format to specify an\n    input program, and has extensive options for precisely describing\n    its context.\n  </p>\n\n  <h2>Math format</h2>\n\n  <p>The Herbie web shell takes input in standard math syntax. More\n  specifically, it uses a subset of\n  the <a href=\"https://mathjs.org/docs/expressions/syntax.html\">math.js\n  syntax</a>. The web shell automatically checks for syntax errors,\n  and provides a graphical user interface for specifying the input\n  domain. The web shell converts the mathematical expression and input\n  ranges into FPCore before sending it to Herbie.</p>\n  \n  <h2 id=\"sec1\">FPCore format</h2>\n\n  <p>Herbie's command-line and batch-mode tools\n  use <a href=\"http://fpbench.org\">FPCore</a> format to describe\n  mathematical expressions. FPCore looks like this:</p>\n\n  <pre>(FPCore (<var>inputs ...</var>) <var>properties ...</var> <var>expression</var>)</pre>\n\n  <p>\n    Each <var>input</var> is a variable name, like <code>x</code>,\n    used in the <var>expression</var>. Properties are used to specify\n    additional information about the <var>expression</var>'s context.\n  </p>\n\n  <p>\n    The expression is written in prefix form, with every function call\n    parenthesized, as in Lisp. For example, the formula for the\n    hypotenuse of a triangle with legs <i>a</i> and <i>b</i> is:\n  </p>\n\n  <pre>(FPCore (a b) (sqrt (+ (* a a) (* b b))))</pre>\n\n  <p>\n    The semicolon (<kbd>;</kbd>) character introduces a line comment.\n    We recommend the <code>.fpcore</code> file extension for FPCore files.\n  </p>\n  \n  <h2>Supported functions</h2>\n  \n  <p>FPCore expressions can use any of the following functions:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>, <code>fabs</code></dt>\n    <dd>The usual arithmetic functions</dd>\n    <dt><code>sqrt</code>, <code>cbrt</code></dt>\n    <dd>Square and cube roots</dd>\n    <dt><code>pow</code>, <code>exp</code>, <code>log</code></dt>\n    <dd>Various exponentiations and logarithms</dd>\n    <dt><code>sin</code>, <code>cos</code>, <code>tan</code></dt>\n    <dd>The trigonometric functions</dd>\n    <dt><code>asin</code>, <code>acos</code>, <code>atan</code>, <code>atan2</code></dt>\n    <dd>The inverse trigonometric functions</dd>\n    <dt><code>sinh</code>, <code>cosh</code>, <code>tanh</code></dt>\n    <dd>The hyperbolic functions</dd>\n    <dt><code>asinh</code>, <code>acosh</code>, <code>atanh</code></dt>\n    <dd>The inverse hyperbolic functions</dd>\n    <dt><code>fma</code>, <code>expm1</code>, <code>log1p</code>, <code>hypot</code></dt>\n    <dd>Specialized numeric functions</dd>\n  </dl>\n\n  <p>Herbie also supports the constants <code>PI</code>\n  and <code>E</code>. Use <code>-</code> for both subtraction and\n  negation.</p>\n\n  <p>However, how Herbie evaluates these functions, their cost, and\n  what additional functions are available depends on\n  the <a href=\"platforms.rkt\">platform</a> you select.</p>\n\n  <h2 id=\"conditionals\">Conditionals</h2>\n  \n  <p>FPCore uses <code>if</code> for conditional expressions:</p>\n\n  <pre>(if <var>cond</var> <var>if-true</var> <var>if-false</var>)</pre>\n\n  <p>\n    The conditional <code><var>cond</var></code> may use:\n  </p>\n  \n  <dl class=\"function-list\">\n    <dt><code>==</code>, <code>!=</code>, <code>&lt;</code>, <code>&gt;</code>, <code>&lt;=</code>, <code>&gt;=</code></dt>\n    <dd>The usual comparison operators</dd>\n    <dt><code>and</code>, <code>or</code>, <code>not</code></dt>\n    <dd>The usual logical operators</dd>\n    <dt><code>TRUE</code>, <code>FALSE</code></dt>\n    <dd>The two boolean values</dd>\n  </dl>\n\n  <p>The comparison operators support chained comparisons with more than two arguments;\n    for example <code>(&lt; 1 x 10)</code> means <code>1 < x < 10</code>.</p>\n\n  <h2 id=\"intermediates\">Intermediate variables</h2>\n  \n  <p>Intermediate variables can be defined\n    using <code>let</code> and <code>let*</code>:</p>\n\n  <pre>(let ([<var>variable</var> <var>value</var>] <var>...</var>) <var>body</var>)</pre>\n  <pre>(let* ([<var>variable</var> <var>value</var>] <var>...</var>) <var>body</var>)</pre>\n\n  <p>In both <code>let</code> and <code>let*</code>,\n  each <var>variable</var> is bound to its <var>value</var> and can be\n  used in the <var>body</var>. The difference between <code>let</code>\n  and <code>let*</code> is what order the values are\n  evaluated in:</p>\n\n  <dl>\n    <dt><code>let</code> expressions</dt>\n    <dd>In a <code>let</code> expression, all the values are evaluated\n      in parallel, before they are bound to their variables. This\n      means that later values can't refer to earlier variables in the\n      same <code>let</code> block.</dd>\n\n    <dt><code>let*</code> expressions</dt>\n    <dd>A <code>let*</code> block looks the same as a <code>let</code>\n      block, except the values are evaluated one at a time, and later\n      values can refer to earlier variables.</dd>\n  </dl>\n\n  <p>Unless you have a lot of Lisp experience, you'll probably\n  find <code>let*</code> more intuitive.</p>\n\n  <p>Internally, Herbie treats intermediate values only as a\n  notational convenience, and inlines their values before improving\n  the formula&apos;s accuracy. Using intermediate variables will\n  therefore not produce a more accurate result or help Herbie run\n  faster.</p>\n\n  <h2 id=\"specs\">Specifications</h2>\n\n  <p>In some cases, your input program is an approximation of some\n  more complex mathematical expression. The <code>:spec</code> (for\n  “specification”) lets you specify the more complex ideal case.\n  Herbie will then try to modify the input program to make it more\n  accurately evaluate the specification.</p>\n\n  <p>For example, suppose you want to evaluate <code>sin(1/x)</code>\n  via a series expansion. Write:</p>\n\n  <pre>(FPCore (x)\n  :spec (sin (/ 1 x))\n  (+ (/ 1 x) (/ 1 (* 6 (pow x 3)))))</pre>\n\n  <p>Herbie will use the <code>:spec</code> expression to evaluate\n  error, but use body expression as a starting-point for finding\n  more accurate expressions.</p>\n\n  <h2 id=\"preconditions\">Preconditions</h2>\n\n  <p>By default, the arguments to formulas are assumed to be\n  arbitrarily large or small floating-point numbers. However, in most\n  programs a smaller range of argument values is possible.\n  The <code>:pre</code> property (for “precondition”) describes this\n  smaller range.</p>\n\n  <p>Preconditions use comparison and boolean operators, just\n  like <a href=\"#conditionals\">conditional statements</a>:</p>\n\n  <pre>(FPCore (x) :pre (&lt; 1 x 10) (/ 1 (- x 1)))</pre>\n\n  <p>Herbie is particularly efficient when when the precondition is\n  an <code>and</code> of ranges for each variable, but more complex\n  preconditions also work.</p>\n\n  <h2 id=\"precisions\">Precisions</h2>\n\n  <p>Herbie supports both single- and double-precision values; you can\n  specify the precision with the <code>:precision</code> property:</p>\n\n  <dl class=\"function-list\">\n    <dt><code>binary32</code></dt>\n    <dd>Single-precision IEEE-754 floating point</dd>\n    <dt><code>binary64</code></dt>\n    <dd>Double-precision IEEE-754 floating point</dd>\n  </dl>\n\n  <p><a href=\"platforms.html\">Platforms</a> can also add additional\n  precisions.</p>\n\n  <h2 id=\"properties\">Miscellaneous Input Properties</h2>\n\n  <p>A <var>name</var> can be provided before the argument list to\n  name an FPCore. That FPCore can then be called in other, later\n  FPCores.</p>\n\n  <p>Herbie uses the <code>:name</code> property to name FPCores in\n  its UI. Its value ought to be a string.</p>\n\n  <p>Herbie allows <code>:alt</code> properties to specify additional\n  \"developer targets\"; these might be other alternatives you&apos;ve\n  tried that you want to compare against.</p>\n\n  <p>Herbie&apos;s benchmark suite also uses properties for continuous\n  integration, but these are not officially supported and their use is\n  discouraged.</p>\n  \n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.3/installing.html",
    "content": "<!doctype html>\n<html>\n\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Installing Herbie</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n\n<body>\n  <header>\n    <h1>Installing Herbie</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> supports Linux, macOS, and Windows. To\n    start, install <a href=\"https://racket-lang.org\">Racket</a>. Then\n    install Herbie, either from a package, from source, or via\n    a <a href=\"docker.html\">Docker image</a>.\n  </p>\n\n  <h2>Installing Racket</h2>\n\n  <p>\n    Install Racket either using\n    the <a href=\"http://download.racket-lang.org/\">official\n    installer</a> or distro-provided packages. Versions as old as 8.10\n    are supported, but more recent versions are faster.\n  </p>\n\n  <p>\n    On Linux, we recommend against installing Racket via Snap. If you\n    must install Racket from Snap, install from source and store that\n    source directory in your home directory or another allow-listed\n    directory.\n  </p>\n\n  <p>\n    Test that Racket is installed correctly and has a correct version:\n  </p>\n\n  <pre class=\"shell\">racket\nWelcome to Racket v8.17 [cs].\n> (exit)</pre>\n\n  <h2>Installing Herbie from a package</h2>\n\n  <p>Herbie can be installed as a binary package on x86 Windows and\n  Linux and on x86 or ARM macOS. If you are on a more obscure\n  platform, please install from source instead.</p>\n\n  <p>After installing Racket, install Herbie from a package with:</p>\n\n  <pre class=\"shell\">raco pkg install --auto herbie</pre>\n\n  <p>Then check that Herbie works by running:</p>\n\n  <pre class=\"shell\">racket -l herbie -- --version\nHerbie 2.2</pre>\n\n  <p>If you'd like, you can run Herbie with the <code>herbie</code>\n  command by adding the following directory to your PATH (example\n  paths for Racket 8.17):</p>\n\n  <ul>\n    <li>On Windows, <code>AppData\\Roaming\\Racket\\8.17\\bin</code> in your user folder.</li>\n    <li>On macOS, <code>Library/Racket/8.17/bin</code> in your home folder.</li>\n    <li>On Linux, <code>.local/share/racket/8.17/bin</code> in your home directory.</li>\n  </ul>\n\n  <p>Once Herbie is installed and working correctly, check out\n  the <a href=\"tutorial.html\">tutorial</a>.</p>\n\n  <h2>Installing Herbie from source</h2>\n  \n  <p>Installing Herbie from source is best if you are a Herbie\n  developer, or if you use a more obscure hardware/OS combination. The\n  instructions assume a standard Unix userland; on Windows, you may\n  have to install tools like Make separately, or use WSL.\n  </p>\n\n  <p>\n    Install Racket as described above. Then install Rust 1.60.0 or\n    later using <a href=\"https://rustup.rs/\">rustup</a> or some other\n    means.\n  </p>\n\n  <p>\n    Once Racket and Rust are installed, download the Herbie source\n    <a href=\"https://github.com/uwplse/herbie\">from GitHub</a> with:\n  </p>\n\n  <pre class=\"shell\">git clone https://github.com/herbie-fp/herbie</pre>\n\n  <p>Change to the <code>herbie</code> directory; you should see\n  a <code>README.md</code> file, a directory named <code>src</code>, a\n  directory named <code>bench/</code>, and a few other files and\n  directories. Install Herbie with:</p>\n\n  <pre class=\"shell\">make install</pre>\n\n  <p>This command installs Herbie and its dependencies and compiles it\n  for faster startup. Check that Herbie works by running:</p>\n\n  <pre class=\"shell\">racket -l herbie -- --version\nHerbie 2.2</pre>\n\n  <p>You can add <code>herbie</code> to your path, as described in the\n  package-install instructions. Once Herbie is installed and working\n  correctly, check out the <a href=\"tutorial.html\">tutorial</a>.</p>\n\n  <h2>Installing Herbie with Docker</h2>\n\n  <p><a href=\"https://docker.com\">Docker</a> is a container manager,\n  which is sort of like a virtual machine. We do not recommend using\n  Herbie in Docker without prior Docker experience.</p>\n\n  <p>The <a href=\"docker.html\">Docker documentation</a> describes how\n  to install and run our <code>uwplse/herbie</code> image.</p>\n\n</body>\n\n</html>\n"
  },
  {
    "path": "www/doc/2.3/options.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Command-line Options</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Command-line Options</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>The <a href=\"../../\"><code>herbie</code></a> command has\n  subcommands and options that influence both its user interface and\n  the quality of its output.</p>\n\n  <h2>Herbie commands</h2>\n\n  <p>Herbie provides several subcommands, which offer interactive and\n    batch modes for both the <a href=\"using-cli.html\">command line</a>\n    and the <a href=\"using-web.html\">web interface</a>:</p>\n\n  <dl>\n    <dt><code>racket -l herbie web</code></dt>\n    <dd>Use Herbie <a href=\"using-web.html\">through your browser</a>\n      using a local server. This server can also be used\n      from <a href=\"https://github.com/herbie-fp/odyssey\">Odyssey</a>.</dd>\n\n    <dt><code>racket -l herbie shell</code></dt>\n    <dd>Use Herbie <a href=\"using-cli.html\">via a command-line shell</a>.\n    Enter an <a href=\"input.html\">FPCore expression</a> and Herbie\n    prints faster and more accurate alternatives.</dd>\n\n    <dt><code>racket -l herbie improve <var>input</var> <var>output</var></code></dt>\n    <dd>Run Herbie on the expressions in the file or\n    directory <var>input</var>. The results are written\n    to <var>output</var>, a single file in FPCore format.</dd>\n\n    <dt><code>racket -l herbie report <var>input</var> <var>output</var></code></dt>\n    <dd>Run Herbie on the expressions in the file or\n    directory <var>input</var>. The results are written\n    to <var>output</var>, a directory of\n    HTML <a href=\"report.html\">reports</a>. Viewing these requires a\n    web server.</dd>\n  </dl>\n\n  <p>We recommend the <code>web</code> subcommand for interactive use\n  with detailed <a href=\"report.html\">reports</a> that include graphs\n  of error versus input values and plots comparing cost and accuracy.\n  This can help you understand whether Herbie's improvements matter\n  for your use case.</p>\n\n  <p>Use <code>herbie <var>subcommand</var> --help</code> to view\n  available command-line options for a subcommand. This command also\n  shows undocumented subcommands not listed on this page.</p>\n\n  <h2>General options</h2>\n\n  <p>\n    General options apply to all subcommands and are passed after the\n    subcommand name but before other arguments, like this:\n  </p>\n\n  <pre class=\"shell\">racket -l herbie report --timeout 60 in.fpcore out/</pre>\n\n  <p>Options must go before subcommand arguments like input and output\n  paths.</p>\n\n  <dl>\n    <dt><code>--platform <var>P</var></code></dt>\n    <dd>Herbie's backend <a href=\"platforms.html\">platform</a>, which\n      affects the operations available to Herbie, their accuracies,\n      and their costs. The platform name is either one of the built-in\n      platforms, or the path to a <a href=\"platforms.html\">custom\n      platform</a>. In general, it's best to select the platform that\n      most closely matches the programming language and hardware where\n      you will be running floating-point code.</dd>\n\n    <dt><code>--seed <var>S</var></code></dt>\n    <dd>The random seed, which changes the randomly-selected points\n      that Herbie evaluates candidate expressions on. The seed is a\n      number between 0 and 2<sup>31</sup> (not including the latter).\n      Two runs of Herbie with the same seed should produce identical\n      results. By default, a random seed is chosen.</dd>\n\n    <dt><code>--timeout <var>T</var></code></dt>\n    <dd>The timeout to use per-input, in seconds. A fractional number\n      of seconds can be given. By default, no timeout is used.</dd>\n\n    <dt><code>--threads <var>N</var></code></dt>\n    <dd>Enables multi-threaded operation. By default, no threads are\n      used. The argument is the number of threads to use,\n      or <code>yes</code> to use all of the hardware threads.</dd>\n\n    <dt><code>--num-points <var>N</var></code></dt>\n    <dd>The number of input points Herbie uses to evaluate candidate\n      expressions. The default, 256, is a good balance for most\n      programs. Increasing this option, say to 512 or 1024, will slow\n      Herbie down but may make its results more consistent.</dd>\n\n    <dt><code>--num-iters <var>N</var></code></dt>\n    <dd>The number of attempts Herbie makes to improve accuracy. The\n      default, 4, suffices for most programs, and more iterations are\n      rarely beneficial. But increase this option, say to 6, can\n      sometimes lead to more accurate or faster results.</dd>\n\n    <dt><code>--num-analysis <var>N</var></code></dt>\n    <dd>The number of input subdivisions to use when searching for\n      valid input points. The default is 12. Increasing this option\n      will slow Herbie down, but may fix a\n      \"<a href=\"faq.html#sample-valid-points\">Cannot sample enough\n      valid points</a>\" error.</dd>\n    \n    <dt><code>--num-enodes <var>N</var></code></dt>\n    <dd>The number of equivalence graph nodes to use when doing\n      algebraic reasoning. The default is 4000. Increasing this option\n      will slow Herbie down, but may improve results slightly.</dd>\n    \n  </dl>\n\n  <h2>Web shell options</h2>\n  \n  <p>The <code>web</code> tool runs Herbie and connects to it from\n  your browser. It has options to control the underlying web\n  server.</p>\n  \n  <dl>\n    <dt><code>--port N</code></dt>\n    <dd>The port the Herbie server runs on. The default port is 8000.</dd>\n\n    <dt><code>--save-session dir</code></dt>\n    <dd>Save all the reports to this directory. The directory also\n    caches previously-computed expressions.</dd>\n\n    <dt><code>--log file</code></dt>\n    <dd>Write an access log to this file, formatted like an Apache\n    log. This log does <em>not</em> contain crash tracebacks.</dd>\n\n    <dt><code>--quiet</code></dt>\n    <dd>By default, but not when this option is set, a browser is\n    automatically started to show the Herbie page. This option also\n    shrinks the text printed on start up.</dd>\n\n    <dt><code>--no-browser</code></dt>\n    <dd>This flag disables the default behavior of opening the Herbie page in your default browser.</dd>\n\n    <dt><code>--public</code></dt>\n    <dd>When set, users on other computers can connect to the demo and\n    use it. (In other words, the server listens\n    on <code>0.0.0.0</code>.) Essential when Herbie is run\n    from <a href=\"docker.html\">Docker</a>.</dd>\n  </dl>\n\n  <h2>Rulesets</h2>\n\n  <p>\n    Herbie uses rewrite rules to change programs and improve accuracy.\n    The <code>--disable rules:<var>group</var></code>\n    and <code>--enable rules:<var>group</var></code> options turn rule\n    sets on and off. In general, turning a ruleset on makes Herbie\n    produce more accurate programs.\n  </p>\n\n  <p>The full list of rule groups is:</p>\n\n  <table class=\"function-list\">\n    <thead><tr><th>Rule Group</th><th>Topic of rewrite rules</th></tr></thead>\n    <tr><td>arithmetic</td><td>Basic arithmetic facts</td></tr>\n    <tr><td>polynomials</td><td>Factoring and powers</td></tr>\n    <tr><td>fractions</td><td>Fraction arithmetic</td></tr>\n    <tr><td>exponents</td><td>Exponentiation identities</td></tr>\n    <tr><td>trigonometry</td><td>Trigonometric identities</td></tr>\n    <tr><td>hyperbolic</td><td>Hyperbolic trigonometric identities</td></tr>\n  </table>\n\n  <h2>Search options</h2>\n\n  <p>These options enable or disable transformations that Herbie uses\n    to find candidate programs. We recommend sticking to the\n    defaults.</p>\n\n  <p>\n    Each option can be turned off with the <code>-o</code>\n    or <code>--disable</code> command-line flag and on with\n    <code>+o</code> or <code>--enable</code>. Turning an option off\n    typically results in less-accurate results, while turning a option\n    on typically results in more confusing output expressions.\n  </p>\n\n  <dl>\n    <dt><code>setup:search</code></dt>\n    <dd>This option, on by default, uses interval subdivision search\n    to help compute ground truth for complicated expressions. If\n    turned off, Herbie will be slightly faster, but may hit the\n    \"<a href=\"faq.html#sample-valid-points\">Cannot sample enough valid\n    points</a>\" error more often. Instead of turning this option off,\n    try adjusting the <kbd>--num-analysis</kbd> flag.</dd>\n\n    <dt><code>setup:preprocess</code></dt>\n    <dd>This option, on by default, uses identities of the input\n    expression (like even or symmetric expressions) to perform\n    rewriting more effectively. If turned off, Herbie will skip\n    preprocessing and work directly with the original expression. This\n    can be faster but may produce less accurate results for\n    expressions with exploitable symmetries.</dd>\n\n    <dt><code>generate:rr</code></dt>\n    <dd>This option, on by default, uses algebraic rewriting to\n    generate candidate programs. This is Herbie's primary method of\n    improving accuracy, and we do not recommend turning off this\n    option.</dd>\n\n    <dt><code>generate:taylor</code></dt>\n    <dd>This option, on by default, uses series expansion to generate\n    candidate programs. If turned off, Herbie will not use series\n    expansion, which may help accuracy in some ranges while leaving\n    Herbie unable to solve certain under- and overflow issues.</dd>\n\n    <dt><code>generate:evaluate</code></dt>\n    <dd>This option, on by default, uses arbitrary-precision\n    arithmetic to generate candidate programs, specifically by exactly\n    computing some constant expressions. If turned off, these exact\n    computations won't be performed and Herbie won't be able to\n    improve accuracy in those cases.</dd>\n\n    <dt><code>generate:proofs</code></dt>\n    <dd>This option, on by default, generates step-by-step derivations\n    for HTML reports. If turned off, the step-by-step derivations will\n    be absent, and Herbie will be slightly faster.</dd>\n\n    <dt><code>reduce:regimes</code></dt>\n    <dd>This option, on by default, uses Herbie's regime inference\n    algorithm to branch between several program candidates. If turned\n    off, branches will not be inferred and the output program will be\n    straight-line code (if the input was). Instead of turning this\n    option off, consider increasing your platform's\n    <a href=\"platforms.html\"><code>if</code> cost</a> to discourage\n    branches.</dd>\n\n    <dt><code>reduce:binary-search</code></dt>\n    <dd>This option, on by default, uses binary search to refine the\n    values used in inferred branches. If turned off, different runs of\n    Herbie will be less consistent, and accuracy near branches will\n    suffer.</dd>\n\n    <dt><code>reduce:branch-expressions</code></dt>\n    <dd>This option, on by default, allows Herbie to branch on\n      expressions, not just variables. This slows Herbie down,\n      particularly for large programs. If turned off, Herbie will only\n      try to branch on variables.</dd>\n  </dl>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.3/platforms.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Platforms</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Writing a Herbie Platform</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>Platforms define <a href=\"../../\">Herbie</a> compilation targets.\n  A platform might be specific to a programming language, to a math\n  library, or to a hardware ISA. Writing a custom platforms can help\n  Herbie produce faster and more accurate programs.</p>\n\n  <h2>Platform Concepts</h2>\n  \n  <p>Herbie operates on mathematical specifications and floating-point\n  expressions.</p>\n\n  <p><dfn>Specifications</dfn> are built from rational numbers,\n  variables, and <dfn>functions</dfn> like <code>+</code>,\n  <code>sin</code>, <code>&lt;</code>, and <code>if</code>. A\n  specification has a <dfn>type</dfn>, which is\n  either <code>real</code> or <code>bool</code>.</p>\n\n  <p>Types, functions, and specifications have floating-point\n  analogs.</p>\n  \n  <p><dfn>Representations</dfn> are the floating-point analogs of\n  types, and Herbie comes with three built in:\n  <code>&lt;binary32&gt;</code> and <code>&lt;binary64&gt;</code> are\n  reprentations of <code>real</code> and correspond to single- and\n  double-precision IEEE-754 arithmetic. There's also\n  a <code>&lt;bool&gt;</code> representation for booleans. It's\n  possible to define new representations, described\n  on <a href=\"plugins.html\">another page</a>.</p>\n\n  <p><dfn>Operations</dfn> are the floating-point analog of functions\n  and represent the actual floating-point operation the compilation\n  target can perform. There are typically several operations for each\n  supported function; for example, in the C standard library\n  <a href=\"https://en.cppreference.com/w/c/numeric/math/cos.html\">provides</a>\n  <code>cosf</code> and <code>cos</code>, both of which correspond to\n  the <code>cos</code> function but for different representations\n  (<code>&lt;binary32&gt;</code> and <code>&lt;binary64&gt;</code>).</p>\n  \n  <p><dfn>Expressions</dfn> are the floating-point analog of\n  specifications and represent target-specific floating-point\n  computations. Platforms, to put it simply, just define the set of\n  representations and operations that expressions are allowed to use.\n  Herbie then searches for a fast and accurate expression that\n  corresponds to the user's input specification.</p>\n\n  <p>Each representation, operation, and thus expression has a\n  <dfn>cost</dfn>, which is a non-negative real number. Generally, the\n  cost of a representation is the time it takes to read a value of\n  that representation from memory and the cost of an operation is the\n  time it takes to execute that operation. However, in principle,\n  platforms can use cost to represent another metric like area or\n  latency. Only relative costs matter. If you're not sure, just\n  putting \"<code>1</code>\" for all the costs is not a bad place to\n  start.</p>\n  \n  <h2>Defining a Platform</h2>\n\n  <p>A platform definition is a text file that starts with:</p>\n\n  <pre>#lang herbie/platform</pre>\n  \n  <p>Herbie can then be informed to use this platform by passing\n  the <code>--platform <var>path/to/file</var></code> <a href=\"options.html\">command-line\n  argument</a>.</p>\n\n  <p>The file contains <a href=\"https://racket-lang.org/\">Racket</a>\n  code. That code can define the platform's representations and\n  operations using <code>define-representation</code>\n  and <code>define-operation</code>. It can also define variables and\n  helper functions, import external packages, or anything else Racket\n  can do. If necessary, it can define new representations.</p>\n  \n  <p>Herbie's <a href=\"https://github.com/herbie-fp/herbie/tree/main/src/platforms\">built-in\n  platforms</a> are good example platforms to study or modify. If you\n  use them as an example, you'll need to change the <code>#lang</code>\n  line at the top of the file to be <code>herbie/platforms</code>; the\n  built-in platforms are different because they are built in to Herbie\n  and can't assume Herbie is installed.</p>\n\n  <h2>Defining Representations</h2>\n\n  <p>The typical platform starts by defining the representations it\n  uses and their costs with <code>define-representation</code>:</p>\n\n  <pre>(define-representation &lt;bool&gt; #:cost 1)\n(define-representation &lt;binary64&gt; #:cost 1.5)</pre>\n\n  <p>This cost is the cost for reading a variable or literal of that\n  representation. Note that platforms must explicitly define a cost\n  for the <code>&lt;bool&gt;</code> representation if it uses\n  booleans. If the platform forgets to define a representation that it\n  uses, Herbie will produce an error when loading the platform.</p>\n\n  <p>If the same cost is used repeatedly, it can be convenient to\n  define a variable:</p>\n\n  <pre>(define cost 1)\n(define-representation &lt;bool&gt; #:cost cost)</pre>\n  \n  <p>After defining the representations it uses, a platform then\n  defines all the operations it supports.</p>\n  \n  <h2>Defining Operations</h2>\n\n  <p>An operation is defined by four fields:</p>\n\n  <ul>\n    <li>A <dfn>signature</dfn>, which gives the operation's name and\n    its input and output representations.</li>\n\n    <li>A <dfn>specification</dfn> for the operation's mathematical\n    behavior.</li>\n\n    <li>An <dfn>implementation</dfn> that computes the operation's\n    output given concrete inputs.</li>\n\n    <li>A <dfn>cost</dfn> for using the operation in an\n    expression.</li>\n  </ul>\n  \n  <p>The <code>define-operation</code> construct requires exactly\n  these four fields:</p>\n\n  <pre>(define-operation (recip [x &lt;binary32&gt;]) &lt;binary32&gt;\n  #:spec (/ 1 x) #:impl (lambda (x) ...) #:cost 3)</pre>\n\n  <p>The first line gives the operation's signature: it is\n  named <code>recip</code>, it has one single-precision\n  input <code>x</code>, and it outputs a single-precision float.</p>\n\n  <p>The <code>#:spec</code> field gives this operation's\n  specification as <code>(/ 1 x)</code>, one divided\n  by <code>x</code>. In other words, this operation computes a\n  number's reciprocal.</p>\n\n  <p>The <code>#:impl</code> field gives this operation's\n  implementation, as a Racket function (defined\n  with <code>lambda</code>). An operation's implementation is a Racket\n  function with as many arguments as the operation. It is called with\n  concrete inputs in the corresponding input representations, and must\n  return an output in the output representation. It can be defined\n  using a <code>lambda</code>, a <code>define</code> block, or any\n  other function-defining Racket construct.</p>\n\n  <p>When an implementation function is called,\n  <code>&lt;binary64&gt;</code> and <code>&lt;binary32&gt;</code>\n  arguments are passed as Racket\n  <a href=\"https://docs.racket-lang.org/guide/performance.html#%28tech._flonum%29\">flonums</a>,\n  while <code>&lt;bool&gt;</code> arguments are passed as Racket\n  <a href=\"https://docs.racket-lang.org/reference/booleans.html#%28def._%28%28quote._~23~25kernel%29._boolean~3f%29%29\">booleans</a>.\n  Single-precision numbers aren't a separate type in Racket. instead,\n  you create them from double-precision floats by\n  calling <a href=\"https://docs.racket-lang.org/reference/flonums.html#%28def._%28%28lib._racket%2Fflonum..rkt%29._flsingle%29%29\"><code>flsingle</code></a>.</p>\n\n  <p>For this example, to compute a 32-bit reciprocal for a 32-bit\n  input, one could use <code>(flsingle (/ 1.0 x))</code> for the body\n  of the <code>lambda</code>.</p>\n\n  <p>The <code>#:cost</code> field gives this operation's cost, 3.</p>\n\n  <h2>Defining Multiple Operations</h2>\n  \n  <p>Realistic platform usually have a lot of similar operations:\n  addition, subtraction, multiplication, and division, or sine,\n  cosine, tangent, and so on. The <code>define-operations</code>\n  construct defines multiple operations at a time, as long as they\n  have the same input and output representations:</p>\n\n  <pre>(define-operations ([x &lt;binary64&gt;] [y &lt;binary64&gt;]) &lt;binary64&gt;\n    [+ #:spec (+ x y) #:impl + #:cost 0.200]\n    [- #:spec (- x y) #:impl - #:cost 0.200]\n    [* #:spec (* x y) #:impl * #:cost 0.250]\n    [/ #:spec (/ x y) #:impl / #:cost 0.350])</pre>\n\n  <p>This block defines four functions, each with their own name,\n  specification, implementation, and cost. Note that in this case\n  the <code>#:impl</code> column refers to the Racket\n  functions <code>+</code>, <code>-</code>, <code>*</code>,\n  and <code>/</code>.</p>\n\n  <h2>Common Kinds of Operations</h2>\n\n  <p>This section lists common kinds of operations and notes things\n  you should keep in mind when defining them.</p>\n\n  <h3>Math Library Functions</h3>\n\n  <p>Most operating systems have a standard <code>libm</code> library\n  that provides elementary functions like <code>cos</code>. You can\n  use Herbie's <code>from-libm</code> helper to load implementations\n  from <code>libm</code>:</p>\n\n  <pre>(define-operation (fabs.f32 [x &lt;binary32&gt;]) &lt;binary32&gt;\n  #:spec (fabs x) #:impl (from-libm 'fabsf) #:cost 0.125)</pre>\n\n  <p>The <code>from-libm</code> helper uses dynamic linking to load\n  <code>libm</code>, extracts the symbol passed to\n  <code>from-libm</code>, and then uses the operation's signature to\n  call into the dynamically-linked library from Racket. Be sure to\n  pass the correct symbol name; for single-precision functions, add the\n  \"<code>f</code>\" suffix.</p>\n\n  <p>For other libraries, open them with\n  <code>ffi-lib</code> and use <code>from-ffi</code>, which\n  generalizes <code>from-libm</code>. For example, to load functions\n  from the GNU Scientific Library:</p>\n\n  <pre>(require ffi/unsafe)\n(define libgsl (ffi-lib \"gsl\"))\n(define-operation (cos.gsl [x &lt;binary64&gt;]) &lt;binary64&gt;\n  #:spec (cos x) #:impl (from-ffi libgsl 'gsl_sf_cos) #:cost 0.125)</pre>\n\n  <h3>Numeric Variations</h3>\n\n  <p>Some platforms provide numeric variations like <code>log1p</code>\n  or <code>cosd</code> for common functions. You can define operations\n  for them using complex specifications:</p>\n\n  <pre>(define-operation (cosd [x &lt;binary64&gt;]) &lt;binary64&gt;\n  #:spec (cos (* x (/ (PI) 180))) #:impl (lambda (x) ...) #:cost 4)</pre>\n\n  <p>The <code>#:spec</code> in this example explains to Herbie\n  that <code>cosd</code> is the cosine of <code>x</code> in degrees.\n  Herbie will then use <code>cosd</code> when that improves\n  accuracy.</p>\n\n  <p>Other common numeric variations\n  include <code>fma</code>, <code>log1p</code>, <code>expm1</code>,\n  and <code>hypot</code>. If they're available on your target,\n  we <em>strongly</em> recommend defining operations for them; they\n  often improve accuracy by quite a bit!</p>\n\n  <h3>Conversions</h3>\n\n  <p>A conversion or cast operation uses mixed representations:</p>\n\n  <pre>(define-operation (64-&gt;32 [x &lt;binary64&gt;]) &lt;binary32&gt;\n  #:spec x #:impl flsingle #:cost 1)</pre>\n\n  <p>This operation has a 64-bit input and a 32-bit output. Its\n  specification is just <code>x</code>, which means it doesn't\n  actually do anything mathematically. The implementation is the\n  standard Racket <code>flsingle</code> function (which converts from\n  double- to single-precision) and it has a cost of 1.</p>\n\n  <p>Herbie will use this conversion operation for casting between the\n  two types.</p>\n\n  <h3>Comparisons</h3>\n\n  <p>Comparison operations return <code>&lt;bool&gt;</code>:</p>\n\n  <pre>(define-operations ([x &lt;binary64&gt;] [y &lt;binary64&gt;]) &lt;bool&gt;\n  [==.f64 #:spec (== x y) #:impl =          #:cost 1]\n  [!=.f64 #:spec (!= x y) #:impl (negate =) #:cost 1]\n  [&lt;.f64  #:spec (&lt; x y)  #:impl &lt;          #:cost 1]\n  [&gt;.f64  #:spec (&gt; x y)  #:impl &gt;          #:cost 1]\n  [&lt;=.f64 #:spec (&lt;= x y) #:impl &lt;=         #:cost 1]\n  [&gt;=.f64 #:spec (&gt;= x y) #:impl &gt;=         #:cost 1])</pre>\n  \n  <p>Here, <code>negate</code> is\n  a <a href=\"https://docs.racket-lang.org/reference/procedures.html#%28def._%28%28lib._racket%2Ffunction..rkt%29._negate%29%29\">Racket\n  function</a> that negates a comparison function.</p>\n\n  <p>A platform only needs to provide the comparison functions\n  available on the target. However, Herbie's \"regimes\" pass uses\n  the <code>&lt;=</code> operation, so it's best to provide one if one\n  is available.</p>\n\n  <p>A platform that uses both representation needs to define\n  separate <code>&lt;binary32&gt;</code>\n  and <code>&lt;binary64&gt;</code> comparison operations. They can\n  have different costs.</p>\n\n  <h3>Conditionals</h3>\n\n  <p>Conditionals can be defined as operations with a boolean argument:</p>\n\n  <pre>(define-operation (if-f64 [c &lt;bool&gt;] [t &lt;binary64&gt;] [f &lt;binary64&gt;]) &lt;binary64&gt;\n  #:spec (if c t f) #:impl if-impl\n  #:cost (if-cost 14) )</pre>\n\n  <p>Here <code>if-impl</code> is a Herbie-provided Racket function\n  that wraps a standard <code>if</code> statement, while\n  the <code>if</code> inside the <code>#:spec</code> is how\n  specifications refer to mathematical conditional expressions.</p>\n\n  <p>Conditional operations usually pass a procedure to\n  <code>#:cost</code>. The helper <code>if-cost</code> returns a procedure\n  that receives the costs of the arguments and combines them into a\n  total cost. It computes the cost of evaluating the condition plus the\n  larger of the two branch costs. In this example we add a constant cost\n  of 14 to that value.</p>\n\n  <p>A platform needs to define both <code>&lt;binary32&gt;</code>\n  and <code>&lt;binary64&gt;</code> conditional operations if it uses\n  both representations. They can have different costs. There's\n  typically no need to define conditional operations\n  for <code>&lt;bool&gt;</code> as Herbie does not rewrite boolean\n  expressions.</p>\n\n  <h3>Constants</h3>\n\n  <p>Mathematical constants like <code>E</code> and <code>PI</code>\n  are considered operations in Herbie; they just have no inputs. For\n  example, to define a 64-bit inverse-&pi; constant, write:</p>\n\n  <pre>(define-operation (INVPI) &lt;binary64&gt;\n  #:spec (/ 1 (PI)) #:impl (lambda () ...) #:fpcore PI #:cost 0.5)</pre>\n\n  <p>Note the parentheses in various fields. The\n  name <code>INVPI</code> has parentheses around it like all operation\n  signatures; it just doesn't have any arguments after the name. In\n  the <code>#:spec</code>, the <code>PI</code> constant is also\n  wrapped in parentheses because it is also treated as a zero-argument\n  function. And in the <code>#:impl</code>, the implementation is\n  given by a Racket function of no arguments. You can also use\n  the <a href=\"https://docs.racket-lang.org/reference/procedures.html#%28def._%28%28lib._racket%2Ffunction..rkt%29._const%29%29\">Racket <code>const</code>\n  function</a> to construct these no-argument functions.</p>\n\n  <p>But in the <code>#:fpcore</code> field the <code>PI</code> value\n  doesn't use parentheses, because FPCore treats constants as\n  constants, not zero-argument functions.</p>\n\n  <p>Constants can be defined in any precision. If you want the same\n  constant to be available in multiple precisions, you have to define\n  multiple constant operations.</p>\n\n  <h3>Negation</h3>\n\n  <p>Herbie's specification language has a negation function, and it's\n  usually a good idea to define a negation operation if your target\n  has one. Define it like this:</p>\n\n  <pre>(define-operation (neg.f32 [x &lt;binary64&gt;]) &lt;binary64&gt;\n    #:spec (neg x) #:impl - #:fpcore (- x) #:cost 0.125)</pre>\n\n  <p>Here, in the <code>#:spec</code>, <code>(neg x)</code> refers to\n  the negation function in Herbie's specification language, while\n  the <code>-</code> symbol after <code>#:impl</code> refers to\n  Racket's subtraction function, which also acts as a negation\n  function.</p>\n\n  <p>There is also an <code>#:fpcore</code> field. This field tells\n  Herbie how to represent this operation in FPCore (for user input and\n  output). The default <code>#:fpcore</code> is the operation's\n  <code>#:spec</code> but there are a few functions (like negation)\n  where Herbie's specification language uses a different syntax from\n  FPCore and <code>#:fpcore</code> needs to be specified manually.</p>\n\n  <h3>Precision-specific Variations</h3>\n\n  <p>If a platform supports both <code>&lt;binary32&gt;</code>\n  and <code>&lt;binary64&gt;</code>, they often support similar\n  operations:</p>\n\n  <pre>(define-operations ([x &lt;binary32&gt;]) &lt;binary32&gt;\n    #:fpcore (! :precision binary32 _)\n    [fabs.f32 #:spec (fabs x) #:impl (from-libm 'fabsf) #:cost 0.125]\n    [sin.f32  #:spec (sin x)  #:impl (from-libm 'sinf)  #:cost 4.250]\n    ...)\n  (define-operations ([x &lt;binary64&gt;]) &lt;binary64&gt;\n    #:fpcore (! :precision binary64 _)\n    [fabs.f64 #:spec (fabs x) #:impl (from-libm 'fabs)  #:cost 0.125]\n    [sin.f64  #:spec (sin x)  #:impl (from-libm 'sin)   #:cost 4.200]\n    ...)</pre>\n\n  <p>Here, two <code>define-operations</code> blocks define two sets\n  of functions with different signatures but identical specifications.\n  To disambiguate these functions in FPCore output,\n  the <code>#:fpcore</code> argument to <code>define-operations</code>\n  defines <a href=\"input.html\">different FPCore properties</a> for\n  each set of operations. In that argument, the underscore is replaced\n  by each operation's <code>#:spec</code>.</p>\n\n  <h3>Hard-to-emulate Operations</h3>\n\n  <p>Sometimes a platform will offer an operation that's difficult to\n  implement accurately. In this case, Herbie's <code>from-rival</code>\n  helper can provide a slow but correctly-rounded implementation:</p>\n\n  <pre>(define-opertion (dotprod [a &lt;binary64&gt;] [b &lt;binary64&gt;]\n                            [c &lt;binary64&gt;] [d &lt;binary64&gt;]) &lt;binary64&gt;\n  #:spec (+ (* a b) (* c d)) #:impl (from-rival) #:cost 1.25)</pre>\n\n  <p>The <code>from-rival</code> helper uses\n  the <a href=\"https://www.mpfr.org/\">MPFR</a> library to evaluate the\n  operation's specification. Compilation is usually <em>much</em>\n  slower than with a native floating-point implementation, but for\n  unusual operations that are difficult to implement otherwise, it can\n  still allow compilation to proceed. There is an\n  optional <code>#:cache?</code> argument to <code>from-rival</code>,\n  on by default. The cache makes Herbie much faster but uses a lot of\n  memory.</p>\n\n  <p>Note that <code>from-rival</code> implementations are always\n  \"correctly-rounded\", meaning as accurate as possible. Most targets\n  don't actually offer correctly-rounded operations, which can mean\n  that Herbie's outputs won't be as accurate as Herbie assumes. It's\n  always better to execute the actual operation on the actual target\n  if possible, so as to precisely emulate its actual behavior.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.3/plugins.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Other APIs</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Other Herbie APIs</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p><a href=\"../../\">Herbie</a> <a href=\"platforms.html\">platforms</a>\n  are the main way to customize Herbie's behavior. The typical\n  platform just defines the set of representations and operations that\n  available to Herbie when compiling. However, platform files can\n  technically contain arbitrary Racket code, and thus can call other\n  Herbie APIs, including importing external libraries, defining new\n  representations, and so on. This page documents such APIs. Note that\n  a level of comfort with Racket is assumed.</p>\n\n  <p>Please note that all of the APIs on this page are considered\n  unstable and may change version to version. If you run into issues,\n  please\n  <a href=\"https://github.com/uwplse/herbie/issues\">file a\n  bug</a>.</p>\n\n  <h2>Defining representations</h2>\n\n  <p><dfn>Representations</dfn> what Herbie calls different number\n  formats. They play a central role\n  in <a href=\"platforms.html\">platforms</a>. Concretely, a\n  representation is a set of Racket values that represent both real\n  numbers and bit patterns.</p>\n\n  <p>Specifically, a representation value needs to be convertible to\n  Racket <a href=\"https://docs.racket-lang.org/math/bigfloat.html\"><code>bigfloat</code></a>\n  values (which are basically MPFR floats) and also\n  to <em>ordinals</em>, meaning integers between\n  -2<sup><var>w</var>&minus;1</sup> and\n  2<sup><var>w</var>&minus;1</sup>&minus;1 for some bit width <var>w</var>.</p>\n\n  <p>Create representations with <code>make-representation</code>:</p>\n\n  <code>\n  <table>\n    <tr><td colspan=2>(<b>make-representation</b></td></tr>\n    <tr><td></td><td>#:name <var>name</var></td></tr>\n    <tr><td></td><td>#:total-bits <var>width</var></td></tr>\n    <tr><td></td><td>#:bf->repr <var>bf->repr</var></td></tr>\n    <tr><td></td><td>#:repr->bf <var>repr->bf</var></td></tr>\n    <tr><td></td><td>#:ordinal->repr <var>ordinal->repr</var></td></tr>\n    <tr><td></td><td>#:repr->ordinal <var>repr->ordinal</var></td></tr>\n    <tr><td></td><td>#:special-value? <var>special?</var>)</td></tr>\n  </table>\n  </code>\n\n  <p>The <code>#:name</code> should be either a symbol, or a list\n  containing symbols and integers. The <code>#:total-bits</code> value\n  should be a positive integer. The <code>#:total-bits</code>\n  parameter determines the total ordinal range your format takes up,\n  not just its significand range, so for example for double-precision\n  floats you need a <code>#:total-bits</code> of 64.</p>\n\n  <p>The <code>#:bf->repr</code> and <code>#:repr->bf</code> values\n  should be that convert between representation values and Racket\n  bigfloats. The <code>repr->bf</code> function should use as large a\n  bigfloat precision as needed to exactly represent the value, while\n  the <code>bf->repr</code> function should round as per the current\n  value of\n  the <a href=\"https://docs.racket-lang.org/math/bigfloat.html#%28def._%28%28lib._math%2Fbigfloat..rkt%29._bf-rounding-mode%29%29\">bf-rounding-mode</a>\n  parameter.</p>\n\n  <p>All non-NaN bigfloat values should result in non-NaN\n  representation values. For example, <code>(bf->repr (bf\n  \"1e1000000\"))</code> should yield the largest real value in the\n  representation. Infinite values, as in <code>(bf->repr\n  +inf.bf)</code>, should be interpreted as really large real values,\n  not as infinite values. For example,\n  the <a href=\"https://posithub.org/\">posit</a> format has an\n  \"infinite\" value, but it behaves more like a NaN, so converting\n  bigfloat infinity to a posit should yield its largest real value\n  instead.</p>\n\n  <p>The <code>#:ordinal->repr</code> and <code>#:repr->ordinal</code>\n  functions represent ordinals as Racket integers between\n  -2<sup><var>width</var>&minus;1</sup> (inclusive) and\n  2<sup><var>width</var>&minus;1</sup> (exclusive). Ordinals\n  must be in real-number order; that is, if <code>(repr->bf x)</code>\n  is less than <code>(repr->bf y)</code>, then <code>(repr->ordinal\n  x)</code> should be less than <code>(repr->ordinal y)</code>.</p>\n\n  <p>The <code>#:special</code> function should return true for NaN\n  values (or whatever your representation calls values that don't\n  represent any real number) and false for all other values. Special\n  values can be anywhere in the ordinal range, and you can have as\n  many or as few of them as you want.</p>\n\n  <p><code>make-representation</code> returns a representation object,\n  which you can then use\n  in <a href=\"platforms.html\"><code>define-representation</code>\n  and <code>define-operation</code></a>.</p>\n\n  <h2>Defining Generators</h2>\n\n  <p><dfn>Generators</dfn> are helper functions for generating\n  implementations in <code>define-operation</code>. For example,\n  <a href=\"platforms.html\"><code>from-ffi</code></a> is a\n  generator.</p>\n\n  <p>To define a generator, use <code>define-generator</code>:</p>\n\n  <code><table>\n  <tr><td colspan=2>(<b>define-generator</b> ((from-<var>foo</var> <var>args</var> ...) spec ctx)</td></tr>\n  <tr><td></td><td><var>body</var> ...)</td></tr>\n  </table></code>\n\n  <p>Here, <code>from-<var>foo</var></code> is the name of your\n  generator, and <var>args</var> are any additional arguments the\n  generator takes. For example, <code>from-libm</code> takes one\n  argument, the symbol name, while <code>from-ffi</code> takes an open\n  library and a symbol name.</p>\n\n  <p>Then, inside the <var>body</var>, you can use those arguments as\n  well as <code>spec</code> and <code>ctx</code>, to construct an\n  actual implementation function.</p>\n\n  <p>The specification <code>spec</code> is a Racket tree made up of\n  lists and symbols and numbers.</p>\n\n  <p>The signature <code>ctx</code> is \"context\" object; you can\n  access its <code>context-repr</code> to get the operation's output\n  representation, its <code>context-vars</code> to access its variable\n  names (as a list of symbols), and its <code>context-var-reprs</code>\n  to access its input representations (as a parallel list of\n  representations). The <code>context-lookup</code> function can be\n  used to look up a input argument's representation by name.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.3/release-notes.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie 2.2 Release Notes</title>\n  <link rel='stylesheet' type='text/css' href=\"../../main.css\">\n  <script src=\"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML\"></script>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <style>\n    .showcase { margin: 1em 0; }\n    .showcase.side-by-side { display: flex; gap: 1em; }\n    .showcase.side-by-side :nth-child(1) { width: 60%; }\n    .showcase.side-by-side :nth-child(2) { flex-grow: 1; hyphens: auto; }\n    #team {\n        display: block; box-sizing: border-box; width: 100%;\n        border-radius: 2em; border: 3px solid black;\n    }\n  </style>\n</head>\n<body>\n  <header>\n    <h1>Herbie 2.2 Release Notes</h1>\n    <a href=\"../..\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>The <a href=\"../..\">Herbie</a> developers are excited to announce\n  Herbie 2.2! This release focuses extensible compilation targets\n  using <i>platforms</i>.</p>\n\n  <p><b>What is Herbie?</b> Herbie compiles mathematical expressions\n  to fast and accurate floating point programs, avoiding the bugs,\n  errors, and surprises of floating point arithmetic.\n  Visit <a href=\"../..\">the main page</a> to learn more.</p>\n  \n  <!--<img src=\"team.png\" id=\"team\" alt=\"The Herbie 2.2 team at UW and U of U\" />-->\n\n  <h2>Releasing the Platforms API</h2>\n\n  <figure class=\"showcase\">\n    <pre>(define-operation (cosd [x &lt;binary64&gt;]) &lt;binary64&gt;\n          #:spec (cos (* x (/ (PI) 180)))\n          #:impl (from-rival)\n          #:cost 12.5)</pre>\n\n    <figcaption>\n      Herbie 2.2's <a href=\"platforms.html\">platforms</a> allow you to\n      define custom compilation targets, including novel hardware\n      (CPUs, GPUs, FPGAs, TPUs), programming languages (Julia, Matlab,\n      Fortran), or software libraries (Numpy, Eigen, cuBLAS).\n      Platforms can define new number formats, new floating-point\n      operations on those formats, and new cost models for those\n      operations. Herbie will automatically optimize its results for\n      your platform.\n    </figcaption>\n  </figure>\n\n  <p>\n  Last year, <a href=\"../2.1/release-notes.html\">Herbie 2.1</a>\n  included the beginnings of <i>platforms</i>, Herbie's API for\n  multiple backends. We've simplified and improved this API, and are\n  now ready to release it.</p>\n  \n  <p>In short, platforms allow you define the functions Herbie is\n  allowed to use when compiling floating-point programs. A platform\n  can expose Python's <code>fsum</code>, Julia's <code>cosd</code>, or\n  AVX's <code>rcpps</code> to Herbie, which can then use those\n  functions to produce even faster and more accurate output.\n  Our <a href=\"../papers.html\">recent publications</a> demonstrate\n  dramatic accuracy and performance improvements using platforms.</p>\n\n  <p>Platforms are a large change, and we invite users to try it out.\n  The <a href=\"platforms.html\">platforms documentation</a> explains\n  how to select different built-in platforms, or even how to write\n  your own.</p>\n  \n  <p>Besides the new feature, platforms allow us to deprecate a\n  variety of now-superseded features:</p>\n\n  <ul>\n    <li>The default platform now uses a realistic, auto-tuned cost\n    model which should lead to faster code in practice.</li>\n\n    <li>The Herbie 2.0 and 2.1 cost models are replaced by\n    the <code>herbie20</code> platform.</li>\n\n    <li>The <code>--no-pareto</code> flag is replaced by\n    the <code>herbie10</code> platform.</li>\n\n    <li>Plugins are now replaced by ordinary Racket libraries imported\n    directly by plugins.</li>\n    \n    <li>Preprocessing is now replaced by standard platform-provided\n    functions such\n    as <code>fmin</code>, <code>fmax</code>, <code>fabs</code>,\n    and <code>copysign</code>.</li>\n  </ul>\n\n  <h2>Restructuring the Main Loop</h2>\n  \n  <figure class=\"showcase\">\n    <img src=\"system-2.2.png\"\n         alt=\"The new Herbie main loop.\n              The simplify step and patch table have been removed,\n              while the compute phase has been added.\">\n    <figcaption>\n      The Herbie main loop is dramatically simplified, with no\n      separate simplify or localize phase and a new compute phase that\n      aid with hard-to-compute constants.\n    </figcaption>\n  </figure>\n\n  <p>We've overhauled the Herbie main loop, which is the high-level\n  algorithm that invokes different Herbie sub-systems to generate and\n  filter different candidate programs. This overhaul both introduces\n  new systems, which should make Herbie more capable, and reduce\n  duplicative work, dramatically speeding up Herbie. Specifically:</p>\n\n  <ul>\n    <li>A new compute phase was added, which replaces variable-free\n      subexpressions with constants. The constants are computed using\n      high-precision arithmetic and are guaranteed to be exact.</li>\n    <li>The simplification phase was removed. This phase mostly\n      duplicated work already done by the rewrite phase, so removing it\n      had very little impact on performance and accuracy of generated\n      code, but reduced Herbie runtime significantly.</li>\n    <li>The localize phase was also removed. This phase existed to\n      reduce duplicate work in other phases; batches deduplicate the\n      work automatically so localize is no longer needed. Removing this\n      phase also significantly sped up Herbie.</li>\n    <li>Minor phases like initial and final simplify were removed as\n      well. Most importantly, this allowed replacing the existing,\n      complex \"accelerator\" API (never fully released) and replace it\n      with the much simpler \"platform\" API.</li>\n    <li>Herbie more correctly tracks Taylor approximations inside\n      Herbie, and will now avoid making \"approximations to\n      approximations\" leading to runaway error in rare cases.</li>\n  </ul>\n      \n\n  <h2>Flattening Expressions to Batches</h2>\n\n  <figure class=\"showcase side-by-side\">\n    <pre>%0 = x\n%1 = (literal 1)\n%2 = (+ %0 %1)\n%3 = (* %2 %2)\n%4 = (- %3 %1)\n%5 = (neg %2)\n%6 = (* %5 %5)\n%7 = (- %6 %1))</pre>\n    <figcaption>\n      An example of a batch, containing two expressions (and their\n      subexpressions): <code>(x + 1)<sup>2</sup> - 1</code>\n      and <code>(-(x + 1))<sup>2</sup> - 1</code>. Shared\n      subexpressions are only represented once in the batch, and are\n      only processed once by Herbie.\n    </figcaption>\n  </figure>\n\n  <p>We have also changed Herbie's main data structure for\n  representing programs. Until now, Herbie represented programs via\n  their abstract syntax tree. While simple and effective, this\n  representation lead to processing identical subexpressions\n  repeatedly. This was especially problematic for larger programs,\n  which can sometimes have the same subexpression appear exponentially\n  many times.</p>\n\n  <p>The batch data structure instead uses a flat array with\n  back-references to represent programs, which means that duplicate\n  subexpressions appear and are processed just once. This lead to\n  significant speedups throughout Herbie:</p>\n\n  <ul>\n    <li>Batches automatically deduplicates identical candidate\n      programs, which occur when multiple Herbie phases produce the\n      same output. There were a lot more of these than we thought; in\n      some cases as much as 25&times; deduplication occurs.</li>\n    <li>The series phase, now uses batches internally, allowing Herbie\n      to consider many more series expansions.</li>\n    <li>Herbie's FFI layer for interacting with\n      the <a href=\"https://egraphs-good.github.io/\">egg</a> library now\n      leverages batches to reduce time spent copying data in and out of\n      egg.</li>\n    <li> In some cases, one batch is shared across multiple phases\n      (like evaluation and pruning), reducing duplication even\n      further.</li>\n    <li>The derivations phase was dramatically sped up by caching\n      proof objects across multiple candidate programs. Additionally,\n      a debugging pass called \"soundiness\" was removed entirely, since\n      the problems it was built to debug no longer occur. Thanks to\n      both changes, derivations take almost no time at all any\n      more.</li>\n  </ul>\n\n  <h2>Sister Projects</h2>\n  \n  <p>\n    The <a href=\"https://github.com/herbie-fp/odyssey\">Odyssey\n      numerics workbench</a> is releasing version 1.2 today, featuring\n      a new \"local error\" component and various design tweaks and\n      improvements. Odyssey can be tried from\n      its <a href=\"https://herbie-fp.github.io/odyssey/\">online\n      demo</a> or installed locally from\n      the <a href=\"https://marketplace.visualstudio.com/items?itemName=herbie-fp.odyssey-fp\">VS\n      Code Marketplace</a>.\n  </p>\n  \n  <p>\n    The <a href=\"https://github.com/herbie-fp/rival\">Rival\n    real-arithmetic package</a> is releasing version 2.2 today,\n    including various tweaks, optimizations, and improvements. Most\n    significantly, a new \"hints\" feature significantly speeds up\n    sampling expressions that\n    use <code>fmin</code>, <code>fmax</code>, and <code>if</code>.\n  </p>\n\n  <h2>Other improvements</h2>\n\n  <ul>\n    <li>Herbie now offers a basic <a href=\"api-endpoints.html\">HTTP\n        API</a>, including both synchronous and asynchronous jobs and\n      access to various internal Herbie features. This HTTP API is a\n      work in progress and is primarily built to support Odyssey.\n      However, our work on the API has also enabled the\n      standard <a href=\"using-web.html\">Herbie web interface</a> to\n      support <a href=\"options.html\">threads</a>, which should make\n      Herbie faster in a lot of common use cases.</li>\n    <li>Small quality-of-life changes have been made to the Herbie\n      reports, including hiding duplicate alternatives, updating\n      various dependencies, and generating the reports more\n      quickly.</li>\n    <li>Optional, off-by-default support for\n      the <a href=\"https://github.com/egraphs-good/egglog\">egglog</a>\n      rewriting engine has been added. We are excited about growth and\n      competition among rewrite engines and hope to continue driving\n      forward this research area.</li>\n    <li>Fixing a variety of small bugs, such as nondeterminism due to\n      an incorrect type signature for <code>fma</code> and new rewrite\n      rules to unlock more accurate results.</li>\n    <li>Many general-purpose cleanups, including removing a lot of\n      now-unnecessary nightly infrastructure, adoption of a new\n      formatting guideline, reorganization of the source code, and new\n      debug infrastructure.</li>\n  </ul>\n\n  <h2>Try it out!</h2>\n\n  <p>\n    We want Herbie to be more useful to scientists, engineers, and\n    programmers around the world. We've got a lot of features we're\n    excited to work on in the coming months. Please\n    <a href=\"https://github.com/herbie-fp/herbie/issues\">report bugs</a>\n    or <a href=\"https://github.com/herbie-fp/herbie\">contribute</a>.\n  </p>\n  <br>\n  <p style=\"font-weight: bold; text-align: center;\">If you find Herbie\n  useful, <a href=\"mailto:herbie@cs.washington.edu\">let us know!</p>\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.3/report.html",
    "content": "<!doctype html>\n<html>\n\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie reports</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n\n<body>\n  <header>\n    <h1>Herbie reports</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>When used <a href=\"using-web.html\">in the browser</a>, Herbie\n    generates HTML reports full of information about the accuracy and relative \n    speed of the initial and alternative expressions.</p>\n\n  <h2 id=\"links\">Summary and Additional links</h2>\n\n  <p>The top of the report page has a right-hand menu bar with\n    additional links. “Metrics” give you detailed internal information\n    about Herbie, while “Report”, if present, takes you back to the\n    full Herbie report.</p>\n\n  <p>Below the menu lies a brief summary of the results. Herbie can\n    produce multiple alternatives to the initial program, and this\n    summary gives their basic statistics.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-large.png\" />\n    <figcaption>Summary numbers from a Herbie report.</figcaption>\n  </figure>\n\n  <dl>\n    <dt>Percentage Accurate</dt>\n    <dd>The <a href=\"errors.html\">percentage accuracy</a> of the\n    initial program and what Herbie thinks is its most accurate\n    alternative.</dd>\n    <dt>Time</dt>\n    <dd>The time it took Herbie to generate all of the alternatives.</dd>\n    <dt>Alternatives</dt>\n    <dd>The number of alternatives found.</dd>\n    <dt>Speedup</dt>\n    <dd>The speed, relative to the initial program,\n    of the fastest alternative that improves accuracy.</dd>\n  </dl>\n\n  <h2 id=\"spec\">Specification</h2>\n\n  <p>Next, the specification that you gave to Herbie. This section is\n    closed by default. Typically, the specification is also the\n    initial program, but in some cases, like if\n    the <a href=\"input.html\"><kbd>:spec</kbd> property</a> is used,\n    they can differ. The specification also includes\n    any <a href=\"input.html#preconditions\">preconditions</a> given to\n    Herbie.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"specification.png\" />\n  </figure>\n\n  <p>You can use the drop-down in the top left to display the\n  specification in an alternative syntax.</p>\n\n  <!-- Colors copied from src/web/resources/report.css -->\n  <h2 id=\"graph\">Local Percentage Accuracy graph</h2>\n\n  <p>\n    Next, the <em>Local Percentage Accuracy</em> graph compares the\n    accuracy of the initial program to Herbie's most accurate\n    alternative. This is helpful for understanding the sorts of inputs\n    Herbie is improving accuracy on. Sometimes, Herbie improved\n    accuracy on some inputs at the cost of accuracy on other inputs\n    that you care more about. You can add a\n    <a href=\"input.html#preconditions\">precondition</a> to restrict Herbie to \n    the more important inputs in that case.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-accuracy.png\" />\n  </figure>\n\n  <p>In the plot, each individual sampled point is shown with a faint\n    circle, and the thick line is moving average of those individual\n    samples. The red line is the initial program and the blue line is\n    Herbie's most accurate alternative.</p>\n  \n  <p>Accuracy is shown on the vertical axis, and higher is better. The\n    horizontal axis shows one of the variables in the input program;\n    the dropdown in the title switches between input variables. The\n    checkboxes below the graph toggle the red and blue lines on and\n    off.</p>\n\n  <p>If Herbie decided to insert an <code>if</code> statement into the\n    program, the locations of those <code>if</code> statements will be\n    marked with vertical bars.</p>\n\n  <h2 id=\"cost-accuracy\">Accuracy vs Speed</h2>\n  <p>Next, a Pareto graph and table list the alternatives Herbie\n    found.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-cost-accuracy.png\" />\n  </figure>\n\n  <p>Both the plot and the table show the same data. In the plot,\n  accuracy is on the vertical axis and speedup is on the horizontal\n  axis. Up and to the right is better. The initial program is shown\n  with a red square, while each of Herbie's alternatives is shown with\n  a blue circle. A faint line shows the Pareto frontier&mdash;that is,\n  it goes through all Herbie alternatives that maximize speed for\n  their level of accuracy. Some of Herbie's alternatives may not be on\n  the Pareto frontier due to differences between the training and test\n  set.</p>\n\n  <p>In the table, each alternative is shown along with its accuracy\n  and speed relative to the initial program. Values are green if they\n  are better than the initial program, and black otherwise. Each\n  alternative is linked to its description lower on the page.</p>\n\n  <h2 id=\"alternatives\">Initial program and Alternatives</h2>\n\n  <p>Below the table come a series of boxes detailing the initial\n    program and each of Herbie's alternatives, along with their\n    accuracy and relative speed.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-alternative.png\" />\n  </figure>\n\n  <p>The accuracy and relative speed of each alternative is given in\n    the title. Below the title, the alternative expression itself is\n    given. The dropdown in the top right can be used to change the\n    syntax used. If Herbie could not come up with anything better than\n    the initial program, no alternatives are displayed.</p>\n\n  <p>Each alternative also has a derivation, which can be shown by\n    clicking on \"Derivation\". The derivation shows each step Herbie\n    took to transform the initial program into this alternative. The\n    initial program has no derivation.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-alternative-derivation.png\" />\n  </figure>\n\n  <p>Each step in the derivation gives the accuracy after that step.\n    Sometimes you can use that to pick a less-complex and\n    not-substantially-less-accurate program. The derivation will also\n    call out any case splits. When a part of the step is colored blue,\n    that identifies the changed part of the expression.</p>\n\n  <p>Derivations may also contain \"step-by-step derivations\"; you can\n  click on those step-by-step derivations to expand them. Each step in\n  the step-by-step derivation names an arithmetic law from Herbie's\n  database, with <kbd>metadata-eval</kbd> meaning that Herbie used\n  direct computation in a particular step.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-step-by-step.png\" />\n  </figure>\n\n  <p>Derivations are intended to give you more confidence in Herbie's\n  results and are not guaranteed to be an accurate reflection of\n  Herbie's internal process of constructing an alternative.</p>\n\n  <h2 id=\"reproduction\">Reproduction</h2>\n\n  <p>Finally, Herbie gives a command you can run to reproduce its\n    result. If you find a Herbie bug, include this code snippet when\n    <a href=\"https://github.com/uwplse/herbie/issues\">filing an issue</a>.</p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-reproduce.png\" />\n  </figure>\n\n  <p>We expect the report to grow more informative with future\n    versions. Please <a href=\"mailto:herbie@cs.washington.edu\">get in\n      touch</a> if there is more information you'd like to see.</p>\n\n</body>\n\n</html>\n"
  },
  {
    "path": "www/doc/2.3/toc.js",
    "content": "function make_toc() {\n    var headings = document.querySelectorAll(\"h2\");\n    var toc = document.createElement(\"nav\");\n    toc.classList.add(\"toc\")\n    var list = document.createElement(\"ul\");\n    for (var i = 0; i < headings.length; i++) {\n        var li = document.createElement(\"li\");\n        var a = document.createElement(\"a\");\n        var h = headings[i];\n        if (! h.id) {\n            h.setAttribute(\"id\", \"heading-\" + i);\n        }\n        a.setAttribute(\"href\", \"#\" + h.id);\n        a.innerHTML = h.innerHTML;\n        li.appendChild(a);\n        list.appendChild(li);\n    }\n    toc.appendChild(list);\n    headings[0].parentNode.insertBefore(toc, headings[0]);\n}\n\nwindow.addEventListener(\"load\", make_toc);\n"
  },
  {
    "path": "www/doc/2.3/tutorial.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie Tutorial</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Herbie Tutorial</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>\n    <a href=\"../../\">Herbie</a> rewrites floating point expressions to\n      make them more accurate. Floating point arithmetic is\n      <a href=\"error.html\">inaccurate</a>; even 0.1 + 0.2 ≠ 0.3 in\n      floating-point. Herbie helps find and fix these mysterious\n      inaccuracies.\n  </p>\n\n  <p>\n    To get started, <a href=\"installing.html\">download and install</a>\n    Herbie. You're then ready to begin using it.\n  </p>\n\n  <h2>Giving Herbie expressions</h2>\n\n  <p>Start Herbie with:</p>\n\n  <pre class=\"shell\">racket -l herbie web</pre>\n  \n  <p>Alternatively, if you added <code>herbie</code> to the path, you\n  can always replace <code>racket -l herbie</code> with\n  just <code>herbie</code>.</p>\n\n  <p>\n    After a brief wait, your web browser should open and show you\n    Herbie's main window. The most important part of the page is this\n    bit:\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"web-input.png\" alt=\"The program input field in the Herbie web UI.\"/>\n  </figure>\n\n  <p>\n    Let's start by just looking at an example of Herbie running.\n    Click \"Show an example\". This will pre-fill the expression\n    <kbd>sqrt(x + 1) - sqrt(x)</kbd>\n    with <code>x</code> ranging from to <kbd>0</kbd> and <kbd>1.79e308</kbd>.\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"range-input.png\" alt=\"The input range field in the Herbie web UI.\"/>\n  </figure>\n\n  <p>\n    Now that you have an expression and a range for each variable,\n    click the \"Improve with Herbie\" button. You should see the entry\n    box gray out, and shortly thereafter some text should appear\n    describing what Herbie is doing. After a few seconds, you'll be\n    redirected to a page with Herbie's results.\n  </p>\n\n  <p>\n    The very top of this results page gives some quick statistics\n    about the alternative ways Herbie found for evaluating this\n    expression:\n  </p>\n\n  <figure>\n    <img width=\"100%\" src=\"report-large.png\" alt=\"Statistics and error measures for this Herbie run.\" />\n  </figure>\n\n  <p>\n    Here, you can see that Herbie's most accurate alternative has an\n    accuracy of 99.7%, much better than the initial program's 53.2%,\n    and that in total Herbie found 5 alternatives. One of those\n    alternatives is both more accurate than the original expression\n    and also 1.9&times; faster. The <a href=\"report.html\">rest of the\n    result page</a> shows each of these alternatives, including\n    details like how they were derived. These details are all\n    <a href=\"report.html\">documented</a>, but for the sake of the\n    tutorial let's move on to a more realistic example.\n  </p>\n\n  <h2>Programming with Herbie</h2>\n\n  <p>\n    You can use Herbie on expressions from source code, mathematical\n    models, or debugging tools. But most users use Herbie as they\n    write code, asking it about any complex floating-point expression\n    they write. Herbie has <a href=\"options.html\">options</a> to log\n    all the expressions you enter so that you can refer to them later.\n  </p>\n\n  <p>But to keep the tutorial focused, let's suppose you're instead\n    tracking down a floating-point bug in existing code. Then you'll\n    need to start by identifying the problematic floating-point\n    expression.</p>\n\n  <p>To demonstrate the workflow, let's walk through\n    <a href=\"https://github.com/josdejong/mathjs/pull/208\">bug 208</a>\n    in <a href=\"http://mathjs.org\">math.js</a>, a math library for\n    JavaScript. The bug deals with inaccurate square roots for complex\n    numbers. (For a full write-up of the bug itself, check out\n    a <a href=\"https://pavpanchekha.com/blog/casio-mathjs.html\">blog\n    post</a> by one of the Herbie authors.)\n  </p>\n\n  <h2>Finding the problematic expression</h2>\n\n  <p>\n    In most programs, there's a small kernel that does the mathematical\n    computations, while the rest of the program sets up parameters,\n    handles control flow, visualizes or prints results, and so on. The\n    mathematical core is what Herbie will be interested in.\n  </p>\n\n  <p>\n    For our example, let's start\n    in <a href=\"https://github.com/josdejong/mathjs/tree/master/lib/function\"><code>lib/function/</code></a>.\n    This directory contains many subdirectories; each file in each\n    subdirectory defines a collection of mathematical functions. We're\n    interested in the complex square root function, which is defined in\n    <a href=\"https://github.com/josdejong/mathjs/blob/da306e26ed34272db44e35f07a3b015c0155d99a/lib/function/arithmetic/sqrt.js\"><code>arithmetic/sqrt.js</code></a>.\n  </p>\n\n  <p>\n    This file handles argument checks, different types, and error\n    handling, for both real and complex square roots. None of that is\n    of interest to Herbie; we want to extract just the mathematical\n    core. So skip down to the <code>isComplex(x)</code> case:\n  </p>\n\n  <pre>var r = Math.sqrt(x.re * x.re + x.im * x.im);\nif (x.im &gt;= 0) {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}\nelse {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      -0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}</pre>\n\n  <p>This is the mathematical core that we want to send to Herbie.</p>\n\n  <h2>Converting problematic code to Herbie input</h2>\n\n  <p>\n    In this code, <code>x</code> is of type <code>Complex</code>, a\n    data structure with multiple fields. Herbie only deals with\n    floating-point numbers, not data structures, so we will treat the\n    input <code>x</code> as two separate inputs to\n    Herbie: <code>xre</code> and <code>xim</code>. We'll also pass\n    each field of the output to Herbie separately.\n  </p>\n\n  <p>\n    This code also branches between non-negative <code>x.im</code> and\n    negative <code>x.im</code>. It's usually better to send each\n    branch to Herbie separately. So in total, this code turns into four\n    Herbie inputs: two output fields, for each of the two branches.\n  </p>\n\n  <p>Let's focus on the first field of the output for the case of\n  non-negative <code>x.im</code>.</p>\n\n  <p>The variable <code>r</code> is an intermediate variable in this\n  code block. Intermediate variables provide Herbie with crucial\n  information that Herbie can use to improve accuracy, so you want to\n  expand or inline them. The result looks like this:</p>\n\n  <pre>0.5 * sqrt(2.0 * (sqrt(xre * xre + xim * xim) + xre))</pre>\n\n  <p>Recall that this code is only run when <code>x.im</code> is\n  non-negative (but it runs for all values of <code>x.re</code>). So, \n  select the full range of values for <code>x.re</code>, but restrict\n  the range of <code>x.im</code>, like this: \n  \n  <figure>\n    <img width=\"100%\" src=\"range-input-2.png\" alt=\"Restricting the input range to xim >= 0.\" />\n  </figure>\n  \n  This asks Herbie to consider only non-negative values\n  of <code>xim</code> when improving the accuracy of this expression.\n  The number <code>1.79e308</code> is approximately the largest\n  double-precision number, and will auto-complete.</p>\n  \n  <h2>Herbie's results</h2>\n\n  <p>Herbie will churn for a few seconds and produce a results page.\n    In this case, Herbie found 4 alternatives, and we're interested in\n    the most accurate one, which should have an\n    <a href=\"error.html\">accuracy of 84.6%:</a></p>\n\n  <figure>\n    <img width=\"100%\" src=\"problematic-highlight.png\" />\n  </figure>\n\n  <p>Below these summary statistics, we can see a graph of accuracy\n  versus input value. By default, it shows accuracy\n  versus <code>xim</code>; higher is better:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"problematic-xim.png\" />\n  </figure>\n\n  <p>The drop in accuracy once <code>xim</code> is bigger than\n  about <code>1e150</code> really stands out, but you can also see\n  that Herbie's alternative more accurate for smaller <code>xim</code>\n  values, too. You can also change the graph to plot accuracy\n  versus <code>xre</code> instead:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"problematic-xre.png\" />\n  </figure>\n\n  <p>This plot makes it clear that Herbie's alternative is almost\n  perfectly accurate for positive <code>xre</code>, but still has some\n  error for negative <code>xre</code>.\n\n  <p>Herbie also found other alternatives, which are less accurate but\n  might be faster. You can see a summary in this table:</p>\n\n  <figure>\n    <figcaption></figcaption>\n    <img width=\"100%\" src=\"problematic-pareto-table.png\" />\n  </figure>\n\n  <p>Herbie's algorithm is randomized, so you likely won't see the\n  exact same thing; you might see more or fewer alternatives, and they\n  might be more or less accurate and fast. That said, the most\n  accurate alternative should be pretty similar.</p>\n\n  <p>That alternative itself is shown lower down on the page:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"problematic-improved-accuracy.png\" />\n  </figure>\n\n  <p>A couple features of this alternative stand out immediately.\n  First of all, Herbie inserted an <code>if</code> statement.\n  This <code>if</code> statement handles a phenomenon known as\n  cancellation, and is part of why Herbie's alternative is more\n  accurate. Herbie also replaced the square root operation with\n  the <code>hypot</code> function, which computes distances more\n  accurately than a direct square root operation.</p>\n\n  <p>If you want to see more about how Herbie derived this result, you\n  could click on the word \"Derivation\" to see a detailed, step-by-step\n  explanation of how Herbie did it. For now, though, let's move on to\n  look at another alternative.</p>\n  \n  <p>The fifth alternative suggested by Herbie is much less accurate,\n  but it is about twice as fast as the original program:</p>\n\n  <figure>\n    <img width=\"100%\" src=\"problematic-improved-speed.png\" />\n  </figure>\n  \n  <p>This alternative is kind of strange: it has two branches, and\n  each one only uses one of the two variables <code>xre</code>\n  and <code>xim</code>. That explains why it's fast, but it's still\n  more accurate than the initial program because it avoids\n  cancellation and overflow issues that plagued the original.</p>\n  \n  <h2>Using Herbie's alternatives</h2>\n  \n  <p>In this case, we were interested in the most accurate possible\n  implementation, so let's try to use Herbie's most accurate\n  alternative.</p>\n\n  <pre>\n// Herbie 2.1 for:\n//   0.5 * sqrt(2.0 * (sqrt(xre*xre + xim*xim) + xre))\nvar r = Math.hypot(x.re, x.im);\nvar re;\nif (xre + r <= 0) {\n    re = 0.5 * Math.sqrt(2 * (x.im / (x.re / x.im) * -0.5));\n} else {\n    re = 0.5 * Math.sqrt(2 * (x.re + r));\n}\nif (x.im &gt;= 0) {\n  return new Complex(\n      re,\n      0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}\nelse {\n  return new Complex(\n      0.5 * Math.sqrt(2.0 * (r + x.re)),\n      -0.5 * Math.sqrt(2.0 * (r - x.re))\n  );\n}</pre>\n\n  <p>Note that I&apos;ve left the Herbie query in a comment. As Herbie\n  gets better, you can re-run it on this original expression to see if\n  it comes up with improvements in accuracy.</p>\n\n  <p>By the way, for some languages, including JavaScript, you can use\n  the drop-down in the top-right corner of the alternative block to\n  translate Herbie&apos;s output to that language. However, you will\n  still probably need to refactor and modify the results to fit your\n  code structure, just like here.</p>\n\n  <h2>Next steps</h2>\n\n  <p>With this change, we&apos;ve made this part of the complex square\n  root function much more accurate, and we could repeat the same steps\n  for the other branches and other fields in this program. You now\n  have a pretty good understanding of Herbie and how to use it.\n  Please <a href=\"mailto:herbie@cs.washington.edu\">let us know</a> if\n  Herbie has helped you, and check out\n  the <a href=\"../../doc.html\">documentation</a> to learn more about\n  Herbie&apos;s various options and outputs.</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.3/using-cli.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie from the Command Line</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>Shell and Batch Mode</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p>Herbie can be used from the command-line or\n  from <a href=\"using-web.html\">the browser</a>. This page covers\n  using Herbie from the command line.</p>\n\n  <h2 id=\"interactive\">The Herbie shell</h2>\n\n  <p>The Herbie shell lets you interact with Herbie: you type in input\n  expressions and Herbie prints their more accurate versions. Run the\n  Herbie shell with this command:</p>\n\n  <pre class=\"shell\">racket -l herbie shell\nStarting Herbie 2.2 with seed 2098242187\nFind help on https://herbie.uwplse.org/, exit with Ctrl-D\n<strong>herbie&gt;</strong> </pre>\n\n\n  <p>Herbie prints a seed, which you can <a href=\"options.html\">use to\n  reproduce</a> a Herbie run, and links you to documentation. Then, it\n  waits for inputs, which you can type directly into your terminal\n  in <a href=\"input.html\">FPCore format</a>:</p>\n\n  <pre><strong>herbie&gt;</strong> (FPCore (x) (- (+ 1 x) x))\n(FPCore (x)\n  <var>...</var>\n  1.0)</pre>\n\n  <p>Herbie suggests that <code>1.0</code> is more accurate than the\n  original expression <code>(- (+ 1 x) x)</code>. The\n  the <var>...</var> elides\n  <a href=\"input.html#properties\">additional information</a> provided\n  by Herbie.</p>\n\n  <p>The Herbie shell only shows Herbie's most accurate variant.</p>\n\n  <h2 id=\"batch\">Batch processing FPCores</h2>\n\n  <p>Alternatively, you can run Herbie on a file with multiple\n  expressions in it, writing Herbie's versions of each to a file. This\n  mode is intended for use by scripts.</p>\n\n  <pre class=\"shell\">racket -l herbie improve bench/tutorial.fpcore out.fpcore\nStarting Herbie 2.2 with seed 1139794558...\nWarning: 75.2% of points produce a very large (infinite) output. You may want to add a precondition.\nSee &lt;<a href=\"https://herbie.uwplse.org/doc/2.0/faq.html#inf-points\">https://herbie.uwplse.org/doc/2.0/faq.html#inf-points</a>&gt; for more.</pre>\n\n  <p>The output file <code>out.fpcore</code> contains more accurate\n  versions of each program:</p>\n\n  <pre>;; seed: 1139794558\n\n(FPCore (x)\n  :name \"Cancel like terms\"\n  <var>...</var>\n  1.0)\n\n(FPCore (x)\n  :name \"Expanding a square\"\n  <var>...</var>\n  (fma x x (+ x x)))\n\n(FPCore (x y z)\n  :name \"Commute and associate\"\n  <var>...</var>\n  0.0)</pre>\n\n  <p>\n    Note that output file is in the same order as the input file. For\n    more control over Herbie, see the documentation of\n    Herbie's <a href=\"options.html\">command-line options</a>.\n  </p>\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc/2.3/using-web.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Using Herbie from the Browser</title>\n  <link rel='stylesheet' type='text/css' href='../../main.css'>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <script type=\"text/javascript\" src=\"toc.js\"></script>\n</head>\n<body>\n  <header>\n    <h1>The Browser UI</h1>\n    <a href=\"../../\"><img class=\"logo\" src=\"../../logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"../../demo/\">Try</a></li>\n        <li><a href=\"installing.html\">Install</a></li>\n        <li><a href=\"tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n\n  <p><a href=\"../../\">Herbie</a> rewrites floating point expressions\n  to make them more accurate. Herbie can be used\n  from <a href=\"using-cli.html\">the command-line</a> or from the\n  browser; this page is about using Herbie from the browser.</p>\n\n\n  <h2 id=\"interactive\">The Herbie web shell</h2>\n\n  <p>The Herbie web shell lets you interact with Herbie through your\n  browser, featuring a convenient input format. The web shell is the\n  friendliest and easiest way to use Herbie.</p>\n\n  <p>Start the Herbie web shell by running:</p>\n\n  <pre class=\"shell\">racket -l herbie web</pre>\n\n  <p>After a few seconds, the web shell will start up and direct your\n  browser to Herbie:</p>\n  \n  <pre class=\"shell\">racket -l herbie web\nStarting Herbie 2.2 with seed 1003430182\nYour Web application is running at http://localhost:8000/.\nStop this program at any time to terminate the Web Server.</pre>\n\n  <figure>\n    <img width=\"100%\" src=\"web-main.png\" alt=\"A screenshot of the Herbie web shell main page.\"/>\n  </figure>\n\n  <p>You can type an input expressions in\n  <a href=\"input.html\">standard mathematical syntax</a>. After typing\n  in an expression, you will be asked to specify the range of values\n  for each input variable. Once you're done, hit the \"Improve with\n  Herbie\" button to run Herbie.</p>\n  \n  <p>The web shell reports Herbie's progress and redirects to a\n  <a href=\"report.html\">report</a> once Herbie is done.</p>\n\n  <p>The web shell can also automatically save the generated reports,\n  and has <a href=\"options.html\">many other options</a> you might want\n  to explore.</p>\n\n\n  <h2 id=\"batch\">Batch report generation</h2>\n\n  <p>A <a href=\"report.html\">report</a> can also be generated directly\n  from an input file in <a href=\"input.html\">FPCore format</a>:</p>\n  \n  <pre class=\"shell\">racket -l herbie report bench/tutorial.fpcore output/ \nStarting Herbie 2.2 with seed 770126425...\nWarning: 25.0% of points produce a very large (infinite) output. You may want to add a precondition.\nSee &lt;<a href=\"faq.html#inf-points\">https://herbie.uwplse.org/doc/latest/faq.html#inf-points</a>&gt; for more.\n  1/3\t[   0.8s]   55% → 100%\tExpanding a square\n  2/3\t[   0.8s]  100% → 100%\tCommute and associate\n  3/3\t[   0.9s]   53% → 100%\tCancel like terms</pre>\n\n  <p>This command generates a report from the input expressions\n  in <code>bench/tutorial.fpcore</code> and saves the report in the\n  directory <code>output/</code>. It's best if that directory doesn't\n  exist before running this command, because otherwise Herbie may\n  overwrite files in that directory.</p>\n\n  <p>Occasionally Herbie will emit warnings, just like in the example\n  above. All of Herbie's warnings\n  are <a href=\"faq.html\">documented</a>, with explanations and\n  suggested fixes.</p>\n\n  <p>The report Herbie generates is in HTML format so you'll need to\n  start a web server. If you have Python installed, that's\n  particularly convenient:</p>\n\n  <pre class=\"shell\">python3 -m http.server -d output</pre>\n\n  <p>Then go to <a href=\"http://localhost:8000/\">localhost:8000</a> in\n  your favorite browser. The report summarizes Herbie's results for\n  all expression in your input file, and you can click on individual\n  expressions to see Herbie's output for them.</p>\n\n  <p>Batch report generation is the best way to run Herbie on a large\n  collection of inputs. Like the web shell, it can be customized\n  through <a href=\"options.html\">command-line options</a>, including\n  parallelizing Herbie with multiple threads.</p>\n\n\n</body>\n</html>\n"
  },
  {
    "path": "www/doc.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>Herbie: Automatically Improving Floating Point Accuracy</title>\n  <link rel='stylesheet' type='text/css' href='main.css' />\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n  <header>\n    <h1>Herbie Documentation</h1>\n    <a href=\"/\"><img class=\"logo\" src=\"logo-car.png\" /></a>\n    <nav>\n      <ul>\n        <li><a href=\"/demo/\">Try</a></li>\n        <li><a href=\"doc/latest/installing.html\">Install</a></li>\n        <li><a href=\"doc/latest/tutorial.html\">Learn</a></li>\n      </ul>\n    </nav>\n  </header>\n  \n  <h2>Tutorials</h2>\n  \n  <ul>\n    <li><a href=\"doc/latest/installing.html\">Installing Herbie</a>: getting Herbie up and running.</li>\n    <li><a href=\"doc/latest/tutorial.html\">Herbie tutorial</a>: how to use Herbie.</li>\n    <li><a href=\"doc/latest/using-web.html\">The browser UI</a>: a guide to running Herbie from your browser.</li>\n    <li><a href=\"doc/latest/using-cli.html\">Shell and batch mode</a>: a guide to running Herbie from the command line.</li>\n    <li><a href=\"doc/latest/report.html\">Reports</a>: understanding Herbie's output.</li>\n    <li><a href=\"doc/latest/docker.html\">Installing with Docker</a>: an alternate installation method for Docker users.</li>\n  </ul>\n\n  <h2>Documentation</h2>\n  \n  <ul>\n    <li><a href=\"doc/latest/input.html\">Input format</a>: what sorts of expressions Herbie supports.</li>\n    <li><a href=\"doc/latest/options.html\">Command-line flags</a>: modifying Herbie's behavior.</li>\n    <li><a href=\"doc/latest/error.html\">What is error?</a>: how Herbie measures floating-point error.</li>\n    <li><a href=\"doc/latest/faq.html\">Warnings and Errors</a>: troubleshooting Herbie.</li>\n    <li><a href=\"doc/latest/release-notes.html\">Release Notes</a>: the biggest and latest changes to Herbie.</li>\n  </ul>\n\n  <h2>Developer Documentation</h2>\n  <ul>\n    <li><a href=\"doc/latest/platforms.html\">Platforms</a>: how to write a new Herbie compilation target.</li>\n    <li><a href=\"doc/latest/plugins.html\">Other APIs</a>: advanced APIs for compilation targets.</li>\n    <li><a href=\"doc/latest/api-endpoints.html\">HTTP API</a>: Herbie's HTTP endpoints</li>\n    <li><a href=\"doc/latest/diagrams.html\">Diagrams</a>: miscellaneous figures related to Herbie</li>\n  </ul>\n\n  <h2>Blog posts about Herbie</h2>\n\n  <ul id=\"blog\">\n    <li>\n      <a href=\"https://uwplse.org/2024/05/09/Herbie-Numerical-Compiler.html\">\n        Herbie, the Numerical Compiler\n      </a>:\n      Core developer\n      <a href=\"https://www.bsaiki.com/\">Brett</a>'s new vision of Herbie\n      as a numerical compiler considering integrating accuracy and platform accelerators.\n    </li>\n    <li>\n      <a href=\"https://www.bsaiki.com/blog/herbie/2024/01/30/herbie-rearch.html\">\n        Rearchitecting Herbie's improvement loop\n      </a>:\n      Core developer\n      <a href=\"https://www.bsaiki.com/\">Brett</a>'s ideas for how\n      Herbie's main loop could better incorporate low-level hardware details.\n    </li>\n    <li>\n      <a href=\"https://pavpanchekha.com/blog/chatgpt-herbie.html\">\n        ChatGPT vs Herbie\n      </a>:\n      How Herbie compares to asking ChatGPT numerics questions.\n      ChatGPT does better than you might expect!\n    <li>\n      <a href=\"https://pavpanchekha.com/blog/megalibm.html\">\n        MegaLibm: a Math Library Workbench\n      </a>:\n      A parallel project staking out what expert-driven tooling\n      for floating-point implementation could look like.\n    </li>\n    <li>\n      <a href=\"https://pavpanchekha.com/blog/herbie-rust.html\">\n        Improving Rust with Herbie\n      </a>:\n      How our work on Herbie discovered an accuracy problem with\n      Rust's <code>asinh</code> function&mdash;and how Herbie helped\n      us fix it.\n    </li>\n    <li>\n      <a href=\"https://pavpanchekha.com/blog/pherbie-default.html\">\n        A new era for Herbie\n      </a>:\n      Celebrating the fact that pareto mode is now enabled by default\n      in Herbie.\n    </li>\n    <li>\n      <a href=\"https://pavpanchekha.com/blog/optimizing-alt-minimize.html\">\n        Optimizing Pruning in Herbie\n      </a>:\n      How one component of Herbie, the pruning step, was minimized,\n      and how that enabled turning on pareto mode by default.\n    </li>\n    <li>\n      <a href=\"https://pavpanchekha.com/blog/herbie-update-2022-06.html\">\n        An update on Herbie, Summer 2022\n      </a>:\n      A short summary of all sorts of improvements and speed-ups done\n      on Herbie in the summer of 2022.\n    </li>\n    <li>\n      <a href=\"https://pavpanchekha.com/blog/accurate-quadratic.html\">\n        An Accurate Quadratic Formula\n      </a>:\n      What it takes to evaluate a well-known expression like the\n      quadratic formula accurately, and how Herbie helps in coming up\n      with a good method.\n    </li>\n    <li>\n      <a href=\"https://pavpanchekha.com/blog/herbie-hypot-issue.html\">\n        User Trust in Herbie\n      </a>: How we think about making Herbie more trustworthy and\n      predictable for users, especially when that means considering\n      factors besides accuracy.\n    </li>\n    <li>\n      <a href=\"https://pavpanchekha.com/blog/understanding-fptaylor.html\">\n        Understanding Error Taylor Series\n      </a>: Summarizing an important error estimation technique used\n      in tools like FPTaylor.\n    </li>\n    <li>\n      <a href=\"https://pavpanchekha.com/blog/symmetric-expressions.html\">\n      Detecting Symmetric Expressions</a>:\n      How Herbie 1.5's new symmetric expressions feature detects\n      symmetric expressions using e-graphs and some group theory.\n    </li>\n    <li>\n      <a href=\"https://pavpanchekha.com/blog/herbie-goals.html\">Long-term\n      Goals for Herbie</a>:\n      Herbie's <a href=\"https://pavpanchekha.com/\">lead developer</a>\n      lays out some of the biggest Herbie changes in the last couple\n      of years, and gives us a look at what's coming down the pipe.\n    </li>\n    <li>\n      <a href=\"http://pavpanchekha.com/blog/herbie-viz.html\">Remembering\n        the Herbie Visualizer</a>:\n      <a href=\"https://pavpanchekha.com/\">Pavel</a> remembers a\n      tool <a href=\"https://alex.uwplse.org\">Alex</a> wrote to help\n      understand how Herbie works.\n    </li>\n    <li>\n      <a href=\"https://homes.cs.washington.edu/~dthien/blog/2018/AltStats/\">Statistics</a> on \n      <a href=\"https://homes.cs.washington.edu/~dthien/blog/2018/AltPickingTests/\">alt picking</a>:\n      <a href=\"https://homes.cs.washington.edu/~dthien\">David</a>\n      designed and ran a series of experiments to evaluate\n      how well Herbie's \"alt\" (candidate) picking heuristics work.\n    </li>\n    <li>\n      <a href=\"https://homes.cs.washington.edu/~dthien/blog/2018/HerbieRegimeTesting/\">Testing</a>\n      <a href=\"https://homes.cs.washington.edu/~dthien/blog/2018/RegimeTestingUpdate1/\">regime</a>\n      <a href=\"https://homes.cs.washington.edu/~dthien/blog/2018/RegimeTestingUpdate2/\">inference</a>:\n      <a href=\"https://homes.cs.washington.edu/~dthien\">David</a>\n      has been poking at Herbie's regime inference to measure how\n      effective it is and characterize situations where we could improve.\n    </li>\n    <li>\n      <a href=\"https://homes.cs.washington.edu/~dthien/blog/2018/Summer2018Research/\">Summer 2018 plan</a>:\n      What <a href=\"https://homes.cs.washington.edu/~dthien\">David Thien</a>\n      will be working on in Herbie this summer!\n    </li>\n    <li><a href=\"http://cseweb.ucsd.edu/~alexss/2017/04/22/introducing-herbgrind.html\">Introducing Herbgrind</a>: what is our sister project Herbgrind all about?</li>\n    <li><a href=\"http://www.i-programmer.info/news/202-number-crunching/9378-let-herbie-make-your-floating-point-better.html\">Let Herbie Make Your Floating Point Better</a>: why programmers who deal with floating point should use Herbie.</li>\n    <li><a href=\"http://alex.uwplse.org/2015/10/16/improving-accuracy-summation.html\">Improving Accuracy: a Look at Sums</a>: why floating point summation is hard, and how compensated summation works.</li>\n    <li><a href=\"http://alex.uwplse.org/2015/08/03/measuring-error.html\">Measuring the Error of Floating Point Programs</a>: how Herbie measures the error of a floating point program, and how we're working to extend that to programs with loops.</li>\n    <li><a href=\"https://pavpanchekha.com/blog/taylor-log.html\">Logarithms of Taylor Expansions</a>: how Herbie takes Taylor expansions of logarithms.</li>\n    <li><a href=\"https://pavpanchekha.com/blog/mathjs-series.html\">Hyperbolic sines in math.js</a>: how Herbie fixed an accuracy bug in <a href=\"http://mathjs.org\">math.js</a> using series expansion.</li>\n    <li><a href=\"https://pavpanchekha.com/blog/taylor-exp.html\">Taylor Expansions of Taylor Expansions</a>: how Herbie takes Taylor expansions of exponential and trigonometric functions.</li>\n    <li><a href=\"https://pavpanchekha.com/blog/arbitrary-precision.html\">Arbitrary Precision, not Arbitrary Accuracy</a>: why arbitrary-precision libraries aren’t an answer to rounding error.</li>\n    <li><a href=\"https://pavpanchekha.com/blog/casio-mathjs.html\">Complex Square Roots in math.js</a>: how Herbie automatically fixed an accuracy bug in <a href=\"http://mathjs.org\">math.js</a>, an open source mathematics library.</li>\n    <li><a href=\"https://pavpanchekha.com/blog/fp-guarantees.html\">Floating Point Guarantees</a>: how floating point rounding and primitive operators work.</li>\n  </ul>\n"
  },
  {
    "path": "www/graph.js",
    "content": "margin = 10;\nbarheight = 10;\nwidth = 505;\ntextbar = 20;\n\nfunction sort_by(type) {\n    return function(a, b) {\n        return b[type] - a[type];\n    }\n}\n\nfunction r10(d) {\n    return \"\" + (Math.round(d * 10) / 10);\n}\n\nfunction make_graph(node, data, start, end) {\n    var len = data.length;\n    var precision = 64; // TODO\n\n    var a = d3.selectAll(\"script\");\n    var script = a[0][a[0].length - 1];\n\n    var svg = node\n        .append(\"g\").attr(\"transform\", \"translate(\" + margin + \",\" + margin + \")\");\n\n    for (var i = 0; i <= precision; i += 4) {\n        svg.append(\"line\")\n            .attr(\"class\", \"gridline\")\n            .attr(\"x1\", i / precision * width)\n            .attr(\"x2\", i / precision * width)\n            .attr(\"y1\", 0)\n            .attr(\"y2\", len * barheight);\n\n        svg.append(\"text\").text(i)\n            .attr(\"x\", i / precision * width)\n            .attr(\"width\", 80)\n            .attr(\"y\", len * barheight + textbar);\n    }\n\n    var bar = svg.selectAll(\"g\").data(data).enter();\n\n    function line_y(d, i) { return (i + .5) * barheight; }\n    function title(d, i) { return d.name + \" (\" + r10(precision - d[start]) + \" to \" + r10(precision - d[end]) + \")\"; }\n\n    bar.append(\"line\")\n        .attr(\"class\", \"guide\")\n        .attr(\"x1\", 0)\n        .attr(\"x2\", function(d) { return (precision - Math.max(d[start], d[end])) / precision * width })\n        .attr(\"y1\", line_y)\n        .attr(\"y2\", line_y);\n\n    var g = bar.append(\"g\").attr(\"title\", title)\n        .attr(\"class\", function(d) { return d[start] > d[end] ? \"good\" : \"bad\" });\n\n    g.append(\"line\")\n        .attr(\"x1\", function(d) {return (precision - Math.max(d[start], d[end])) / precision * width})\n        .attr(\"x2\", function(d) { return (precision - Math.min(d[start], d[end])) / precision * width })\n        .attr(\"y1\", line_y)\n        .attr(\"y2\", line_y);\n\n    g.append(\"g\").attr(\"transform\", function(d, i) {\n        return \"translate(\" + ((precision - Math.min(d[start], d[end])) / precision * width) + \", \" + line_y(d, i) + \")\";\n    })\n        .append(\"polygon\").attr(\"points\", \"0,-3,0,3,5,0\");\n}\n\nfunction draw_results(node) {\n    d3.json(\"results.json\", function(err, data) {\n        if (err) return console.error(err);\n        data = data.tests;\n    \n        data.sort(sort_by(\"start\"));\n        make_graph(node, data, \"start\", \"end\");\n    });\n}\n"
  },
  {
    "path": "www/index.html",
    "content": "<!doctype html>\n<meta charset=\"utf-8\" />\n<title>Herbie: Automatically Improving Floating Point Accuracy</title>\n<script src=\"https://d3js.org/d3.v3.min.js\" charset=\"utf-8\"></script>\n<script type='text/javascript' src='graph.js'></script>\n<link rel='stylesheet' type='text/css' href='main.css' />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\n<header>\n  <h1>The Herbie Project</h1>\n  <a href=\"/\"><img class=\"logo\" src=\"logo-car.png\" /></a>\n  <nav>\n    <ul>\n      <li><a href=\"/demo/\">Try</a></li>\n      <li><a href=\"doc/latest/installing.html\">Install</a></li>\n      <li><a href=\"doc/latest/tutorial.html\">Learn</a></li>\n    </ul>\n  </nav>\n</header>\n\n<figure class=\"showcase\">\n  <h2>Find and fix floating-point problems:</h2>\n  <div class=\"before-after\">\n    <code class=\"before\">sqrt(x+1) - sqrt(x)</code>\n    →\n    <code class=\"after\">1/(sqrt(x+1) + sqrt(x))</code>\n  </div>\n  <figcaption>\n    Herbie detects inaccurate expressions\n    and finds more accurate replacements.\n    The red expression is inaccurate when <i>x > 1</i>;\n    Herbie's replacement, in blue, is accurate for all <i>x</i>.\n  </figcaption>\n</figure>\n\n<div class=\"column-container\">\n  <div>\n    <h3>Use</h3>\n    <ul>\n      <li><a href=\"/demo/\">Web demo</a></li>\n      <li><a href=\"doc/latest/installing.html\">Install</a></li>\n      <li><a href=\"#news\">News</a></li>\n      <li><a href=\"doc.html#blog\">Blog</a></li>\n    </ul>\n  </div>\n  <div>\n    <h3>Learn</h3>\n    <ul>\n      <li><a href=\"doc/latest/tutorial.html\">Tutorial</a></li>\n      <li><a href=\"doc/latest/release-notes.html\">Release Notes</a></li>\n      <li><a href=\"doc.html\">Documentation</a></li>\n      <li><a href=\"papers.html\">Papers about Herbie</a></li>\n    </ul>\n  </div>\n  <div>\n    <h3>Contribute</h3>\n    <ul>\n      <li><a href=\"https://github.com/herbie-fp/herbie\">Source Code</a></li>\n      <li><a href=\"https://github.com/herbie-fp/herbie/issues\">Report a Bug</a></li>\n      <li><a href=\"https://github.com/herbie-fp/herbie/blob/master/LICENSE.md\">License</a></li>\n    </ul>\n  </div>\n</div>\n\n<figure class=\"showcase\">\n  <style scoped>\n    line { pointer-events: all; }\n    .good, .bad { stroke-width: 3px; stroke-opacity: 0.6; fill-opacity: 0.6; }\n    .good:hover, .bad:hover { stroke-opacity: 1.0; fill-opacity: 1.0; }\n    .good * { stroke: black; fill: black; }\n    .bad * { stroke: darkred; fill: darkred; }\n    .gridline, .guide { stroke: rgb(40%, 40%, 40%); }\n    text { text-anchor: middle; }\n  </style>\n  <svg id=\"results\" width=\"100%\" viewBox=\"0 0 525 320\"></svg>\n  <script>draw_results(d3.select(\"#results\"))</script>\n  <figcaption>Herbie improving accuracy on the “Hamming” benchmark suite. Longer arrows are better. Each arrow starts at the accuracy of the original expression, and ends at the accuracy of Herbie’s output, in each case on random double-precision inputs.</figcaption>\n</figure>\n\n<h2>Herbie Project News</h2>\n<ol id=\"news\">\n  <li><time>4 Aug</time><a href=\"doc/2.2/release-notes.html\">Herbie 2.2</a> is out today! The star of this release is a new <a href=\"doc/2.2/platforms.html\">platform API</a> for pluggable compilation targets. Try it out!</li>\n  <hr class=\"yearmark\" />\n  <li><time>17 Jul</time>Today we are releasing <a href=\"doc/2.1/release-notes.html\">Herbie 2.1</a>! This release makes Herbie's generated code&mdash;and Herbie itself&mdash;faster. Try it out!</li>\n  <hr class=\"yearmark\" />\n  <li><time>30 Jun</time>We are proud to release <a href=\"doc/2.0/release-notes.html\">Herbie 2.0</a>! This release teaches Herbie to optimize for both accuracy and speed, and includes a complete redesign of Herbie's reports and metrics. Try it out!</li>\n  <hr class=\"yearmark\" />\n  <li><time>24 Jul</time>Due to a major unforseen issue with our release infrastructure, we are re-releasing <a href=\"doc/1.5/release-notes.html\">Herbie 1.5</a>. If you previously tried to install it and failed, please try again!</li>\n  <li><time>9 Jul</time>We're pleased to announce the release of <a href=\"doc/1.5/release-notes.html\">Herbie 1.5</a>, with features like argument sorting and multiple outputs. Do try it out!</li>\n  <li><time>14 Jun</time><a href=\"https://www.bsaiki.com\">Brett</a> and <a href=\"https://www.oflatt.com\">Oliver</a> are giving a talk <a href=\"http://arith2021.arithsymposium.org\">ARITH 2021</a> on adding precision tuning to Herbie. Tune in or <a href=\"papers.html\">read the paper</a> to learn more!</li>\n  <hr class=\"yearmark\" />\n  <li><time>21 Jul</time><a href=\"https://homes.cs.washington.edu/~ztatlock/\">Zach</a> and <a href=\"https://pavpanchekha.com/\">Pavel</a> gave a talk about Herbie's last five years: <a href=\"https://www.youtube.com/watch?v=E2KtVa7j2eY&list=PL6VFuHglY6bKikq0bE5XTKFbKaY67l8aV&index=2&t=0s\">trust, measurement, community, and generality</a>.</li>\n  <li><time>20 Jul</time>The chaos of 2020 now brings you a rowboat of stability: <a href=\"doc/1.4/release-notes.html\">Herbie 1.4</a>, with significant speed-ups and ease of use improvements. Download and try it today!</li>\n  <hr class=\"yearmark\" />\n  <li><time>18 Nov</time><a href=\"http://davidthien.com\">David</a> will be talking about FPBench 1.2 and the latest improvements in Herbie at <a href=\"https://correctness-workshop.github.io/2019/\">Correctness 2019</a> in <a href=\"https://sc19.supercomputing.org\">Denver</a>.</li>\n  <li><time>17 Nov</time>Herbie got a shout-out in <a href=\"https://pavpanchekha.com/\">Pavel</a>'s talk at the <a href=\"http://fpanalysistools.org/sc19/\">FP analysis tutorial</a> at <a href=\"https://sc19.supercomputing.org\">SC'19</a>.</li>\n  <li><time>1 May</time><a href=\"https://pavpanchekha.com/\">Pavel</a> will be joining the <a href=\"https://www.utah.edu/\">University of Utah</a> as an assistant professor next year, joining <a href=\"http://www.cs.utah.edu/~ganesh/\">Ganesh</a> and <a href=\"https://zvonimir.info/\">Zvonimir</a> at what is already a nexus of floating-point research.</li>\n  <li><time>13 Mar</time><a href=\"https://homes.cs.washington.edu/~ztatlock/\">Zach</a> gave a keynote at <a href=\"https://posithub.org/conga/2019/\">CoNGA’19</a> on multi-precision, multi-format computations and our efforts to support them in Herbie, <a href=\"http://fpbench.org\">FPBench</a>, and <a href=\"http://titanic.uwplse.org\">Titanic</a>.</li>\n  <hr class=\"yearmark\" />\n  <li><time>20 Jun</time><a href=\"http://alexsanchezstern.com/\">Alex</a> gave <a href=\"https://www.youtube.com/watch?v=bFL6PaPrz8Y\">a talk</a> on our sister project Herbgrind at <a href=\"https://conf.researchr.org/home/pldi-2018\">PLDI’18</a>. Watch it if you want to know how Herbgrind pulls inaccurate floating-point expressions out of large numeric code bases.</li>\n  <li><time>15 Jun</time>After a year of work, <a href=\"doc/1.2/release-notes.html\">Herbie 1.2</a> has been released. This release focuses on creativity and accuracy, with a new system to infer better branches and more accurate defaults for Herbie's various parameters. Read about all the changes in the <a href=\"doc/1.2/release-notes.html\">release notes</a>.</li>\n  <li><time>9 Apr</time>We teamed up with <a href=\"https://www.mpi-sws.org/people/hbecker/\">Heiko</a> and <a href=\"https://people.mpi-sws.org/~eva/\">Eva</a> on the <a href=\"https://github.com/malyzajko/daisy\">Daisy</a> team to combine our tools and evaluate how best to use them together—it'll be published at <a href=\"https://fm2018.org\">FM’18</a>. If you're using Herbie with other floating point tools, let us know!</li>\n  <li><time>1 Mar</time><a href=\"https://pavpanchekha.com/\">Pavel</a> and <a href=\"https://homes.cs.washington.edu/~ztatlock/\">Zach</a> went to see <a href=\"https://www.mccawhall.com/events/detail/herbie-hancock\">Herbie Hancock play at the Seattle Center</a>. Watching Herbie play Chameleon on the keytar is sure to inspire the next generation of floating point accuracy improvement!</li>\n  <li><time>17 Jan</time><a href=\"https://pavpanchekha.com/\">Pavel</a> gave <a href=\"https://www.youtube.com/watch?v=oYtnXEZC0jk\">a talk</a> at <a href=\"https://www.microsoft.com/en-us/research/\">Microsoft Research Redmond</a> on Herbie and <a href=\"http://herbgrind.ucsd.edu\">Herbgrind</a>, plus the <a href=\"http://fpbench.org\">FPBench</a> project. Thank you everyone who came!</li>\n  <li><time>3 Jan</time> <a href=\"https://pavpanchekha.com\">Pavel</a> wrote a <a href=\"http://pavpanchekha.com/blog/how-herbie.html\">retrospective</a> on the early history of Herbie, and some lessons learned.</li>\n  <hr class=\"yearmark\" />\n  <li><time>24 Aug</time><a href=\"https://pavpanchekha.com/\">Pavel</a> gave a talk at <a href=\"https://www.mpi-sws.org/\">MPI-SWS</a> Saarbrücken on Herbie, <a href=\"http://herbgrind.ucsd.edu\">Herbgrind</a>, lessons learned, and what comes next. Thank you <a href=\"https://people.mpi-sws.org/~eva/\">Eva Darulova</a> and her students for the invitation and the warm welcome. The video was recorded and can be watched on <a href=\"https://www.youtube.com/watch?v=WvDZ4m4fAF0\">YouTube</a>.</li>\n  <li><time>3 May</time> After incubating on this website, <a href=\"http://herbgrind.ucsd.edu\">Herbgrind</a> has moved to a <a href=\"http://herbgrind.ucsd.edu\">new website</a> hosted at UCSD, where <a href=\"http://alexsanchezstern.com/\">Alex</a>, Herbie star and the main Herbgrind developer, is now doing his PhD. We'll continue our close collaboration, including in the FPBench project, and are hoping the new, more-focused websites help users.</li>\n  <li><time>1 May</time>Just one month after the beta, <a href=\"doc/1.1/release-notes.html\">Herbie 1.1</a> has been released. This release adds a <a href=\"doc/latest/using-web.html\">browser</a> interface for Herbie, and includes significant bug fixes, usability tweaks, and improvements. Read about all the changes in the <a href=\"doc/1.1/release-notes.html\">release notes</a>.</li>\n  <li><time>20 Apr</time>Our sister project <a href=\"http://herbgrind.ucsd.edu\">Herbgrind</a> has released version 0.42. This pre-release is a reworked, faster, and more stable Herbgrind, which can find root causes for floating-point errors in the largest and gnarliest of codebases!</li>\n  <li><time>2 Apr</time>After months of work, a beta of <a href=\"doc/1.1/release-notes.html\">Herbie 1.1</a> has been released. This release adds a <a href=\"doc/latest/using-web.html\">browser</a> interface for Herbie, and includes significant bug fixes, usability tweaks, and improvements. Read about all the changes in the <a href=\"doc/1.1/release-notes.html\">release notes</a>.</li>\n  <li><time>3 Feb</time> <a href=\"https://s3-us-west-2.amazonaws.com/uwplse/Herbie/dropbox-2014-04.mp4\">Zach</a> is giving <a href=\"http://www.cs.utah.edu/calendar/colloquium-zach-tatlock/\">a talk</a> at the University of Utah about Herbie, FPBench, and Herbgrind. Please come to learn about automated tools for floating point!</li>\n  <hr class=\"yearmark\" />\n  <li><time>13 Jun</time>After months of work, the Herbie developers are proud to announce the release of <a href=\"doc/1.0/release-notes.html\">Herbie 1.0</a>. This release transitions to the <a href=\"doc/latest/input.html\">FPCore</a> format from the <a href=\"http://fpbench.org\">FPBench</a> initiative, and includes significant bug fixes, usability tweaks, and improvements. Read about all the changes in the <a href=\"doc/1.0/release-notes.html\">release notes</a>.</li>\n  <li><time>9 May</time>In preparation for the Version 1.0 release, we've renamed the <code>pi</code> and <code>e</code> constants to upper case. This matches <code>libm</code> and should make it a little harder to cause bugs. Herbie will now optimize expressions like <code>(exp 1)</code> to <code>E</code>.</li>\n  <li><time>6 May</time>We're proud to announce that we've been collaborating with <a href=\"http://perso.univ-perp.fr/mmartel/\">Prof. Martel</a> and his students to build a <a href=\"http://fpbench.org\">common benchmark suite and format</a> for floating point tools. Version 1.0 of Herbie will support only the FPBench format.</li>\n  <li><time>4 Apr</time><a href=\"https://pavpanchekha.com/\">Pavel</a> is giving a talk at Google on how Herbie works and what our plans for the future are.</li>\n  <li><time>30 Mar</time><a href=\"https://pavpanchekha.com/\">Pavel</a> is giving a talk at MIT on how Herbie works internally.</li>\n  <li><time>6 Mar</time>In preparation for the Version 1.0 release, we've renamed several functions in Herbie to match the <code>libm</code> names. In particular, look out for <code>abs</code>, which is now <code>fabs</code>, and <code>expt</code>, which is now <code>pow</code>.</li>\n  <li><time>26 Jan</time><a href=\"https://pavpanchekha.com/\">Pavel</a> is giving a talk at MathWorks on how Herbie works answered questions on how it could be extended.</li>\n  <li><time>25 Jan</time>The <a href=\"https://github.com/mcarton/rust-herbie-lint\">Herbie Rust Linter</a> plugs into the Rust compiler to add warnings for numerically unstable expressions, and suggests Herbie's more accurate output as a hint.</li>\n  <hr class=\"yearmark\" />\n  <li><time>1 Oct</time>The <a href=\"https://github.com/mikeizbicki/HerbiePlugin#herbie-ghc-plugin\">Herbie GHC Plugin</a> by Mike Izbicki automatically runs Herbie on applicable expressions in a Haskell program. He's also scanned all of <a href=\"https://www.stackage.org/lts-3.5\">Stackage LTS-3.5</a> for numerical inaccuracies with Herbie.</li>\n  <li><time>13 Jun</time><a href=\"https://pavpanchekha.com/\">Pavel</a> is giving a <a href=\"papers.html\">Distinguished Paper</a> talk at <a href=\"http://conf.researchr.org/home/pldi2015\">PLDI’15</a> on the scientific advances that underpin Herbie.</li>\n  <li><time>9 Apr</time><a href=\"https://homes.cs.washington.edu/~ztatlock/\">Zach</a> is giving a talk at Berkeley on how we plan to improve floating point accuracy with Herbie.</li>\n  <hr class=\"yearmark\" />\n  <li><time>17 Jun</time><a href=\"https://pavpanchekha.com/\">Pavel</a> is giving a <a href=\"https://s3-us-west-2.amazonaws.com/uwplse/Herbie/oplss-2014-06.pdf\">talk</a> at OPLSS on whether floating point accuracy can be improved, and our plans for finding out.</li>\n  <li><time>15 May</time><a href=\"https://pavpanchekha.com/\">Pavel</a> is giving a <a href=\"https://s3-us-west-2.amazonaws.com/uwplse/Herbie/lightingtalk-2014-05.pdf\">lightning talk</a> on a new project to improve the accuracy of floating point expressions.</li>\n  <li><time>31 Mar</time><a href=\"https://pavpanchekha.com/\">Pavel</a> is giving a <a href=\"https://s3-us-west-2.amazonaws.com/uwplse/Herbie/dropbox-2014-04.pdf\">talk</a> on at Dropbox on a new project to improve the accuracy of floating point expressions. (<a href=\"https://s3-us-west-2.amazonaws.com/uwplse/Herbie/dropbox-2014-04.mp4\">video</a>)</li>\n</ol>\n\n<script>\n  var news = document.getElementById(\"news\");\n  for (var i = 3; i < news.children.length; i++) {\n      news.children[i].style.display = \"none\";\n  }\n  var more = document.createElement(\"li\");\n  more.classList.add(\"more\");\n  more.innerHTML = \"See older news\";\n  more.addEventListener(\"click\", function(e) {\n      for (var i = 0; i < news.children.length; i++) {\n          news.children[i].style.display = \"list-item\";\n      }\n      more.style.display = \"none\";\n  });\n  news.appendChild(more);\n</script>\n\n<h2>The Herbie Developers</h2>\n\n<p>Herbie is developed at <a href=\"https://cs.washington.edu\">UW</a> <a href=\"https://uwplse.org\">PLSE</a>, with contributions from a supportive community.</p>\n\n<p>The main contributors are\n  <a href=\"https://pavpanchekha.com\">Pavel Panchekha</a>,\n  <a href=\"http://alexsanchezstern.com/\">Alex Sanchez-Stern</a>,\n  <a href=\"https://homes.cs.washington.edu/~dthien/blog/\">David Thien</a>,\n  <a href=\"https://homes.cs.washington.edu/~ztatlock/\">Zachary Tatlock</a>,\n  <a>Jason Qiu</a>,\n  <a href=\"https://github.com/jackfirth\">Jack Firth</a>, and\n  <a href=\"http://homes.cs.washington.edu/~jrw12/\">James R. Wilcox</a>.\n</p>\n\n<img src=\"doc/latest/team.png\" />\n"
  },
  {
    "path": "www/main.css",
    "content": "@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Serif:wght@400,700&family=IBM+Plex+Mono&family=Ruda:wght@600&display=swap');\n\nhtml { font-family: 'IBM Plex Serif', serif; font-size: 16px; line-height: 1.4; }\nbody { max-width: 650px; margin: .5em auto 3em;}\n\nh1, h2, h3 {\n    font-family: 'Ruda', sans-serif; letter-spacing: .06ch; font-weight: 600;\n    clear: both;\n}\nh1 {font-size: 20px; line-height: 1; margin: 4em 0 .5em; }\nh2 {font-size: 18px; line-height: 1.125; margin: 3em 0 .25em; }\nh3 {font-size: 17px; line-height: 1.286; margin: 1.5em 0 .2em; font-weight: 400; }\n\np, li, dd, blockquote, figcaption, summary {\n  text-align: justify; -moz-hyphens: auto; -webkit-hyphens: auto; hyphens: auto;\n  margin: 0 0 1em 0;\n}\ndd { margin: .5em 0 1em; }\n\n.showcase { background: #ddd; padding: 1em; margin: 4em 0; clear: both;}\n.showcase > h2 { margin: 0 0 1em; }\n.showcase figcaption {font-size: 15px; line-height: 1.4; margin-top: 1em;}\n.showcase img { width: 100%; }\n.before-after { font-size: 20px; text-align: center; line-height: 1.5; }\n.before-after code { padding: 0 1ex; font-weight: bold; }\n.before-after .before { color: #aa2e00; }\n.before-after .after { color: #0000e0; }\n\nheader {\n    line-height: 2; border-bottom: 1px solid #ddd; margin-bottom: 2em;\n    display: flex; flex-direction: row; align-items: bottom;\n}\nheader h1 { width: calc(50% - 54px/2); margin: 0; font-size: 125%; line-height: 1.6 }\nheader img { width: 54px; height: 24px; vertical-align: bottom; padding-bottom: 4px; }\nheader nav { width: calc(50% - 54px/2); text-align: right; }\nheader ul { margin: 0; padding: 0; font-weight: bold; }\nheader li { display: inline-block; margin: 0 .5em; }\nheader li::before { content: \"•\"; margin-right: 1em; }\nheader li:first-child::before { content: none; }\n\n.toc { margin: 2em 0; background: #eee; padding: 1em; }\n.toc::before { content: \"Table of Contents\"; font-size: 110%; font-weight: bold; }\n.toc ul { list-style: outside none; padding: 0; }\n\nsvg {margin: 0 auto; display: block;}\n\npre { padding-left: 2em; font-size: 16px; font-family: 'IBM Plex Mono', monospace; }\npre.shell:before { content: \"$\"; margin-right: 1ex; font-weight: bold; }\n\ndiv.column-container { display: flex; justify-content: space-around;}\ndiv.column-container h3 { margin: 0 0 1em; }\ndiv.column-container ul { list-style: inside none; margin: 0; padding: 0; }\n\nul {padding-left: 1em;}\na {color: #2A6496; text-decoration: none}\na:hover {text-decoration: underline; color: #295785}\n\n#formula input { width: 100%; font-size: 125%; }\n#errors li { color: #800; }\n#progress {\n    font-size: 14px; font-family: sans-serif; background-color: #f1f1f1;\n    padding-left: 0; overflow: scroll; overflow-y: auto;\n}\n#num-jobs { font-weight: bold; }\n\ndl { margin: 1em 0; }\ndl dd { margin: .5em 1em; }\ndl.function-list dt { font-weight: bold; float: left; width: 220px; clear: left; margin-bottom: .5em; }\ndl.function-list dd { clear: right; margin: 0; }\ndl.function-list dd:after { clear: both; height: 1px; display: block; content: \".\"; visibility: hidden; margin: 0;}\n\ntable.function-list { width: 100%; margin: 1em; }\ntable.function-list th { text-align: left; }\ntable.function-list td:nth-child(1) { font-family: monospace; min-width: 170px; margin: 0 1em .5em 1em; }\n\n\nh2 .badges { color: #2A6496; margin-left: 1ex; float: right; }\n.video { display: block; margin: auto; }\n.abstract { padding: 1em 3em; position: relative; }\n.abstract:before { content: \"“\"; font-size: 600%; position: absolute; top: 0; left: 0; font-family: serif; color: #ccc; }\n.abstract:after { content: \"”\"; font-size: 600%; position: absolute; bottom: -.5em; right: 0; font-family: serif; color: #ccc; }\n.paper-thumb { width: 30%; float: left; margin: 1em; }\n.paper-thumb img { width: 100%; border: 1px solid #ccc; }\n\n#news { list-style: none inside; padding: 0; position: relative; }\n#news li { margin-bottom: 12px; margin-left: 80px; }\n#news time {\n    font-weight: bold; text-align: right;\n    position: absolute; left: 0;\n    display: block; width: 75px;\n}\n#news time:after { content: \":\"; }\n#news .yearmark { border: 0; border-top: 1px solid #bbb; margin: 1em 0; width: 90px; }\n#news .more {\n    color: #2A6496; text-decoration: none; cursor: pointer;\n    margin-left: 0; text-align: center;\n}\n#news .more::before, #news .more::after { content: \"⇩\"; padding: 1ex; }\n#news .more:hover {text-decoration: underline; color: #295785}\n\nbody > img { width: 100%; display: block; margin: 2em 0; }\n\n@media (max-width: 600px) {\n    body { padding: 1em; margin: 0 auto;}\n    .showcase, body > img { margin-left: -1em; margin-right: -1em;}\n    body > img { width: calc(100% + 2em); }\n}\n\n.warning { background: #fffdbb; border: 3px solid #E9DA8A; padding: 5px; }\n"
  },
  {
    "path": "www/papers.html",
    "content": "<!doctype html>\n<meta charset=\"utf-8\" />\n<title>Herbie Papers</title>\n<link rel='stylesheet' type='text/css' href='main.css' />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\n<header>\n  <h1>Herbie Related Papers</h1>\n  <a href=\"/\"><img class=\"logo\" src=\"logo-car.png\" /></a>\n  <nav>\n    <ul>\n      <li><a href=\"/demo/\">Try</a></li>\n      <li><a href=\"doc/latest/installing.html\">Install</a></li>\n      <li><a href=\"doc/latest/tutorial.html\">Learn</a></li>\n    </ul>\n  </nav>\n</header>\n\n<p>This page describes papers related to the <a href=\"../../\">Herbie\nproject</a>, either because they describe Herbie and its internals or\nbecause they were inspired by our work on Herbie. In total, this page\nlists over a dozen publications, including papers\nin <span style=\"color:#2A6496;\">★</span>&nbsp;major venues and which\nreceived 🏆&nbsp;awards.</p>\n\n<h2>PLDI’15: Herbie <span class=\"badges\">★ 🏆</span></h2>\n\n<details>\n  <summary>\n    <a href=\"pldi15-paper.pdf\">Automatically Improving Accuracy for Floating Point Expressions</a>\n    was published at\n    <a href=\"http://conf.researchr.org/home/pldi2015\">★&nbsp;PLDI 2015</a>,\n    where it won the 🏆&nbsp;<em>Distinguished Paper Award</em>.\n    The paper introduces Herbie, describes its internals, and\n    relates experiments describing its effectiveness.\n  </summary>\n\n  <blockquote class=\"abstract\">\n    <p>Scientific and engineering applications depend on floating\n    point arithmetic to approximate real arithmetic. This\n    approximation introduces rounding error, which can accumulate to\n    produce unacceptable results. While the numerical methods\n    literature provides techniques to mitigate rounding error,\n    applying these techniques requires manually rearranging\n    expressions and understanding the finer details of floating point\n    arithmetic.</p>\n    <p>We introduce Herbie, a tool which <em>automatically</em>\n    discovers the rewrites experts perform to improve accuracy.\n    Herbie's heuristic search estimates and localizes rounding error\n    using sampled points (rather than static error analysis), applies\n    a database of rules to generate improvements, takes series\n    expansions, and combines improvements for different input regions.\n    We evaluated Herbie on examples from a classic numerical methods\n    textbook, and found that Herbie was able to improve accuracy on\n    each example, some by up to 60 bits, while imposing a median\n    performance overhead of 40%. Colleagues in machine learning have\n    used Herbie to significantly improve the results of a clustering\n    algorithm, and a mathematical library has accepted two patches\n    generated using Herbie.</p>\n  </blockquote>\n</details>\n\n<p>\n  The <a href=\"pldi15-paper.pdf\">paper</a>,\n  <a href=\"https://www.youtube.com/watch?v=qnkElmpTtBw\">video abstract</a>,\n  <a href=\"https://www.youtube.com/watch?v=RNzsvp6NLOY\">conference talk</a>,\n  and <a href=\"pldi15-slides.pdf\">conference talk slides</a> are available.\n</p>\n\n<h2>NSV’16: FPBench</h2>\n\n<details>\n  <summary>\n    <a href=\"http://fpbench.org/nsv16-paper.pdf\">Toward a Standard\n    Benchmark Format and Suite for Floating-Point Analysis</a> was\n    published at <a href=\"https://nsv2016.pages.ist.ac.at/\">NSV'16</a>.\n    The paper presents the motivation behind FPBench and describes a\n    preliminary version of the FPBench standards.\n  </summary>\n  <blockquote class=\"abstract\">\n    <p>We introduce FPBench, a standard benchmark format for\n    validation and optimization of numerical accuracy in\n    floating-point computations. FPBench is a first step toward\n    addressing an increasing need in our community for comparisons and\n    combinations of tools from different application domains. To this\n    end, FPBench provides a basic floating-point benchmark format and\n    accuracy measures for comparing different tools. The FPBench\n    format and measures allow comparing and composing different\n    floating-point tools. We describe the FPBench format and measures\n    and show that FPBench expresses benchmarks from recent papers in\n    the literature, by building an initial benchmark suite drawn from\n    these papers. We intend for FPBench to grow into a standard\n    benchmark suite for the members of the floating-point tools\n    research community.</p>\n  </blockquote>\n</details>\n\n<p>\n  The <a href=\"http://fpbench.org/nsv16-paper.pdf\">paper</a>,\n  <a href=\"https://www.youtube.com/watch?v=SRE2Gky381M\">conference talk</a>,\n  and <a href=\"http://fpbench.org/nsv16-slides.pdf\">conference talk\n  slides</a> are available. The standards presented in the paper have\n  grown to become the <a href=\"http://fpbench.org/\">FPBench\n  project</a>.\n</p>\n\n<h2>PLDI’18: Herbgrind <span class=\"badges\">★</span></h2>\n\n<details>\n  <summary>\n    <a href=\"http://herbgrind.ucsd.edu/herbgrind-pldi18.pdf\">Finding\n    Root Causes of Floating Point Error</a> was published\n    at <a href=\"https://conf.researchr.org/home/pldi-2018\">★&nbsp;PLDI\n    2018</a>. The paper describes how Herbgrind tracks error and\n    discovers root causes for floating-point error.\n  </summary>\n  <blockquote class=\"abstract\">\n    <p>Floating-point arithmetic plays a central role in science,\n    engineering, and finance by enabling developers to approximate\n    real arithmetic. To address numerical issues in large\n    floating-point applications, developers must identify root causes,\n    which is difficult because floating-point errors are generally\n    non-local, non-compositional, and non-uniform.</p>\n    <p>This paper presents Herbgrind, a tool to help developers\n    identify and address root causes in numerical code written in\n    low-level languages like C/C++ and Fortran. Herbgrind dynamically\n    tracks dependencies between operations and program outputs to\n    avoid false positives and abstracts erroneous computations to\n    simplified program fragments whose improvement can reduce output\n    error. We perform several case studies applying Herbgrind to\n    large, expert-crafted numerical programs and show that it scales\n    to applications spanning hundreds of thousands of lines, correctly\n    handling the low-level details of modern floating point hardware\n    and mathematical libraries and tracking error across function\n    boundaries and through the heap.</p>\n  </blockquote>\n</details>\n\n<p>\n  The <a href=\"http://herbgrind.ucsd.edu/herbgrind-pldi18.pdf\">paper</a>,\n  <a href=\"https://www.youtube.com/watch?v=bFL6PaPrz8Y\">conference talk</a>,\n  and <a href=\"http://herbgrind.ucsd.edu/pldi18-talk/\">conference talk\n  slides</a> are available. Herbgrind is available\n  on <a href=\"http://herbgrind.ucsd.edu/\">its website</a>.\n</p>\n\n<h2>FM’18 short: Daisy/Herbie</h2>\n\n<details>\n  <summary>\n    <a href=\"http://fpbench.org/fm18-paper.pdf\">Combining Tools for\n    Optimization and Analysis of Floating-Point Computations</a> was\n    published\n    at <a href=\"https://www.win.tue.nl/~evink/FM2018/\">FM'18'</a>. The\n    paper describes how different floating-point analysis tools can be\n    combined using tools provided by the FPBench project.\n  </summary>\n  <blockquote class=\"abstract\">\n    <p>Recent renewed interest in optimizing and analyzing\n    floating-point programs has lead to a diverse array of new tools\n    for numerical programs. These tools are often complementary, each\n    focusing on a distinct aspect of numerical programming. Building\n    reliable floating point applications typically requires addressing\n    several of these aspects, which makes easy composition essential.\n    This paper describes the composition of two recent floating-point\n    tools: Herbie, which performs accuracy optimization, and Daisy,\n    which performs accuracy verification. We find that the combination\n    provides numerous benefits to users, such as being able to use\n    Daisy to check whether Herbie's unsound optimizations improved the\n    worst-case roundoff error, as well as benefits to tool authors,\n    including uncovering a number of bugs in both tools. The\n    combination also allowed us to compare the different program\n    rewriting techniques implemented by these tools for the first\n    time. The paper lays out a road map for combining other\n    floating-point tools and for surmounting common challenges.</p>\n  </blockquote>\n</details>\n\n<p>\n  The <a href=\"http://fpbench.org/fm18-paper.pdf\">paper</a> is available.\n</p>\n\n<h2>Correctness’19: Multi-precision Herbie</h2>\n\n<details>\n  <summary>\n    <a href=\"https://sc19.supercomputing.org/proceedings/workshops/workshop_files/ws_corr102s1-file1.pdf\">Toward\n    Multi-Precision, Multi-Format Numerics</a> was published at\n    <a href=\"https://sc19.supercomputing.org/proceedings/workshops/workshop_sessions.html#sess118\">Correctness'19</a>.\n    The paper describes Herbie's model of multi-precision/multi-format\n    code.\n  </summary>\n  <blockquote class=\"abstract\">\n    <p>Recent research has provided new, domain-specific number\n    systems that accelerate modern workloads. Using these number\n    systems effectively requires analyzing subtle multi-format,\n    multi-precision (MPMF) code. Ideally, recent programming tools\n    that automate numerical analysis tasks could help make MPMF\n    programs both accurate and fast. However, three key challenges\n    must be addressed: existing automated tools are difficult to\n    compose due to subtle incompatibilities; there is no \"gold\n    standard\" for correct MPMF execution; and no methodology exists\n    for generalizing existing, IEEE-754-specialized tools to support\n    MPMF. In this paper we report on recent work towards mitigating\n    these related challenges. First, we extend the FPBench standard to\n    support multi-precision, multi-format (MPMF) applications. Second,\n    we present Titanic, a tool which provides reference results for\n    arbitrary MPMF computations. Third, we describe our experience\n    adapting an existing numerical tool to support MPMF programs.</p>\n  </blockquote>\n</details>\n\n<p>\n  The <a href=\"https://sc19.supercomputing.org/proceedings/workshops/workshop_files/ws_corr102s1-file1.pdf\">paper</a> is available.\n</p>\n\n<h2>NSV’20: Towards Numerical Assistants <span class=\"badges\">🏆</span></h2>\n\n<details>\n  <summary>\n    <em>Towards Numerical Assistants: Trust, Measurement, Community,\n    and Generality for the Numerical Workbench</em> was published\n    at <a href=\"https://nsv2020.github.io/\">NSV'20</a>, where it was an\n    🏆&nbsp;<em>invited talk</em>. The talk described the goals\n    driving Herbie's development up to 2020.\n  </summary>\n  <blockquote class=\"abstract\">\n    <p>The last few years have seen an explosion of work on tools that address numerical error in scientific, mathematical, and engineering software. The resulting tools can provide essential guidance to expert non-experts: scientists, mathematicians, and engineers for whom mathematical computation is essential but who may have little formal training in numerical methods. It is now time for these tools to move into practice.</p>\n    <p>Practitioners need a \"numerical workbench\" that not only succeeds as a research artifact but as a daily tool. We describe our experience adapting Herbie, a tool for numerical error repair, from a research prototype to a reliable workhorse for daily use. In particular, we focus on how we worked to increase user trust and use internal measurement to polish the tool. Looking more broadly, we show that community development and an investment in the generality of our tools, such as through the FPBench project, will better support users and strengthen our research community.</p>\n  </blockquote>\n</details>\n\n<p>\n  The <a href=\"https://www.youtube.com/watch?v=E2KtVa7j2eY\">conference\n  talk</a>\n  and <a href=\"https://nsv2020.github.io/nsv2020_slides_herbie_fpbench.pdf\">conference\n  talk slides</a> are available.\n</p>\n\n<h2>POPL’21: Egg <span class=\"badges\">★ 🏆</span></h2>\n\n<details>\n  <summary>\n    <a href=\"https://dl.acm.org/doi/10.1145/3434304\"><code>egg</code>:\n    Fast and extensible equality saturation</a> was published at\n    <a href=\"https://conf.researchr.org/home/pldi-2021\">★&nbsp;PLDI 2021</a>,\n    where it won the 🏆&nbsp;<em>Distinguished Paper Award</em>.\n    The paper describes a new library for equality saturation used by Herbie.\n  </summary>\n  <blockquote class=\"abstract\">\n    <p>An e-graph efficiently represents a congruence relation over\n    many expressions. Although they were originally developed in the\n    late 1970s for use in automated theorem provers, a more recent\n    technique known as equality saturation repurposes e-graphs to\n    implement state-of-the-art, rewrite-driven compiler optimizations\n    and program synthesizers. However, e-graphs remain unspecialized\n    for this newer use case. Equality saturation workloads exhibit\n    distinct characteristics and often require ad-hoc e-graph\n    extensions to incorporate transformations beyond purely syntactic\n    rewrites.</p>\n    <p>This work contributes two techniques that make e-graphs fast\n    and extensible, specializing them to equality saturation. A new\n    amortized invariant restoration technique called rebuilding takes\n    advantage of equality saturation's distinct workload, providing\n    asymptotic speedups over current techniques in practice. A general\n    mechanism called e-class analyses integrates domain-specific\n    analyses into the e-graph, reducing the need for ad hoc\n    manipulation.</p>\n    <p>We implemented these techniques in a new open-source library\n    called egg. Our case studies on three previously published\n    applications of equality saturation highlight how egg's\n    performance and flexibility enable state-of-the-art results across\n    diverse domains.</p>\n  </blockquote>\n</details>\n\n<p>\n  The <a href=\"https://dl.acm.org/doi/10.1145/3434304\">paper</a>, <a href=\"https://www.youtube.com/watch?v=ap29SzDAzP0\">video\n  abstract</a>, and <a href=\"https://www.youtube.com/watch?v=LKELTEOFY-s\">conference\n  talk</a> are available.\n</p>\n\n<h2>ARITH’21: Pareto Herbie <span class=\"badges\">★</span></h2>\n\n<details>\n  <summary>\n    <a href=\"arith21-paper.pdf\">Combining Precision Tuning and Rewriting</a>\n    was published at\n    <a href=\"http://arith2021.arithsymposium.org\">★&nbsp;ARITH 2021</a>.\n    The paper introduces Herbie's pareto mode and describes the\n    modification to Herbie that enable it.\n  </summary>\n\n  <blockquote class=\"abstract\">\n    <p>Precision tuning and rewriting can improve both the accuracy\n      and speed of floating point expressions, yet these techniques are\n      typically applied separately. This paper explores how\n      finer-grained interleaving of precision tuning and rewriting can\n      help automatically generate a richer set of Pareto-optimal\n      accuracy versus speed trade-offs.</p>\n    <p>We introduce Pherbie (Pareto Herbie), a tool providing both\n      precision tuning and rewriting, and evaluate interleaving these\n      two strategies at different granularities. Our results demonstrate\n      that finer-grained interleavings improve both the Pareto curve of\n      candidate implementations and overall optimization time. On a\n      popular set of tests from the FPBench suite, Pherbie finds both\n      implementations that are significantly more accurate for a given\n      cost and significantly faster for a given accuracy bound compared\n      to baselines using precision tuning and rewriting alone or in\n      sequence.</p>\n  </blockquote>\n</details>\n\n<p>\n  The <a href=\"arith21-paper.pdf\">paper</a>,\n  <a href=\"https://www.youtube.com/watch?v=ytWhp0I8KVw\">conference talk</a>,\n  and <a href=\"arith21-slides.pdf\">conference talk slides</a> are available.\n</p>\n\n<h2>OOPSLA’21: Ruler <span class=\"badges\">★ 🏆</span></h2>\n\n<details>\n  <summary>\n    <a href=\"https://dl.acm.org/doi/pdf/10.1145/3485496\">Rewrite Rule\n    Inference Using Equality Saturation</a> was published\n    in <a href=\"https://2021.splashcon.org/track/splash-2021-oopsla\">OOPSLA'21</a>,\n    where it won the 🏆&nbsp;<em>Distinguished Paper Award</em>. The\n    paper describes how rewrite rules, like the ones Herbie uses, can\n    be synthesized from examples.\n  </summary>\n  <blockquote class=\"abstract\">\n    <p>Many compilers, synthesizers, and theorem provers rely on rewrite rules to simplify expressions or prove equivalences. Developing rewrite rules can be difficult: rules may be subtly incorrect, profitable rules are easy to miss, and rulesets must be rechecked or extended whenever semantics are tweaked. Large rulesets can also be challenging to apply: redundant rules slow down rule-based search and frustrate debugging.</p>\n    <p>This paper explores how equality saturation, a promising technique that uses e-graphs to apply rewrite rules, can also be used to infer rewrite rules. E-graphs can compactly represent the exponentially large sets of enumerated terms and potential rewrite rules. We show that equality saturation efficiently shrinks both sets, leading to faster synthesis of smaller, more general rulesets.</p>\n    <p>We prototyped these strategies in a tool dubbed Ruler. Compared to a similar tool built on CVC4, Ruler synthesizes 5.8× smaller rulesets 25× faster without compromising on proving power. In an end-to-end case study, we show Ruler-synthesized rules which perform as well as those crafted by domain experts, and addressed a longstanding issue in a popular open source tool.</p>\n  </blockquote>\n</details>\n\n<p>\n  The <a href=\"https://dl.acm.org/doi/pdf/10.1145/3485496\">paper</a> and\n  <a href=\"https://www.youtube.com/watch?v=5VGTXMgebOo\">conference talk</a>\n  are available.\n</p>\n\n<h2>Correctness’21: Rising Heterogeneity</h2>\n\n<details>\n  <summary>\n    <a href=\"https://web.cs.ucdavis.edu/~rubio/includes/correctness21.pdf\">Guarding\n    Numerics Amidst Rising Heterogeneity</a> was published\n    at <a href=\"https://correctness-workshop.github.io/2021/\">Correctness'21</a>.\n    The paper warns that Herbie and similar tools must adapt to\n    hardware accelerators and GPUs.\n  </summary>\n  <blockquote class=\"abstract\">\n    New heterogeneous computing platforms—especially GPUs\n    and other accelerators—are being introduced at a brisk pace,\n    motivated by the goals of exploiting parallelism and reducing\n    data movement. Unfortunately, their sheer variety as well as\n    the optimization options supported by them have been observed\n    to alter the computed numerical results to the extent that\n    reproducible results are no longer possible to obtain without extra\n    effort. Our main contribution in this paper is to document the\n    scope and magnitude of this problem which we classify under the\n    heading of numerics. We propose a taxonomy to classify specific\n    problems to be addressed by the community, a few immediately\n    actionable topics as the next steps, and also forums within which\n    to continue discussions.\n  </blockquote>\n</details>\n\n<p>\n  The <a href=\"https://web.cs.ucdavis.edu/~rubio/includes/correctness21.pdf\">paper</a> is available.\n</p>\n\n<h2>EGRAPHS’22: Synthesizing Identities</h2>\n\n<details>\n  <summary>\n    <a href=\"https://dl.acm.org/doi/10.1145/3520308.3534506\">Synthesizing\n    mathematical identities with e-graphs</a> was published\n    at <a href=\"https://pldi22.sigplan.org/home/egraphs-2022\">EGRAPHS'22</a>.\n    The paper describes how identities derived from mathematical\n    expressions can be used to improve accuracy.\n  </summary>\n  <blockquote class=\"abstract\">\n    <p>Identities compactly describe properties of a mathematical\n    expression and can be leveraged into faster and more accurate\n    function implementations. However, identities must currently be\n    discovered manually, which requires a lot of expertise. We propose\n    a two-phase synthesis and deduplication pipeline that discovers\n    these identities automatically. In the synthesis step, a set of\n    rewrite rules is composed, using an e-graph, to discover candidate\n    identities. However, most of these candidates are duplicates,\n    which a secondary de-duplication step discards using integer\n    linear programming and another e-graph. Applied to a set of 61\n    benchmarks, the synthesis phase generates 7 215 candidate\n    identities which the de-duplication phase then reduces down to 125\n    core identities.</p>\n  </blockquote>\n</details>\n\n<p>\n  The <a href=\"https://dl.acm.org/doi/10.1145/3520308.3534506\">paper</a>\n  is available.\n</p>\n\n<h2>PLDI’22: OpTuner <span class=\"badges\">★</span></h2>\n\n<details>\n  <summary>\n    <em>Choosing Mathematical Function Implementations for Speed and Accuracy</em>\n    was published\n    at <a href=\"https://pldi22.sigplan.org/\">PLDI'22</a>. The paper\n    describes how multiple implementations of functions\n    like <code>sin</code> can be combined to achieve better\n    combinations of accuracy and precision.\n  </summary>\n  <blockquote class=\"abstract\">\n    <p>Standard implementations of functions like <code>sin</code>\n    and <code>exp</code> optimize for accuracy, not speed, because\n    they are intended for general-purpose use. But just like many\n    applications tolerate inaccuracy from cancellation, rounding\n    error, and singularities, many application could also tolerate\n    less-accurate function implementations. This raises an intriguing\n    possibility: speeding up numerical code by using different\n    function implementations.</p>\n    <p>This paper thus introduces OpTuner, an automated tool for\n    selecting the best implementation for each mathematical function\n    call site. OpTuner uses error Taylor series and integer linear\n    programming to compute optimal assignments of 297 function\n    implementations to call sites and presents the user with a\n    speed-accuracy Pareto curve. In a case study on the POV-Ray ray\n    tracer, OpTuner speeds up a critical computation by 2.48×, leading\n    to a whole program speedup of 1.09× with no change in the program\n    output; human efforts result in slower code and lower-quality\n    output. On a broader study of 36 standard benchmarks, OpTuner\n    demonstrates speedups of 2.05× for negligible decreases in\n    accuracy and of up to 5.37× for error-tolerant applications.</p>\n  </blockquote>\n</details>\n\n<p>\n  The <a href=\"https://www.youtube.com/watch?v=5ausmx4dVHw\">conference\n  talk</a> is available.\n</p>\n\n<h2>FMCAD’22: Egg Proofs <span class=\"badges\">★</span></h2>\n\n<details>\n  <summary>\n    <a href=\"https://repositum.tuwien.at/bitstream/20.500.12708/81325/1/Flatt-2022-Small%20Proofs%20from%20Congruence%20Closure-vor.pdf\">Small\n    Proofs from Congruence Closure</a> was published\n    in <a href=\"https://fmcad.forsyte.at/FMCAD22/\">FMCAD'22</a>. The\n    paper describes how <code>egg</code> computes auditable proofs of\n    the rewrites it performs, which are used in Herbie as a debugging\n    tool.\n  </summary>\n  <blockquote class=\"abstract\">\n    <p>Satisfiability Modulo Theory (SMT) solvers and equality\n    saturation engines must generate proof certificates from\n    e-graph-based congruence closure procedures to enable verification\n    and conflict clause generation. Smaller proof certificates speed\n    up these activities. Though the problem of generating proofs of\n    minimal size is known to be NP-complete, existing proof\n    minimization algorithms for congruence closure generate\n    unnecessarily large proofs and introduce asymptotic overhead over\n    the core congruence closure procedure. In this paper, we introduce\n    an <code>O(n<sup>5</sup>)</code> time algorithm which generates\n    optimal proofs under a new relaxed “proof tree size” metric that\n    directly bounds proof size. We then relax this approach further to\n    a practical <code>O(n log(n))</code> greedy algorithm which\n    generates small proofs with no asymptotic overhead. We implemented\n    our techniques in the egg equality saturation toolkit, yielding\n    the first certifying equality saturation engine. We show that our\n    greedy approach in egg quickly generates substantially smaller\n    proofs than the state-of-the-art Z3 SMT solver on a corpus of\n    3 760 benchmarks.\n  </blockquote>\n</details>\n\n<p>\n  The <a href=\"https://repositum.tuwien.at/bitstream/20.500.12708/81325/1/Flatt-2022-Small%20Proofs%20from%20Congruence%20Closure-vor.pdf\">paper</a>\n  and <a href=\"https://www.youtube.com/watch?v=_KnAHFdqWT0\">conference\n  talk</a> are available.\n</p>\n\n<h2>UIST’23: Odyssey</h2>\n\n<details>\n  <summary>\n    <a href=\"https://arxiv.org/pdf/2305.10599.pdf\">Odyssey: An\n    Interactive Workbench for Expert-Driven Floating-Point Expression\n    Rewriting</a> was published in <a href=\"https://uist.acm.org/2023/\">UIST’23</a>. This paper describes\n    an experimental new user interface for Herbie.\n  </summary>\n  <blockquote class=\"abstract\">\n    <p>In recent years, researchers have proposed a number of automated tools to\n      identify and improve floating-point rounding error in mathematical expressions.\n    However, users struggle to effectively apply these tools.\n    In this paper, we work with\n      novices, experts, and tool developers to\n      investigate user needs during the expression rewriting process.\n    We find that users follow an iterative design process.\n    They want to compare expressions on multiple input ranges,\n      integrate and guide various rewriting tools,\n      and understand where errors come from.\n    We organize this investigation's results into a three-stage workflow\n      and implement that workflow\n      in a new, extensible workbench dubbed Odyssey.\n    Odyssey enables users to:\n      (1) diagnose problems in an expression,\n      (2) generate solutions automatically or by hand, and\n      (3) tune their results.\n    Odyssey tracks a working set of expressions\n      and turns a state-of-the-art automated tool \"inside out,\"\n      giving the user access to internal heuristics, algorithms,\n      and functionality.\n    In a user study, Odyssey enabled five expert numerical analysts\n       to solve challenging rewriting problems\n      where state-of-the-art automated tools fail.\n    In particular, the experts unanimously praised Odyssey’s novel support for\n      interactive range modification and local error visualization.</p>\n  </blockquote>\n</details>\n\n<p>\n  The <a href=\"https://arxiv.org/abs/2305.10599\">paper</a>\n  and <a href=\"https://github.com/herbie-fp/odyssey\">application</a>\n  are available.\n</p>\n\n\n\n<h2>EGRAPHS’23: Using egglog to Improve Floating-point Error</h2>\n\n<details>\n  <summary>\n    <a href=\"https://effect.systems/doc/egraphs-2023-egglog/paper.pdf\">egglog In Practice: Automatically Improving Floating-point Error</a> was published in the workshop\n    <a href=\"https://pldi23.sigplan.org/home/egraphs-2023#About\">EGRAPHS'23</a>.\n    The paper describes how to use egglog to\n    optimize floating-point error in programs.\n  </summary>\n  <blockquote class=\"abstract\">\n    <p>\n      Herbie is a tool for automatically improving floating-point accuracy in programs. Egglog is a new language for performing rewriting over equality, supporting robust analysis. In this tutorial, we show how we improved Herbie in two ways. First, we will show how we leverage egglog to perform sound rewriting in the presence of division for Herbie. Second, we show how to use egglog's powerful rules to extract more accurate programs from the database.\n    </p>\n  </blockquote>\n</details>\n\n\n\n<h2>ARITH’23: Rival</h2>\n\n<details>\n  <summary>\n    <a href=\"arith23-paper.pdf\">Making Interval Arithmetic Robust to Overflow</a>\n    was published at <a href=\"https://arith2023.arithsymposium.org/\">ARITH'23</a>.\n    This paper describes Herbie's interval arithmetic library and\n    specifically how it deals with overflow to infinity.\n  </summary>\n  <blockquote class=\"abstract\">\n    <p>In theory, interval arithmetic at high precision can compute mathematical expressions to any required accuracy. An arbitrary precision library like MPFR can thus be used to evaluate real-valued expressions. In practice, however, MPFR's maximum representable exponent means some inputs cannot be evaluated to the required accuracy. This paper introduces movability flags, which soundly detect the majority of these inputs. Movability flags are set when overflow occurs and track whether recomputing at higher precision could possibly result in narrow intervals. In our tests on 481 expressions, movability flags detect 81.0% of unsamplable inputs. Compared to Mathematica, our movability-flag-enhanced interval arithmetic library resolves 60.3% more challenging inputs, returns 7.6× fewer completely indeterminate results, and avoids 64 cases of fatal error.</p>\n  </blockquote>\n</details>\n\n<p>\n  A long <a href=\"https://arxiv.org/pdf/2107.05784.pdf\">preprint</a>,\n  <a href=\"https://docs.racket-lang.org/rival/\">documentation</a>,\n  and <a href=\"https://github.com/herbie-fp/rival\">source code</a> is\n  available.\n</p>\n\n<h2>POPL’24: MegaLibm <span class=\"badges\">★ 🏆</span></h2>\n\n<details>\n  <summary>\n    <a href=\"https://dl.acm.org/doi/10.1145/3632874\">\n      Implementation and Synthesis of Math Library Functions</a>\n    was published at <a href=\"https://popl24.sigplan.org/\">POPL'24</a>,\n    where it won the 🏆&nbsp;<em>Distinguished Paper Award</em>.\n    This paper describes a DSL for implementing\n    library functions such as <code>sin</code> and <code>log</code>.\n  </summary>\n  <blockquote class=\"abstract\">\n    <p>Achieving speed and accuracy for math library functions like exp, sin, and log is difficult. This is because low-level implementation languages like C do not help math library developers catch mathematical errors, build implementations incrementally, or separate high-level and low-level decision making. This ultimately puts development of such functions out of reach for all but the most experienced experts. To address this, we introduce MegaLibm, a domain-specific language for implementing, testing, and tuning math library implementations. MegaLibm is safe, modular, and tunable. Implementations in MegaLibm can automatically detect mathematical mistakes like sign flips via semantic well-formedness checks, and components like range reductions can be implemented in a modular, composable way, simplifying implementations. Once the high-level algorithm is done, tuning parameters like working precisions and evaluation schemes can be adjusted through orthogonal tuning parameters to achieve the desired speed and accuracy. MegaLibm also enables math library developers to work interactively, compiling, testing, and tuning their implementations and invoking tools like Sollya and type-directed synthesis to complete components and synthesize entire implementations. MegaLibm can express 8 state-of-the-art math library implementations with comparable speed and accuracy to the original C code, and can synthesize 5 variations and 3 from-scratch implementations with minimal guidance.</p>\n  </blockquote>\n</details>\n\n<p>\n  A <a href=\"https://arxiv.org/abs/2311.01515\">preprint</a>,\n  <a href=\"https://www.youtube.com/live/ArzcDPauQGA?si=CKWP0Z6TYOFonG1h&t=5673\">talk</a>,\n  <a href=\"https://github.com/IanBriggs/megalibm\">source code</a> are\n  available.\n</p>\n\n<h2>arXiv: Rival Evaluation</h2>\n\n<details>\n  <summary>\n    <a href=\"https://arxiv.org/pdf/2410.07468\">Fast Real Evaluation Through Sound Mixed-Precision Tuning</a>.\n    This paper describes how Herbie accurately evaluates mathematical expressions\n    and the optimizations that make this process fast.\n  </summary>\n  <blockquote class=\"abstract\">\n    <p>Evaluating a real-valued expression to high precision is a key building block in computational mathematics, physics, and numerics. A typical implementation uses a uniform precision for each operation, and doubles that precision until the real result can be bounded to some sufficiently narrow interval. However, this is wasteful: usually only a few operations really need to be performed at high precision, and the bulk of the expression could use much lower precision. Uniform precision can also waste iterations discovering the necessary precision and then still overestimate by up to a factor of two. We propose to instead use mixed-precision interval arithmetic to evaluate real-valued expressions. A key challenge is deriving the mixed-precision assignment both soundly and quickly. To do so, we introduce a sound variation of error Taylor series and condition numbers, specialized to interval arithmetic, that can be evaluated with minimal overhead thanks to an \"exponent trick\". Our implementation, Reval, achieves a speed-up of 1.25x compared to the state-of-the-art Sollya tool, with the speed-up increasing to 2.99x on the most difficult input points. An examination of the precisions used with and without precision tuning shows that the speed-up results come from quickly assigning lower precisions for the majority of operations. </p>\n  </blockquote>\n</details>\n\n<p>\n  A <a href=\"https://arxiv.org/pdf/2410.07468\">paper</a>,\n  <a href=\"https://docs.racket-lang.org/rival/\">documentation</a>,\n  and <a href=\"https://github.com/herbie-fp/rival\">source code</a> are\n  available.\n</p>\n\n<h2>ARITH’25: <span style=\"font-variant: small-caps;\">ExplaniFloat</span>\n</h2>\n\n<details>\n  <summary>\n    <a href=\"https://arxiv.org/abs/2503.11884\">Mixing Condition Numbers and\n    Oracles for Accurate Floating-point Debugging</a> was published\n    at <a href=\"https://www.arith2025.org/\">★&nbsp;ARITH 2025</a>. The paper\n    introduces <span style=\"font-variant: small-caps;\">ExplaniFloat</span>, a\n    numerical debugger that combines performant numerical oracles and sound\n    error analysis for fast and accurate floating-point debugging.\n  </summary>\n\n  <blockquote class=\"abstract\">\n    <p>\n      Recent advances have made numeric debugging tools much faster by using\n      double-double oracles, and numeric analysis tools much more accurate by\n      using condition numbers. But these techniques have downsides:\n      double-double oracles have correlated error so miss floating-point errors\n      while condition numbers cannot cleanly handle over- and under- flow. We\n      combine both techniques to avoid these downsides. Our combination,\n      <span style=\"font-variant: small-caps;\">ExplaniFloat</span>, computes\n      condition numbers using double-double arithmetic, which avoids correlated\n      errors. To handle over- and under- flow, it introduces a separate\n      logarithmic oracle. As a result, <span style=\"font-variant:\n      small-caps;\">ExplaniFloat</span> achieves a precision of 80.0% and a\n      recall of 96.1% on a collection of 546 difficult numeric benchmarks: more\n      accurate than double-double oracles yet dramatically faster than\n      arbitrary-precision condition number computations.\n    </p>\n  </blockquote>\n</details>\n\n<p>\n  A <a href=\"https://arxiv.org/abs/2503.11884\">paper</a>,\n  and <a href=\"https://github.com/herbie-fp/herbie/tree/bhargav-nobigfloat\">source code</a> are\n  available.\n</p>\n"
  },
  {
    "path": "www/results.json",
    "content": "{\"flags\":[\"precision:double\",\"setup:simplify\",\"reduce:regimes\",\"reduce:taylor\",\"reduce:simplify\",\"reduce:avg-error\",\"rules:arithmetic\",\"rules:polynomials\",\"rules:fractions\",\"rules:exponents\",\"rules:trigonometry\",\"rules:hyperbolic\",\"generate:rr\",\"generate:taylor\",\"generate:simplify\"],\"seed\":\"#(772101555 1905824529 294602591 2478279198 2123125427 4197813737)\",\"points\":256,\"date\":1493418730,\"commit\":\"a6770931126e0702f83b80fffb3cdf362d9e07c9\",\"branch\":\"develop\",\"iterations\":3,\"note\":false,\"bit_width\":64,\"tests\":[{\"bits\":1408,\"start\":39.78563602870575,\"input\":\"(sqrt (/ (- (exp (* 2 x)) 1) (- (exp x) 1)))\",\"output\":\"(sqrt (/ (+ (exp x) 1) 1))\",\"link\":\"0-sqrtexpproblem344\",\"ninf\":0,\"pinf\":0,\"end-est\":0.0078125,\"name\":\"sqrtexp (problem 3.4.4)\",\"samplers\":[\"default\"],\"time\":53697.2470703125,\"status\":\"imp-start\",\"vars\":[\"x\"],\"target\":false,\"end\":0.014412722522414014},{\"bits\":2432,\"start\":31.277522201292555,\"input\":\"(/ (- x (sin x)) (- x (tan x)))\",\"output\":\"(if (<= x -9.950485992669078e-09) (- (/ x (- x (tan x))) (/ (sin x) (- x (tan x)))) (if (<= x 0.16631490308113306) (- (* 9/40 (sqr x)) (+ (* 27/2800 (pow x 4)) 1/2)) (/ (- x (sin x)) (- x (tan x)))))\",\"link\":\"1-sintanproblem345\",\"ninf\":0,\"pinf\":0,\"end-est\":0.36733237039018785,\"name\":\"sintan (problem 3.4.5)\",\"samplers\":[\"default\"],\"time\":135208.11889648438,\"status\":\"imp-start\",\"vars\":[\"x\"],\"target\":false,\"end\":0.1040637469913252},{\"bits\":2432,\"start\":36.53944527020705,\"input\":\"(/ (+ (- b/2) (sqrt (- (sqr b/2) (* a c)))) a)\",\"output\":\"(if (<= b/2 -1.751131060884064e+136) (* -2 (/ b/2 a)) (if (<= b/2 8.548826144111727e-60) (/ 1 (/ a (+ (- b/2) (sqrt (- (sqr b/2) (* a c)))))) (- (/ (+ b/2 (- b/2)) a) (/ (* 1/2 c) b/2))))\",\"link\":\"2-quad2pproblem321positive\",\"ninf\":0,\"pinf\":0,\"end-est\":8.759031935807828,\"name\":\"quad2p (problem 3.2.1, positive)\",\"samplers\":[\"default\",\"default\",\"default\"],\"time\":119061.97412109375,\"status\":\"imp-start\",\"vars\":[\"a\",\"b/2\",\"c\"],\"target\":false,\"end\":5.966762651991987},{\"bits\":2944,\"start\":37.82838784287472,\"input\":\"(/ (- (- b/2) (sqrt (- (sqr b/2) (* a c)))) a)\",\"output\":\"(if (<= b/2 -3.093544874321455e-77) (* (/ -1/2 b/2) c) (if (<= b/2 5.845042913155354e+61) (/ 1 (/ a (- (- b/2) (sqrt (- (sqr b/2) (* a c)))))) (+ (* (/ c b/2) 1/2) (/ (- (- b/2) b/2) a))))\",\"link\":\"3-quad2mproblem321negative\",\"ninf\":0,\"pinf\":0,\"end-est\":8.241281491524308,\"name\":\"quad2m (problem 3.2.1, negative)\",\"samplers\":[\"default\",\"default\",\"default\"],\"time\":126471.29907226562,\"status\":\"imp-start\",\"vars\":[\"a\",\"b/2\",\"c\"],\"target\":false,\"end\":5.326392364138352},{\"bits\":2432,\"start\":31.059705602958424,\"input\":\"(/ (- 1 (cos x)) (sqr x))\",\"output\":\"(* (/ (sin x) x) (/ (/ (sin x) (+ 1 (cos x))) x))\",\"link\":\"4-cos2problem341\",\"ninf\":0,\"pinf\":0,\"end-est\":0.3600447888363383,\"name\":\"cos2 (problem 3.4.1)\",\"samplers\":[\"default\"],\"time\":82701.72485351562,\"status\":\"imp-start\",\"vars\":[\"x\"],\"target\":false,\"end\":0.27141353358701925},{\"bits\":1408,\"start\":31.55214583076247,\"input\":\"(- (pow (+ x 1) (/ 1 n)) (pow x (/ 1 n)))\",\"output\":\"(if (<= n -2.672258838309128e-11) (- (- (/ (/ 1 x) n) (/ (/ 1/2 n) (sqr x))) (/ (log x) (* n (* n x)))) (if (<= n 19699878403.887928) (exp (cube (cbrt (log (- (pow (+ x 1) (/ 1 n)) (pow x (/ 1 n))))))) (- (- (/ (/ 1 x) n) (/ (/ 1/2 n) (sqr x))) (/ (log x) (* n (* n x))))))\",\"link\":\"5-2nthrtproblem346\",\"ninf\":0,\"pinf\":0,\"end-est\":21.21301382692941,\"name\":\"2nthrt (problem 3.4.6)\",\"samplers\":[\"default\",\"default\"],\"time\":143232.169921875,\"status\":\"imp-start\",\"vars\":[\"x\",\"n\"],\"target\":false,\"end\":6.774720844192645},{\"bits\":1408,\"start\":40.755841804999065,\"input\":\"(- (log (+ N 1)) (log N))\",\"output\":\"(if (<= N 9328.390986348908) (log (/ (+ N 1) N)) (+ (/ (- (/ 1/3 N) 1/2) (sqr N)) (/ 1 N)))\",\"link\":\"6-2logproblem336\",\"ninf\":0,\"pinf\":0,\"end-est\":0.11448705279133702,\"name\":\"2log (problem 3.3.6)\",\"samplers\":[\"default\"],\"time\":41444.029052734375,\"status\":\"imp-start\",\"vars\":[\"N\"],\"target\":false,\"end\":19.49352325492048},{\"bits\":896,\"start\":14.049500988425633,\"input\":\"(- (/ 1 (+ x 1)) (/ 1 x))\",\"output\":\"(if (<= x -209135036385.79047) (- (/ 1 (pow x 3)) (+ (pow x (- 2)) (/ 1 (pow x 4)))) (if (<= x 290639.63932394225) (/ (- x (+ 1 x)) (* (+ x 1) x)) (- (/ 1 (pow x 3)) (+ (pow x (- 2)) (/ 1 (pow x 4))))))\",\"link\":\"7-2fracproblem331\",\"ninf\":0,\"pinf\":0,\"end-est\":0.0234375,\"name\":\"2frac (problem 3.3.1)\",\"samplers\":[\"default\"],\"time\":30894.91796875,\"status\":\"imp-start\",\"vars\":[\"x\"],\"target\":false,\"end\":0.014198120312590145},{\"bits\":2432,\"start\":38.890098631337246,\"input\":\"(- (cos (+ x eps)) (cos x))\",\"output\":\"(if (<= eps -3.645937152382937e+19) (- (- (* (cos x) (cos eps)) (* (sin x) (sin eps))) (cos x)) (if (<= eps 4.729663737457019e-05) (* -2 (* (sin (/ eps 2)) (sin (/ (+ (+ x eps) x) 2)))) (- (* (cos x) (cos eps)) (+ (* (sin x) (sin eps)) (cos x)))))\",\"link\":\"8-2cosproblem335\",\"ninf\":0,\"pinf\":0,\"end-est\":0.6303043448114194,\"name\":\"2cos (problem 3.3.5)\",\"samplers\":[\"default\",\"default\"],\"time\":104279.31079101562,\"status\":\"imp-start\",\"vars\":[\"x\",\"eps\"],\"target\":false,\"end\":1.2578573335845715},{\"bits\":1408,\"start\":29.805220676286638,\"input\":\"(- (pow (+ x 1) (/ 1 3)) (pow x (/ 1 3)))\",\"output\":\"(/ 1 (+ (sqr (pow (+ x 1) (/ 1 3))) (+ (sqr (exp (/ (log x) 3))) (* (pow (+ x 1) (/ 1 3)) (pow x (/ 1 3))))))\",\"link\":\"9-2cbrtproblem334\",\"ninf\":0,\"pinf\":0,\"end-est\":2.8592450383022707,\"name\":\"2cbrt (problem 3.3.4)\",\"samplers\":[\"default\"],\"time\":86841.42700195312,\"status\":\"imp-start\",\"vars\":[\"x\"],\"target\":false,\"end\":2.63051098758136},{\"bits\":2432,\"start\":30.222464775570813,\"input\":\"(/ (- 1 (cos x)) (sin x))\",\"output\":\"(* 1 (/ (sin x) (+ (cos x) 1)))\",\"link\":\"10-tanhfexample34\",\"ninf\":0,\"pinf\":0,\"end-est\":0.5284202760025005,\"name\":\"tanhf (example 3.4)\",\"samplers\":[\"default\"],\"time\":51172.2109375,\"status\":\"eq-target\",\"vars\":[\"x\"],\"target\":0.000625,\"end\":0.4384920000497587},{\"bits\":2432,\"start\":34.16168973131298,\"input\":\"(/ (+ (- b) (sqrt (- (sqr b) (* 4 (* a c))))) (* 2 a))\",\"output\":\"(if (<= b -1.751131060884064e+136) (/ (- b) a) (if (<= b -5.335815531470738e-240) (/ 1 (/ (* 2 a) (+ (- b) (sqrt (- (sqr b) (* 4 (* a c))))))) (if (<= b 5.845042913155354e+61) (/ 1 (* (- (- b) (sqrt (- (* b b) (* (* 4 a) c)))) (/ (/ 2 4) c))) (- (/ (+ b (- b)) (+ a a)) (/ c b)))))\",\"link\":\"11-quadpp42positive\",\"ninf\":0,\"pinf\":0,\"end-est\":6.078206418658915,\"name\":\"quadp (p42, positive)\",\"samplers\":[\"default\",\"default\",\"default\"],\"time\":124200.916015625,\"status\":\"gt-target\",\"vars\":[\"a\",\"b\",\"c\"],\"target\":21.51568349447677,\"end\":5.376176978102462},{\"bits\":2944,\"start\":34.438091592742474,\"input\":\"(/ (- (- b) (sqrt (- (sqr b) (* 4 (* a c))))) (* 2 a))\",\"output\":\"(if (<= b -2.049536640230252e+150) (/ (* (/ c 2) 4) (- (/ (+ c c) (/ b a)) (- b (- b)))) (if (<= b 3.902728914492509e-158) (* (/ 4 2) (/ c (+ (- b) (sqrt (- (* b b) (* a (* c 4))))))) (if (<= b 5.845042913155354e+61) (/ 1 (/ (* 2 a) (- (- b) (sqrt (- (sqr b) (* 4 (* a c))))))) (- (/ c b) (/ b a)))))\",\"link\":\"12-quadmp42negative\",\"ninf\":0,\"pinf\":0,\"end-est\":5.090534681871955,\"name\":\"quadm (p42, negative)\",\"samplers\":[\"default\",\"default\",\"default\"],\"time\":127442.75390625,\"status\":\"gt-target\",\"vars\":[\"a\",\"b\",\"c\"],\"target\":21.537857357826326,\"end\":5.5027912650509085},{\"bits\":1408,\"start\":61.40424674064236,\"input\":\"(/ (log (- 1 x)) (log (+ 1 x)))\",\"output\":\"(- (+ (* 1/2 (sqr x)) (+ 1 x)))\",\"link\":\"13-qlogexample310\",\"ninf\":0,\"pinf\":0,\"end-est\":0.5716777813221573,\"name\":\"qlog (example 3.10)\",\"samplers\":[\"default\"],\"time\":22658.823974609375,\"status\":\"eq-target\",\"vars\":[\"x\"],\"target\":0.4463297341631591,\"end\":0.008125},{\"bits\":1408,\"start\":63.323661641605746,\"input\":\"(- (- (* (+ n 1) (log (+ n 1))) (* n (log n))) 1)\",\"output\":\"(- (* (log (+ n 1)) (+ n 1)) (+ (* (log n) (- n)) 1))\",\"link\":\"14-logsexample38\",\"ninf\":0,\"pinf\":0,\"end-est\":60.73435355682203,\"name\":\"logs (example 3.8)\",\"samplers\":[\"default\"],\"time\":43125.350830078125,\"status\":\"gt-target\",\"vars\":[\"n\"],\"target\":60.78763823817359,\"end\":0.2685},{\"bits\":1408,\"start\":59.443513693513,\"input\":\"(log (/ (- 1 eps) (+ 1 eps)))\",\"output\":\"(- (+ (* 2/3 (pow eps 3)) (+ (* 2/5 (pow eps 5)) (* 2 eps))))\",\"link\":\"15-logqproblem343\",\"ninf\":0,\"pinf\":0,\"end-est\":0.13714055965779817,\"name\":\"logq (problem 3.4.3)\",\"samplers\":[\"default\"],\"time\":91070.09790039062,\"status\":\"eq-target\",\"vars\":[\"eps\"],\"target\":0.06565423716474932,\"end\":0.08804107935288033},{\"bits\":2432,\"start\":59.91793067942972,\"input\":\"(- (/ 1 x) (/ 1 (tan x)))\",\"output\":\"(+ (* 2/945 (pow x 5)) (+ (* 1/3 x) (* 1/45 (pow x 3))))\",\"link\":\"16-invcotexample39\",\"ninf\":0,\"pinf\":0,\"end-est\":0.34765625,\"name\":\"invcot (example 3.9)\",\"samplers\":[\"default\"],\"time\":26213.670166015625,\"status\":\"eq-target\",\"vars\":[\"x\"],\"target\":0.0759660601543468,\"end\":0.3295731203125902},{\"bits\":2432,\"start\":61.9783442604534,\"input\":\"(/ (* eps (- (exp (* (+ a b) eps)) 1)) (* (- (exp (* a eps)) 1) (- (exp (* b eps)) 1)))\",\"output\":\"(if (<= (/ (* eps (- (exp (* (+ a b) eps)) 1)) (* (- (exp (* a eps)) 1) (- (exp (* b eps)) 1))) -1.4449365230670285e-180) (+ (/ 1 b) (/ 1 a)) (if (<= (/ (* eps (- (exp (* (+ a b) eps)) 1)) (* (- (exp (* a eps)) 1) (- (exp (* b eps)) 1))) 2.5007607876802412e-113) (+ (/ 1 b) (/ 1 a)) (+ (/ 1 b) (/ 1 a))))\",\"link\":\"17-expq3problem342\",\"ninf\":0,\"pinf\":0,\"end-est\":4.24688513434934,\"name\":\"expq3 (problem 3.4.2)\",\"samplers\":[\"default\",\"default\",\"default\"],\"time\":233948.95581054688,\"status\":\"gt-target\",\"vars\":[\"a\",\"b\",\"eps\"],\"target\":14.651067317747806,\"end\":0.014198120312590145},{\"bits\":1408,\"start\":45.739517733726835,\"input\":\"(/ (exp x) (- (exp x) 1))\",\"output\":\"(if (<= x -9.950485992669078e-09) (/ 1 (- 1 (exp (- x)))) (if (<= x 0.16631490308113306) (+ (/ 1 x) (+ 1/2 (* 1/12 x))) (/ 1 (- 1 (exp (- x))))))\",\"link\":\"18-expq2section311\",\"ninf\":0,\"pinf\":0,\"end-est\":0.22577593043685318,\"name\":\"expq2 (section 3.11)\",\"samplers\":[\"default\"],\"time\":20018.59912109375,\"status\":\"gt-target\",\"vars\":[\"x\"],\"target\":30.12948710533904,\"end\":0.05791712397806687},{\"bits\":1408,\"start\":59.33343129621902,\"input\":\"(- (exp x) 1)\",\"output\":\"(+ (* (* x x) (+ 1/2 (* x 1/6))) x)\",\"link\":\"19-expm1example37\",\"ninf\":0,\"pinf\":0,\"end-est\":0.3642608971118385,\"name\":\"expm1 (example 3.7)\",\"samplers\":[\"default\"],\"time\":35543.492919921875,\"status\":\"eq-target\",\"vars\":[\"x\"],\"target\":0.06436560156295071,\"end\":0.06598364687698317},{\"bits\":1408,\"start\":33.44360243099122,\"input\":\"(- (exp (* a x)) 1)\",\"output\":\"(if (<= (* a x) -1.6665755921255327e-09) (- (exp (* a x)) 1) (+ (* x a) (* 1/2 (* (* x a) (* x a)))))\",\"link\":\"20-expaxsection35\",\"ninf\":0,\"pinf\":0,\"end-est\":0.30826629080627144,\"name\":\"expax (section 3.5)\",\"samplers\":[\"default\",\"default\"],\"time\":31542.9580078125,\"status\":\"gt-target\",\"vars\":[\"a\",\"x\"],\"target\":7.952127997421758,\"end\":0.18645915544792366},{\"bits\":1408,\"start\":33.99583817370671,\"input\":\"(+ (- (exp x) 2) (exp (- x)))\",\"output\":\"(+ (* 1/12 (pow x 4)) (+ (* 1/360 (pow x 6)) (sqr x)))\",\"link\":\"21-exp2problem337\",\"ninf\":0,\"pinf\":0,\"end-est\":0.7811424888959018,\"name\":\"exp2 (problem 3.3.7)\",\"samplers\":[\"default\"],\"time\":51116.8779296875,\"status\":\"gt-target\",\"vars\":[\"x\"],\"target\":8.659910873648657,\"end\":0.11144644300676601},{\"bits\":1152,\"start\":9.49656829978195,\"input\":\"(+ (- (/ 1 (+ x 1)) (/ 2 x)) (/ 1 (- x 1)))\",\"output\":\"(/ (/ (- (/ 2 x) 0) (- x 1)) (+ 1 x))\",\"link\":\"22-3fracproblem333\",\"ninf\":0,\"pinf\":0,\"end-est\":0.060878759768442016,\"name\":\"3frac (problem 3.3.3)\",\"samplers\":[\"default\"],\"time\":139599.76000976562,\"status\":\"eq-target\",\"vars\":[\"x\"],\"target\":0.23795078190808433,\"end\":0.06871936093777044},{\"bits\":2432,\"start\":36.40936010427848,\"input\":\"(- (tan (+ x eps)) (tan x))\",\"output\":\"(if (<= eps -2.4610266585566768e-113) (/ (- (sqr (/ (+ (tan x) (tan eps)) (- 1 (* (tan x) (tan eps))))) (sqr (tan x))) (+ (/ (+ (tan x) (tan eps)) (- 1 (* (tan x) (tan eps)))) (tan x))) (if (<= eps 3.1547769921923584e-35) (+ (* (sqr x) (cube eps)) (+ eps (* (cube x) (pow eps 4)))) (- (* (/ (+ (tan eps) (tan x)) (- 1 (/ (cube (* (tan eps) (sin x))) (cube (cos x))))) (+ (sqr 1) (+ (sqr (* (tan x) (tan eps))) (* 1 (* (tan x) (tan eps)))))) (tan x))))\",\"link\":\"23-2tanproblem332\",\"ninf\":0,\"pinf\":0,\"end-est\":16.79675543908866,\"name\":\"2tan (problem 3.3.2)\",\"samplers\":[\"default\",\"default\"],\"time\":153829.44311523438,\"status\":\"gt-target\",\"vars\":[\"x\",\"eps\"],\"target\":24.868488975311955,\"end\":11.1570419418963},{\"bits\":1408,\"start\":29.901471078747512,\"input\":\"(- (sqrt (+ x 1)) (sqrt x))\",\"output\":\"(/ 1 (+ (sqrt (+ x 1)) (sqrt x)))\",\"link\":\"24-2sqrtexample31\",\"ninf\":0,\"pinf\":0,\"end-est\":0.19988251953688405,\"name\":\"2sqrt (example 3.1)\",\"samplers\":[\"default\"],\"time\":20755.375,\"status\":\"eq-target\",\"vars\":[\"x\"],\"target\":0.16316052656439306,\"end\":0.16316052656439306},{\"bits\":2432,\"start\":36.71325510564527,\"input\":\"(- (sin (+ x eps)) (sin x))\",\"output\":\"(if (<= eps -3.645937152382937e+19) (- (+ (* (sin x) (cos eps)) (* (cos x) (sin eps))) (sin x)) (if (<= eps 6.326235572596747e-15) (* 2 (* (sin (/ eps 2)) (cos (/ (+ (+ x eps) x) 2)))) (- (+ (* (sin x) (cos eps)) (* (cos x) (sin eps))) (sin x))))\",\"link\":\"25-2sinexample33\",\"ninf\":0,\"pinf\":0,\"end-est\":0.40463013074677723,\"name\":\"2sin (example 3.3)\",\"samplers\":[\"default\",\"default\"],\"time\":82629.40185546875,\"status\":\"gt-target\",\"vars\":[\"x\",\"eps\"],\"target\":14.900038199925003,\"end\":1.0798819096901375},{\"bits\":1152,\"start\":19.330732255826693,\"input\":\"(- (/ 1 (sqrt x)) (/ 1 (sqrt (+ x 1))))\",\"output\":\"(* (/ 1 (+ (sqrt (+ 1 x)) (sqrt x))) (/ 1 (* (sqrt x) (sqrt (+ x 1)))))\",\"link\":\"26-2isqrtexample36\",\"ninf\":0,\"pinf\":0,\"end-est\":0.3721339476841681,\"name\":\"2isqrt (example 3.6)\",\"samplers\":[\"default\"],\"time\":35296.56103515625,\"status\":\"eq-target\",\"vars\":[\"x\"],\"target\":0.714170361427429,\"end\":0.3941741281572718},{\"bits\":1408,\"start\":14.541859386925417,\"input\":\"(- (atan (+ N 1)) (atan N))\",\"output\":\"(atan2 (+ 1 0) (+ (* (+ N 1) N) 1))\",\"link\":\"27-2atanexample35\",\"ninf\":0,\"pinf\":0,\"end-est\":0.29506882110978144,\"name\":\"2atan (example 3.5)\",\"samplers\":[\"default\"],\"time\":15547.489990234375,\"status\":\"eq-target\",\"vars\":[\"N\"],\"target\":0.39299853686879893,\"end\":0.39174853686879885}]}"
  }
]