How Fast Is Crow?

Crow benchmark sources

Supporting files for the How Fast Is Crow? article · the programs in four languages, the harness and the raw timings

README.md

 # Crow benchmark sources
 
The programs, harness and raw results behind the performance tables in
"Crow, a Programming Language" and "Crow vs. Other Languages" on aggnr.com.
 
Measured 2026-10-21 on an Apple M4 Max (16 cores, 64 GB), macOS 26.5,
with crow 0.7.0 and the changes after it (commit d3ee350), rustc 1.93.1,
go 1.23.0 and CPython 3.12.12. Every binary had run once before the timed
runs, since macOS checks a new executable at its first launch.
 
## Files
 
- `*.co` — the Crow programs. Sizes are written into the files
  (`fannkuch[10]`, `n = 50000000` in `nbody.co`, `n = 1000000` in
  `nbody_1m.co`, `n = 5500`, `n = 5000`, `n = 18`).
- `*.rs`, `*.go`, `*.py` — hand-written ports of the same programs. The
  Rust and Go ports of spectral norm, k-nucleotide, reverse complement and
  binary trees take a thread count as their last argument (16 here); the
  Python ports of spectral norm and binary trees take a process count.
- `fasta.go` — makes the input for k-nucleotide and reverse complement:
  `./fasta_go 5000000 1 > fasta.txt` (50.8 MB).
- `pidigits-Cargo.toml` — the Rust pidigits port needs the `num-bigint`
  crate; build it as a cargo project with this manifest.
- `binarytrees-mimalloc-Cargo.toml` — the Rust binary-trees port linked
  against mimalloc (prepend
  `use mimalloc::MiMalloc; #[global_allocator] static GLOBAL: MiMalloc = MiMalloc;`
  to the source).
- `bench5.py` — the harness: five runs per program and language (three for
  the interpreter), median, min and max, and a check that every port's
  output is byte-identical.
- `results5.json` — the raw timings this run produced.
 
## Building
 
```
crow build fannkuch.co            # and the others; crow build = opt-level 3 + LTO
rustc -C opt-level=3 -C target-cpu=native -o fannkuch_rs fannkuch.rs
go build -o fannkuch_go fannkuch.go
python bench5.py                  # expects the binaries named as above
``` 

bench5.py

 """Five runs per program and language; median, min and max. Interpreted
Crow three runs. Writes results5.json and prints a table."""
import hashlib
import json
import os
import statistics
import subprocess
import time
 
PY = os.path.expanduser("~/.venvs/finch_ml/bin/python")
CROW = os.path.expanduser("~/.cargo/bin/crow")
 
 
def once(cmd, stdin=None):
    f = open(stdin, "rb") if stdin else None
    t0 = time.perf_counter()
    r = subprocess.run(cmd, stdin=f, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    dt = time.perf_counter() - t0
    if f:
        f.close()
    if r.returncode != 0:
        raise RuntimeError(f"{cmd}: exit {r.returncode}: {r.stderr.decode(errors='replace')[:200]}")
    return dt, hashlib.md5(r.stdout).hexdigest()
 
 
def runs(cmd, n=5, stdin=None):
    times, digests = [], set()
    for _ in range(n):
        dt, d = once(cmd, stdin)
        times.append(dt)
        digests.add(d)
    assert len(digests) == 1, f"{cmd}: output changed between runs"
    return times, digests.pop()
 
 
CASES = [
    ("fannkuch", "n = 10", {
        "crow": ["./fannkuch"], "rust": ["./fannkuch_rs", "10"], "go": ["./fannkuch_go", "10"],
        "cpython": [PY, "fannkuch.py", "10"], "crow -i": [CROW, "run", "-i", "fannkuch.co"]}, None),
    ("n-body", "50 million steps", {
        "crow": ["./nbody"], "rust": ["./nbody_rs", "50000000"], "go": ["./nbody_go", "50000000"]}, None),
    ("n-body", "1 million steps", {
        "crow": ["./nbody_1m"], "rust": ["./nbody_rs", "1000000"], "go": ["./nbody_go", "1000000"],
        "cpython": [PY, "nbody.py", "1000000"], "crow -i": [CROW, "run", "-i", "nbody_1m.co"]}, None),
    ("spectral norm", "n = 5,500", {
        "crow": ["./spectralnorm"], "rust": ["./spectralnorm_rs", "5500", "16"], "go": ["./spectralnorm_go", "5500", "16"],
        "cpython": [PY, "spectralnorm.py", "5500", "16"], "crow -i": [CROW, "run", "-i", "spectralnorm.co"]}, None),
    ("k-nucleotide", "5 million", {
        "crow": ["./knucleotide"], "rust": ["./knucleotide_rs", "16"], "go": ["./knucleotide_go", "16"],
        "cpython": [PY, "knucleotide.py"], "crow -i": [CROW, "run", "-i", "knucleotide.co"]}, "fasta.txt"),
    ("reverse complement", "5 million", {
        "crow": ["./revcomp"], "rust": ["./revcomp_rs", "16"], "go": ["./revcomp_go", "16"],
        "cpython": [PY, "revcomp.py"], "crow -i": [CROW, "run", "-i", "revcomp.co"]}, "fasta.txt"),
    ("pidigits", "5,000 digits", {
        "crow": ["./pidigits"], "rust": ["./pidigits_crate/target/release/pidigits", "5000"], "go": ["./pidigits_go", "5000"],
        "cpython": [PY, "pidigits.py", "5000"], "crow -i": [CROW, "run", "-i", "pidigits.co"]}, None),
    ("binary trees", "depth 18", {
        "crow": ["./binarytrees"], "rust": ["./binarytrees_rs", "18", "16"], "rust (mimalloc)": ["./bt_mi/target/release/bt_mi", "18", "16"],
        "go": ["./binarytrees_go", "18", "16"], "cpython": [PY, "binarytrees.py", "18", "16"],
        "crow -i": [CROW, "run", "-i", "binarytrees.co"]}, None),
]
 
out = []
for prog, size, langs, stdin in CASES:
    digests = {}
    for lang, cmd in langs.items():
        n = 3 if lang == "crow -i" else 5
        try:
            ts, d = runs(cmd, n, stdin)
        except Exception as e:  # noqa: BLE001
            print(f"{prog:19s} {size:17s} {lang:16s} FAILED {e}", flush=True)
            continue
        digests[lang] = d
        med = statistics.median(ts)
        out.append({"program": prog, "size": size, "lang": lang, "runs": n, "median": med, "min": min(ts), "max": max(ts), "times": ts, "md5": d})
        print(f"{prog:19s} {size:17s} {lang:16s} median {med:7.3f}  min {min(ts):7.3f}  max {max(ts):7.3f}  spread {100*(max(ts)-min(ts))/med:4.0f}%", flush=True)
    if len(set(digests.values())) != 1:
        print(f"  !! outputs differ for {prog}: {digests}", flush=True)
    else:
        print(f"  outputs identical across {len(digests)} ports", flush=True)
json.dump(out, open("results5.json", "w"), indent=1)
print("done") 

results5.json

 [
 {
  "program": "fannkuch",
  "size": "n = 10",
  "lang": "crow",
  "runs": 5,
  "median": 0.12661862466484308,
  "min": 0.12469450011849403,
  "max": 0.12821362540125847,
  "times": [
   0.12719512544572353,
   0.12643879186362028,
   0.12469450011849403,
   0.12821362540125847,
   0.12661862466484308
  ],
  "md5": "323202fa3c20601a3e135f4e04d8e1eb"
 },
 {
  "program": "fannkuch",
  "size": "n = 10",
  "lang": "rust",
  "runs": 5,
  "median": 0.13213629182428122,
  "min": 0.13150033447891474,
  "max": 0.1324076671153307,
  "times": [
   0.13225845899432898,
   0.13179741706699133,
   0.13150033447891474,
   0.1324076671153307,
   0.13213629182428122
  ],
  "md5": "323202fa3c20601a3e135f4e04d8e1eb"
 },
 {
  "program": "fannkuch",
  "size": "n = 10",
  "lang": "go",
  "runs": 5,
  "median": 0.12332841660827398,
  "min": 0.12322391662746668,
  "max": 0.12442158348858356,
  "times": [
   0.12442158348858356,
   0.12332841660827398,
   0.12322391662746668,
   0.1232340419664979,
   0.1238984577357769
  ],
  "md5": "323202fa3c20601a3e135f4e04d8e1eb"
 },
 {
  "program": "fannkuch",
  "size": "n = 10",
  "lang": "cpython",
  "runs": 5,
  "median": 2.9719013329595327,
  "min": 2.970015707425773,
  "max": 2.981610666960478,
  "times": [
   2.9711843747645617,
   2.970015707425773,
   2.981610666960478,
   2.9767775824293494,
   2.9719013329595327
  ],
  "md5": "323202fa3c20601a3e135f4e04d8e1eb"
 },
 {
  "program": "fannkuch",
  "size": "n = 10",
  "lang": "crow -i",
  "runs": 3,
  "median": 1.306546333245933,
  "min": 1.30296004191041,
  "max": 1.3126017497852445,
  "times": [
   1.3126017497852445,
   1.30296004191041,
   1.306546333245933
  ],
  "md5": "323202fa3c20601a3e135f4e04d8e1eb"
 },
 {
  "program": "n-body",
  "size": "50 million steps",
  "lang": "crow",
  "runs": 5,
  "median": 4.2005200842395425,
  "min": 4.195659499615431,
  "max": 4.203349375165999,
  "times": [
   4.203349375165999,
   4.202794540673494,
   4.2005200842395425,
   4.195659499615431,
   4.196747042238712
  ],
  "md5": "32c32132315472b32572eb1f52fc01a6"
 },
 {
  "program": "n-body",
  "size": "50 million steps",
  "lang": "rust",
  "runs": 5,
  "median": 1.5316822919994593,
  "min": 1.5277127092704177,
  "max": 1.5345129994675517,
  "times": [
   1.5318213747814298,
   1.5316822919994593,
   1.5315814996138215,
   1.5277127092704177,
   1.5345129994675517
  ],
  "md5": "32c32132315472b32572eb1f52fc01a6"
 },
 {
  "program": "n-body",
  "size": "50 million steps",
  "lang": "go",
  "runs": 5,
  "median": 1.4819951253011823,
  "min": 1.4794401666149497,
  "max": 1.4821725832298398,
  "times": [
   1.4817267088219523,
   1.4820147501304746,
   1.4821725832298398,
   1.4819951253011823,
   1.4794401666149497
  ],
  "md5": "32c32132315472b32572eb1f52fc01a6"
 },
 {
  "program": "n-body",
  "size": "1 million steps",
  "lang": "crow",
  "runs": 5,
  "median": 0.08638154156506062,
  "min": 0.08562891650944948,
  "max": 0.08656199928373098,
  "times": [
   0.08656199928373098,
   0.08562891650944948,
   0.08638154156506062,
   0.08636962529271841,
   0.0865072924643755
  ],
  "md5": "6f4826a164a3e707ddfedd4b5b6d38e2"
 },
 {
  "program": "n-body",
  "size": "1 million steps",
  "lang": "rust",
  "runs": 5,
  "median": 0.03203687537461519,
  "min": 0.03169116657227278,
  "max": 0.03212766721844673,
  "times": [
   0.03169116657227278,
   0.032065083272755146,
   0.03203687537461519,
   0.03212766721844673,
   0.03185912501066923
  ],
  "md5": "6f4826a164a3e707ddfedd4b5b6d38e2"
 },
 {
  "program": "n-body",
  "size": "1 million steps",
  "lang": "go",
  "runs": 5,
  "median": 0.031459749676287174,
  "min": 0.031059875153005123,
  "max": 0.03165741730481386,
  "times": [
   0.031059875153005123,
   0.031459749676287174,
   0.03154745977371931,
   0.03165741730481386,
   0.031217041425406933
  ],
  "md5": "6f4826a164a3e707ddfedd4b5b6d38e2"
 },
 {
  "program": "n-body",
  "size": "1 million steps",
  "lang": "cpython",
  "runs": 5,
  "median": 2.3509047077968717,
  "min": 2.3413364170119166,
  "max": 2.3817698750644922,
  "times": [
   2.377620958723128,
   2.3413364170119166,
   2.3509047077968717,
   2.3421438755467534,
   2.3817698750644922
  ],
  "md5": "6f4826a164a3e707ddfedd4b5b6d38e2"
 },
 {
  "program": "n-body",
  "size": "1 million steps",
  "lang": "crow -i",
  "runs": 3,
  "median": 2.128798959776759,
  "min": 2.087382416240871,
  "max": 2.1333018336445093,
  "times": [
   2.128798959776759,
   2.1333018336445093,
   2.087382416240871
  ],
  "md5": "6f4826a164a3e707ddfedd4b5b6d38e2"
 },
 {
  "program": "spectral norm",
  "size": "n = 5,500",
  "lang": "crow",
  "runs": 5,
  "median": 0.08134200051426888,
  "min": 0.0795697495341301,
  "max": 0.0821498753502965,
  "times": [
   0.0821498753502965,
   0.08134200051426888,
   0.08207733277231455,
   0.07960616704076529,
   0.0795697495341301
  ],
  "md5": "1584fbeab0a952f314fbf0fd7621885f"
 },
 {
  "program": "spectral norm",
  "size": "n = 5,500",
  "lang": "rust",
  "runs": 5,
  "median": 0.07576483301818371,
  "min": 0.07173583284020424,
  "max": 0.07733591739088297,
  "times": [
   0.07173583284020424,
   0.07332850061357021,
   0.07579137478023767,
   0.07576483301818371,
   0.07733591739088297
  ],
  "md5": "1584fbeab0a952f314fbf0fd7621885f"
 },
 {
  "program": "spectral norm",
  "size": "n = 5,500",
  "lang": "go",
  "runs": 5,
  "median": 0.10663099959492683,
  "min": 0.10592270828783512,
  "max": 0.11032320838421583,
  "times": [
   0.10592270828783512,
   0.1062610000371933,
   0.10725591611117125,
   0.10663099959492683,
   0.11032320838421583
  ],
  "md5": "1584fbeab0a952f314fbf0fd7621885f"
 },
 {
  "program": "spectral norm",
  "size": "n = 5,500",
  "lang": "cpython",
  "runs": 5,
  "median": 8.844692875631154,
  "min": 8.673282207921147,
  "max": 8.948407417163253,
  "times": [
   8.948407417163253,
   8.686181458644569,
   8.844692875631154,
   8.897352125495672,
   8.673282207921147
  ],
  "md5": "1584fbeab0a952f314fbf0fd7621885f"
 },
 {
  "program": "spectral norm",
  "size": "n = 5,500",
  "lang": "crow -i",
  "runs": 3,
  "median": 6.570208791643381,
  "min": 6.543285749852657,
  "max": 6.594627249985933,
  "times": [
   6.594627249985933,
   6.570208791643381,
   6.543285749852657
  ],
  "md5": "1584fbeab0a952f314fbf0fd7621885f"
 },
 {
  "program": "k-nucleotide",
  "size": "5 million",
  "lang": "crow",
  "runs": 5,
  "median": 0.05431133322417736,
  "min": 0.053443250246346,
  "max": 0.05559858400374651,
  "times": [
   0.05559858400374651,
   0.05431133322417736,
   0.05362291540950537,
   0.055286542512476444,
   0.053443250246346
  ],
  "md5": "0fe2fd08243d139606d5b50e1e16ed71"
 },
 {
  "program": "k-nucleotide",
  "size": "5 million",
  "lang": "rust",
  "runs": 5,
  "median": 0.02782437577843666,
  "min": 0.027199416421353817,
  "max": 0.0286056250333786,
  "times": [
   0.027375875040888786,
   0.027199416421353817,
   0.02782437577843666,
   0.0286056250333786,
   0.028043375350534916
  ],
  "md5": "0fe2fd08243d139606d5b50e1e16ed71"
 },
 {
  "program": "k-nucleotide",
  "size": "5 million",
  "lang": "go",
  "runs": 5,
  "median": 0.1318800002336502,
  "min": 0.13100854121148586,
  "max": 0.1342447092756629,
  "times": [
   0.1342447092756629,
   0.13100854121148586,
   0.1318800002336502,
   0.13119020778685808,
   0.13189304154366255
  ],
  "md5": "0fe2fd08243d139606d5b50e1e16ed71"
 },
 {
  "program": "k-nucleotide",
  "size": "5 million",
  "lang": "cpython",
  "runs": 5,
  "median": 4.266343416646123,
  "min": 4.169315208680928,
  "max": 4.423589707352221,
  "times": [
   4.423589707352221,
   4.169315208680928,
   4.397985000163317,
   4.266343416646123,
   4.191954541951418
  ],
  "md5": "0fe2fd08243d139606d5b50e1e16ed71"
 },
 {
  "program": "k-nucleotide",
  "size": "5 million",
  "lang": "crow -i",
  "runs": 3,
  "median": 0.2608485845848918,
  "min": 0.2605542913079262,
  "max": 0.26258308440446854,
  "times": [
   0.2605542913079262,
   0.2608485845848918,
   0.26258308440446854
  ],
  "md5": "0fe2fd08243d139606d5b50e1e16ed71"
 },
 {
  "program": "reverse complement",
  "size": "5 million",
  "lang": "crow",
  "runs": 5,
  "median": 0.10683029145002365,
  "min": 0.10193170793354511,
  "max": 0.10796116665005684,
  "times": [
   0.10193170793354511,
   0.10683029145002365,
   0.10693079233169556,
   0.10646695829927921,
   0.10796116665005684
  ],
  "md5": "1fb8dee22daca7e37c0728146f0922c3"
 },
 {
  "program": "reverse complement",
  "size": "5 million",
  "lang": "rust",
  "runs": 5,
  "median": 0.06125212460756302,
  "min": 0.06003108248114586,
  "max": 0.0624286662787199,
  "times": [
   0.06003108248114586,
   0.06125212460756302,
   0.0624286662787199,
   0.06237270962446928,
   0.060746874660253525
  ],
  "md5": "1fb8dee22daca7e37c0728146f0922c3"
 },
 {
  "program": "reverse complement",
  "size": "5 million",
  "lang": "go",
  "runs": 5,
  "median": 0.0721376659348607,
  "min": 0.07046554051339626,
  "max": 0.07426141761243343,
  "times": [
   0.07050850056111813,
   0.07271674927324057,
   0.0721376659348607,
   0.07426141761243343,
   0.07046554051339626
  ],
  "md5": "1fb8dee22daca7e37c0728146f0922c3"
 },
 {
  "program": "reverse complement",
  "size": "5 million",
  "lang": "cpython",
  "runs": 5,
  "median": 0.23751424998044968,
  "min": 0.23499695863574743,
  "max": 0.24063954036682844,
  "times": [
   0.24056758359074593,
   0.23751250002533197,
   0.23499695863574743,
   0.24063954036682844,
   0.23751424998044968
  ],
  "md5": "1fb8dee22daca7e37c0728146f0922c3"
 },
 {
  "program": "reverse complement",
  "size": "5 million",
  "lang": "crow -i",
  "runs": 3,
  "median": 0.5537444585934281,
  "min": 0.5533660007640719,
  "max": 0.5548450835049152,
  "times": [
   0.5537444585934281,
   0.5533660007640719,
   0.5548450835049152
  ],
  "md5": "1fb8dee22daca7e37c0728146f0922c3"
 },
 {
  "program": "pidigits",
  "size": "5,000 digits",
  "lang": "crow",
  "runs": 5,
  "median": 0.30799200013279915,
  "min": 0.3053967924788594,
  "max": 0.3091033324599266,
  "times": [
   0.3091033324599266,
   0.3053967924788594,
   0.30762104224413633,
   0.30887812469154596,
   0.30799200013279915
  ],
  "md5": "37df65c33d3422c721a1987269d50eb9"
 },
 {
  "program": "pidigits",
  "size": "5,000 digits",
  "lang": "rust",
  "runs": 5,
  "median": 0.8134558331221342,
  "min": 0.8106924993917346,
  "max": 0.8214566251263022,
  "times": [
   0.8214566251263022,
   0.8134558331221342,
   0.8142017079517245,
   0.8128723343834281,
   0.8106924993917346
  ],
  "md5": "37df65c33d3422c721a1987269d50eb9"
 },
 {
  "program": "pidigits",
  "size": "5,000 digits",
  "lang": "go",
  "runs": 5,
  "median": 0.26464737486094236,
  "min": 0.264099458232522,
  "max": 0.26621820870786905,
  "times": [
   0.26588650047779083,
   0.26464737486094236,
   0.264099458232522,
   0.2644134173169732,
   0.26621820870786905
  ],
  "md5": "37df65c33d3422c721a1987269d50eb9"
 },
 {
  "program": "pidigits",
  "size": "5,000 digits",
  "lang": "cpython",
  "runs": 5,
  "median": 0.9903083741664886,
  "min": 0.986634916625917,
  "max": 0.9920188747346401,
  "times": [
   0.9920188747346401,
   0.9889799160882831,
   0.9903083741664886,
   0.986634916625917,
   0.9918315410614014
  ],
  "md5": "37df65c33d3422c721a1987269d50eb9"
 },
 {
  "program": "pidigits",
  "size": "5,000 digits",
  "lang": "crow -i",
  "runs": 3,
  "median": 0.3420087918639183,
  "min": 0.34037216752767563,
  "max": 0.3424863750115037,
  "times": [
   0.3420087918639183,
   0.34037216752767563,
   0.3424863750115037
  ],
  "md5": "37df65c33d3422c721a1987269d50eb9"
 },
 {
  "program": "binary trees",
  "size": "depth 18",
  "lang": "crow",
  "runs": 5,
  "median": 0.09356691595166922,
  "min": 0.09192362520843744,
  "max": 0.10606408305466175,
  "times": [
   0.09192362520843744,
   0.09448933321982622,
   0.10606408305466175,
   0.09356691595166922,
   0.09253508318215609
  ],
  "md5": "04083ec3542623e5258db423ba0d7ee5"
 },
 {
  "program": "binary trees",
  "size": "depth 18",
  "lang": "rust",
  "runs": 5,
  "median": 0.7552614593878388,
  "min": 0.7305715000256896,
  "max": 0.7952742492780089,
  "times": [
   0.7358365003019571,
   0.7552614593878388,
   0.7305715000256896,
   0.7569287922233343,
   0.7952742492780089
  ],
  "md5": "04083ec3542623e5258db423ba0d7ee5"
 },
 {
  "program": "binary trees",
  "size": "depth 18",
  "lang": "rust (mimalloc)",
  "runs": 5,
  "median": 0.1521114595234394,
  "min": 0.15104408282786608,
  "max": 0.15329466573894024,
  "times": [
   0.15324412565678358,
   0.15329466573894024,
   0.15168491657823324,
   0.1521114595234394,
   0.15104408282786608
  ],
  "md5": "04083ec3542623e5258db423ba0d7ee5"
 },
 {
  "program": "binary trees",
  "size": "depth 18",
  "lang": "go",
  "runs": 5,
  "median": 0.6415721671655774,
  "min": 0.6383472923189402,
  "max": 0.6574915423989296,
  "times": [
   0.6431570407003164,
   0.6574915423989296,
   0.6415721671655774,
   0.6403929581865668,
   0.6383472923189402
  ],
  "md5": "04083ec3542623e5258db423ba0d7ee5"
 },
 {
  "program": "binary trees",
  "size": "depth 18",
  "lang": "cpython",
  "runs": 5,
  "median": 0.6356999585404992,
  "min": 0.6260153753682971,
  "max": 0.6459652502089739,
  "times": [
   0.641351250000298,
   0.6459652502089739,
   0.6324360007420182,
   0.6356999585404992,
   0.6260153753682971
  ],
  "md5": "04083ec3542623e5258db423ba0d7ee5"
 },
 {
  "program": "binary trees",
  "size": "depth 18",
  "lang": "crow -i",
  "runs": 3,
  "median": 2.2552013341337442,
  "min": 2.2539211669936776,
  "max": 2.2572009582072496,
  "times": [
   2.2552013341337442,
   2.2572009582072496,
   2.2539211669936776
  ],
  "md5": "04083ec3542623e5258db423ba0d7ee5"
 }
] 

Fannkuch-redux

fannkuch.co

 --- fannkuch-redux: checksum and max flips over all permutations of 1..n
--- (benchmarks game), single-threaded
 
fn fannkuch[n]
    perm1 = range[n]
    perm = range[n]
    count = range[n]
    max_flips = 0
    checksum = 0
    perm_count = 0
    r = n
 
    while true
        while r gt 1
            count[r - 1] = r
            r = r - 1
 
        for i in range[n]
            perm[i] = perm1[i]
 
        flips = 0
        k = perm[0]
        while k gt 0
            i = 0
            j = k
            while i lt j
                t = perm[i]
                perm[i] = perm[j]
                perm[j] = t
                i = i + 1
                j = j - 1
            flips = flips + 1
            k = perm[0]
 
        if flips gt max_flips
            max_flips = flips
        if perm_count % 2 eq 0
            checksum = checksum + flips
        else
            checksum = checksum - flips
 
        --- next permutation
        while true
            if r eq n
                return [checksum, max_flips]
            p0 = perm1[0]
            for i in range[r]
                perm1[i] = perm1[i + 1]
            perm1[r] = p0
            count[r] = count[r] - 1
            if count[r] gt 0
                break
            r = r + 1
        perm_count = perm_count + 1
 
res = fannkuch[10]
log['`res[0]`']
log['Pfannkuchen(10) = `res[1]`'] 

fannkuch.rs

 fn fannkuch(n: usize) -> (i64, i64) {
    let mut perm1: Vec<usize> = (0..n).collect();
    let mut perm = vec![0usize; n];
    let mut count = vec![0usize; n];
    let (mut max_flips, mut checksum, mut perm_count) = (0i64, 0i64, 0i64);
    let mut r = n;
    loop {
        while r > 1 {
            count[r - 1] = r;
            r -= 1;
        }
        perm.copy_from_slice(&perm1);
        let mut flips = 0i64;
        let mut k = perm[0];
        while k > 0 {
            perm[..=k].reverse();
            flips += 1;
            k = perm[0];
        }
        if flips > max_flips {
            max_flips = flips;
        }
        checksum += if perm_count % 2 == 0 { flips } else { -flips };
        loop {
            if r == n {
                return (checksum, max_flips);
            }
            let p0 = perm1[0];
            for i in 0..r {
                perm1[i] = perm1[i + 1];
            }
            perm1[r] = p0;
            count[r] -= 1;
            if count[r] > 0 {
                break;
            }
            r += 1;
        }
        perm_count += 1;
    }
}
 
fn main() {
    let n: usize = std::env::args().nth(1).unwrap().parse().unwrap();
    let (c, m) = fannkuch(n);
    println!("{}\nPfannkuchen({}) = {}", c, n, m);
} 

fannkuch.go

 package main
 
import (
	"fmt"
	"os"
	"strconv"
)
 
func fannkuch(n int) (int, int) {
	perm1 := make([]int, n)
	for i := range perm1 {
		perm1[i] = i
	}
	perm := make([]int, n)
	count := make([]int, n)
	maxFlips, checksum, permCount := 0, 0, 0
	r := n
	for {
		for r > 1 {
			count[r-1] = r
			r--
		}
		copy(perm, perm1)
		flips := 0
		for k := perm[0]; k > 0; k = perm[0] {
			for i, j := 0, k; i < j; i, j = i+1, j-1 {
				perm[i], perm[j] = perm[j], perm[i]
			}
			flips++
		}
		if flips > maxFlips {
			maxFlips = flips
		}
		if permCount%2 == 0 {
			checksum += flips
		} else {
			checksum -= flips
		}
		for {
			if r == n {
				return checksum, maxFlips
			}
			p0 := perm1[0]
			for i := 0; i < r; i++ {
				perm1[i] = perm1[i+1]
			}
			perm1[r] = p0
			count[r]--
			if count[r] > 0 {
				break
			}
			r++
		}
		permCount++
	}
}
 
func main() {
	n, _ := strconv.Atoi(os.Args[1])
	c, m := fannkuch(n)
	fmt.Printf("%d\nPfannkuchen(%d) = %d\n", c, n, m)
} 

fannkuch.py

 import sys
 
 
def fannkuch(n):
    perm1 = list(range(n))
    count = [0] * n
    max_flips = checksum = perm_count = 0
    r = n
    while True:
        while r > 1:
            count[r - 1] = r
            r -= 1
        perm = perm1[:]
        flips = 0
        k = perm[0]
        while k:
            perm[:k + 1] = perm[k::-1]
            flips += 1
            k = perm[0]
        if flips > max_flips:
            max_flips = flips
        checksum += flips if perm_count % 2 == 0 else -flips
        while True:
            if r == n:
                return checksum, max_flips
            p0 = perm1[0]
            perm1[:r] = perm1[1:r + 1]
            perm1[r] = p0
            count[r] -= 1
            if count[r] > 0:
                break
            r += 1
        perm_count += 1
 
 
n = int(sys.argv[1])
c, m = fannkuch(n)
print(f"{c}\nPfannkuchen({n}) = {m}") 

N-body

nbody.co

 --- n-body (benchmarks game): the Sun and four giant planets, advanced n
--- steps of 0.01; prints the energy before and after
 
pi = 3.141592653589793
solar_mass = 4.0 * pi * pi
days = 365.24
 
x = [0.0, 4.84143144246472090, 8.34336671824457987, 12.8943695621391310, 15.3796971148509165]
y = [0.0, -1.16032004402742839, 4.12479856412430479, -15.1111514016986312, -25.9193146099879641]
z = [0.0, -0.103622044471123109, -0.403523417114321381, -0.223307578892655734, 0.179258772950371181]
vx = [0.0, 0.00166007664274403694 * days, -0.00276742510726862411 * days, 0.00296460137564761618 * days, 0.00268067772490389322 * days]
vy = [0.0, 0.00769901118419740425 * days, 0.00499852801234917238 * days, 0.00237847173959480950 * days, 0.00162824170038242295 * days]
vz = [0.0, -0.0000690460016972063023 * days, 0.0000230417297573763929 * days, -0.0000296589568540237556 * days, -0.0000951592254519715870 * days]
m = [solar_mass, 0.000954791938424326609 * solar_mass, 0.000285885980666130812 * solar_mass, 0.0000436624404335156298 * solar_mass, 0.0000515138902046611451 * solar_mass]
 
fn energy[x, y, z, vx, vy, vz, m]
    e = 0.0
    for i in range[5]
        e = e + 0.5 * m[i] * (vx[i] * vx[i] + vy[i] * vy[i] + vz[i] * vz[i])
        j = i + 1
        while j lt 5
            dx = x[i] - x[j]
            dy = y[i] - y[j]
            dz = z[i] - z[j]
            e = e - m[i] * m[j] / sqrt[dx * dx + dy * dy + dz * dz]
            j = j + 1
    return e
 
fn run[n, x, y, z, vx, vy, vz, m]
    dt = 0.01
    step = 0
    while step lt n
        i = 0
        while i lt 5
            j = i + 1
            while j lt 5
                dx = x[i] - x[j]
                dy = y[i] - y[j]
                dz = z[i] - z[j]
                d2 = dx * dx + dy * dy + dz * dz
                mag = dt / (d2 * sqrt[d2])
                vx[i] = vx[i] - dx * m[j] * mag
                vy[i] = vy[i] - dy * m[j] * mag
                vz[i] = vz[i] - dz * m[j] * mag
                vx[j] = vx[j] + dx * m[i] * mag
                vy[j] = vy[j] + dy * m[i] * mag
                vz[j] = vz[j] + dz * m[i] * mag
                j = j + 1
            i = i + 1
        for k in range[5]
            x[k] = x[k] + dt * vx[k]
            y[k] = y[k] + dt * vy[k]
            z[k] = z[k] + dt * vz[k]
        step = step + 1
    return [energy[x, y, z, vx, vy, vz, m]]
 
--- the Sun's velocity cancels the system's momentum
px = 0.0
py = 0.0
pz = 0.0
for k in range[5]
    px = px + vx[k] * m[k]
    py = py + vy[k] * m[k]
    pz = pz + vz[k] * m[k]
vx[0] = -px / solar_mass
vy[0] = -py / solar_mass
vz[0] = -pz / solar_mass
 
n = 50000000
log[fmt[energy[x, y, z, vx, vy, vz, m], 9]]
after = run[n, x, y, z, vx, vy, vz, m]
log[fmt[after[0], 9]] 

nbody_1m.co

 --- n-body (benchmarks game): the Sun and four giant planets, advanced n
--- steps of 0.01; prints the energy before and after
 
pi = 3.141592653589793
solar_mass = 4.0 * pi * pi
days = 365.24
 
x = [0.0, 4.84143144246472090, 8.34336671824457987, 12.8943695621391310, 15.3796971148509165]
y = [0.0, -1.16032004402742839, 4.12479856412430479, -15.1111514016986312, -25.9193146099879641]
z = [0.0, -0.103622044471123109, -0.403523417114321381, -0.223307578892655734, 0.179258772950371181]
vx = [0.0, 0.00166007664274403694 * days, -0.00276742510726862411 * days, 0.00296460137564761618 * days, 0.00268067772490389322 * days]
vy = [0.0, 0.00769901118419740425 * days, 0.00499852801234917238 * days, 0.00237847173959480950 * days, 0.00162824170038242295 * days]
vz = [0.0, -0.0000690460016972063023 * days, 0.0000230417297573763929 * days, -0.0000296589568540237556 * days, -0.0000951592254519715870 * days]
m = [solar_mass, 0.000954791938424326609 * solar_mass, 0.000285885980666130812 * solar_mass, 0.0000436624404335156298 * solar_mass, 0.0000515138902046611451 * solar_mass]
 
fn energy[x, y, z, vx, vy, vz, m]
    e = 0.0
    for i in range[5]
        e = e + 0.5 * m[i] * (vx[i] * vx[i] + vy[i] * vy[i] + vz[i] * vz[i])
        j = i + 1
        while j lt 5
            dx = x[i] - x[j]
            dy = y[i] - y[j]
            dz = z[i] - z[j]
            e = e - m[i] * m[j] / sqrt[dx * dx + dy * dy + dz * dz]
            j = j + 1
    return e
 
fn run[n, x, y, z, vx, vy, vz, m]
    dt = 0.01
    step = 0
    while step lt n
        i = 0
        while i lt 5
            j = i + 1
            while j lt 5
                dx = x[i] - x[j]
                dy = y[i] - y[j]
                dz = z[i] - z[j]
                d2 = dx * dx + dy * dy + dz * dz
                mag = dt / (d2 * sqrt[d2])
                vx[i] = vx[i] - dx * m[j] * mag
                vy[i] = vy[i] - dy * m[j] * mag
                vz[i] = vz[i] - dz * m[j] * mag
                vx[j] = vx[j] + dx * m[i] * mag
                vy[j] = vy[j] + dy * m[i] * mag
                vz[j] = vz[j] + dz * m[i] * mag
                j = j + 1
            i = i + 1
        for k in range[5]
            x[k] = x[k] + dt * vx[k]
            y[k] = y[k] + dt * vy[k]
            z[k] = z[k] + dt * vz[k]
        step = step + 1
    return [energy[x, y, z, vx, vy, vz, m]]
 
--- the Sun's velocity cancels the system's momentum
px = 0.0
py = 0.0
pz = 0.0
for k in range[5]
    px = px + vx[k] * m[k]
    py = py + vy[k] * m[k]
    pz = pz + vz[k] * m[k]
vx[0] = -px / solar_mass
vy[0] = -py / solar_mass
vz[0] = -pz / solar_mass
 
n = 1000000
log[fmt[energy[x, y, z, vx, vy, vz, m], 9]]
after = run[n, x, y, z, vx, vy, vz, m]
log[fmt[after[0], 9]] 

nbody.rs

 const PI: f64 = 3.141592653589793;
const SOLAR_MASS: f64 = 4.0 * PI * PI;
const DAYS: f64 = 365.24;
 
#[derive(Clone, Copy)]
struct Body {
    x: [f64; 3],
    v: [f64; 3],
    m: f64,
}
 
fn bodies() -> [Body; 5] {
    [
        Body { x: [0.0; 3], v: [0.0; 3], m: SOLAR_MASS },
        Body {
            x: [4.84143144246472090e+00, -1.16032004402742839e+00, -1.03622044471123109e-01],
            v: [1.66007664274403694e-03 * DAYS, 7.69901118419740425e-03 * DAYS, -6.90460016972063023e-05 * DAYS],
            m: 9.54791938424326609e-04 * SOLAR_MASS,
        },
        Body {
            x: [8.34336671824457987e+00, 4.12479856412430479e+00, -4.03523417114321381e-01],
            v: [-2.76742510726862411e-03 * DAYS, 4.99852801234917238e-03 * DAYS, 2.30417297573763929e-05 * DAYS],
            m: 2.85885980666130812e-04 * SOLAR_MASS,
        },
        Body {
            x: [1.28943695621391310e+01, -1.51111514016986312e+01, -2.23307578892655734e-01],
            v: [2.96460137564761618e-03 * DAYS, 2.37847173959480950e-03 * DAYS, -2.96589568540237556e-05 * DAYS],
            m: 4.36624404335156298e-05 * SOLAR_MASS,
        },
        Body {
            x: [1.53796971148509165e+01, -2.59193146099879641e+01, 1.79258772950371181e-01],
            v: [2.68067772490389322e-03 * DAYS, 1.62824170038242295e-03 * DAYS, -9.51592254519715870e-05 * DAYS],
            m: 5.15138902046611451e-05 * SOLAR_MASS,
        },
    ]
}
 
fn offset_momentum(b: &mut [Body; 5]) {
    let mut p = [0.0f64; 3];
    for body in b.iter() {
        for k in 0..3 {
            p[k] += body.v[k] * body.m;
        }
    }
    for k in 0..3 {
        b[0].v[k] = -p[k] / SOLAR_MASS;
    }
}
 
fn energy(b: &[Body; 5]) -> f64 {
    let mut e = 0.0;
    for i in 0..5 {
        e += 0.5 * b[i].m * (b[i].v[0] * b[i].v[0] + b[i].v[1] * b[i].v[1] + b[i].v[2] * b[i].v[2]);
        for j in i + 1..5 {
            let dx = b[i].x[0] - b[j].x[0];
            let dy = b[i].x[1] - b[j].x[1];
            let dz = b[i].x[2] - b[j].x[2];
            e -= b[i].m * b[j].m / (dx * dx + dy * dy + dz * dz).sqrt();
        }
    }
    e
}
 
fn advance(b: &mut [Body; 5], dt: f64) {
    for i in 0..5 {
        for j in i + 1..5 {
            let dx = b[i].x[0] - b[j].x[0];
            let dy = b[i].x[1] - b[j].x[1];
            let dz = b[i].x[2] - b[j].x[2];
            let d2 = dx * dx + dy * dy + dz * dz;
            let mag = dt / (d2 * d2.sqrt());
            let (mi, mj) = (b[i].m, b[j].m);
            b[i].v[0] -= dx * mj * mag;
            b[i].v[1] -= dy * mj * mag;
            b[i].v[2] -= dz * mj * mag;
            b[j].v[0] += dx * mi * mag;
            b[j].v[1] += dy * mi * mag;
            b[j].v[2] += dz * mi * mag;
        }
    }
    for body in b.iter_mut() {
        for k in 0..3 {
            body.x[k] += dt * body.v[k];
        }
    }
}
 
fn main() {
    let n: usize = std::env::args().nth(1).unwrap().parse().unwrap();
    let mut b = bodies();
    offset_momentum(&mut b);
    println!("{:.9}", energy(&b));
    for _ in 0..n {
        advance(&mut b, 0.01);
    }
    println!("{:.9}", energy(&b));
} 

nbody.go

 package main
 
import (
	"fmt"
	"math"
	"os"
	"strconv"
)
 
const solarMass = 4 * math.Pi * math.Pi
const days = 365.24
 
type body struct{ x, y, z, vx, vy, vz, m float64 }
 
func bodies() []body {
	return []body{
		{0, 0, 0, 0, 0, 0, solarMass},
		{4.84143144246472090e+00, -1.16032004402742839e+00, -1.03622044471123109e-01,
			1.66007664274403694e-03 * days, 7.69901118419740425e-03 * days, -6.90460016972063023e-05 * days,
			9.54791938424326609e-04 * solarMass},
		{8.34336671824457987e+00, 4.12479856412430479e+00, -4.03523417114321381e-01,
			-2.76742510726862411e-03 * days, 4.99852801234917238e-03 * days, 2.30417297573763929e-05 * days,
			2.85885980666130812e-04 * solarMass},
		{1.28943695621391310e+01, -1.51111514016986312e+01, -2.23307578892655734e-01,
			2.96460137564761618e-03 * days, 2.37847173959480950e-03 * days, -2.96589568540237556e-05 * days,
			4.36624404335156298e-05 * solarMass},
		{1.53796971148509165e+01, -2.59193146099879641e+01, 1.79258772950371181e-01,
			2.68067772490389322e-03 * days, 1.62824170038242295e-03 * days, -9.51592254519715870e-05 * days,
			5.15138902046611451e-05 * solarMass},
	}
}
 
func offsetMomentum(b []body) {
	var px, py, pz float64
	for _, o := range b {
		px += o.vx * o.m
		py += o.vy * o.m
		pz += o.vz * o.m
	}
	b[0].vx, b[0].vy, b[0].vz = -px/solarMass, -py/solarMass, -pz/solarMass
}
 
func energy(b []body) float64 {
	e := 0.0
	for i := range b {
		e += 0.5 * b[i].m * (b[i].vx*b[i].vx + b[i].vy*b[i].vy + b[i].vz*b[i].vz)
		for j := i + 1; j < len(b); j++ {
			dx, dy, dz := b[i].x-b[j].x, b[i].y-b[j].y, b[i].z-b[j].z
			e -= b[i].m * b[j].m / math.Sqrt(dx*dx+dy*dy+dz*dz)
		}
	}
	return e
}
 
func advance(b []body, dt float64) {
	for i := range b {
		for j := i + 1; j < len(b); j++ {
			dx, dy, dz := b[i].x-b[j].x, b[i].y-b[j].y, b[i].z-b[j].z
			d2 := dx*dx + dy*dy + dz*dz
			mag := dt / (d2 * math.Sqrt(d2))
			mi, mj := b[i].m, b[j].m
			b[i].vx -= dx * mj * mag
			b[i].vy -= dy * mj * mag
			b[i].vz -= dz * mj * mag
			b[j].vx += dx * mi * mag
			b[j].vy += dy * mi * mag
			b[j].vz += dz * mi * mag
		}
	}
	for i := range b {
		b[i].x += dt * b[i].vx
		b[i].y += dt * b[i].vy
		b[i].z += dt * b[i].vz
	}
}
 
func main() {
	n, _ := strconv.Atoi(os.Args[1])
	b := bodies()
	offsetMomentum(b)
	fmt.Printf("%.9f\n", energy(b))
	for i := 0; i < n; i++ {
		advance(b, 0.01)
	}
	fmt.Printf("%.9f\n", energy(b))
} 

nbody.py

 import sys
from math import pi, sqrt
 
SOLAR_MASS = 4 * pi * pi
DAYS = 365.24
 
# x, y, z, vx, vy, vz, mass
BODIES = [
    [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, SOLAR_MASS],
    [4.84143144246472090e+00, -1.16032004402742839e+00, -1.03622044471123109e-01,
     1.66007664274403694e-03 * DAYS, 7.69901118419740425e-03 * DAYS, -6.90460016972063023e-05 * DAYS,
     9.54791938424326609e-04 * SOLAR_MASS],
    [8.34336671824457987e+00, 4.12479856412430479e+00, -4.03523417114321381e-01,
     -2.76742510726862411e-03 * DAYS, 4.99852801234917238e-03 * DAYS, 2.30417297573763929e-05 * DAYS,
     2.85885980666130812e-04 * SOLAR_MASS],
    [1.28943695621391310e+01, -1.51111514016986312e+01, -2.23307578892655734e-01,
     2.96460137564761618e-03 * DAYS, 2.37847173959480950e-03 * DAYS, -2.96589568540237556e-05 * DAYS,
     4.36624404335156298e-05 * SOLAR_MASS],
    [1.53796971148509165e+01, -2.59193146099879641e+01, 1.79258772950371181e-01,
     2.68067772490389322e-03 * DAYS, 1.62824170038242295e-03 * DAYS, -9.51592254519715870e-05 * DAYS,
     5.15138902046611451e-05 * SOLAR_MASS],
]
 
 
def offset_momentum(b):
    px = sum(o[3] * o[6] for o in b)
    py = sum(o[4] * o[6] for o in b)
    pz = sum(o[5] * o[6] for o in b)
    b[0][3], b[0][4], b[0][5] = -px / SOLAR_MASS, -py / SOLAR_MASS, -pz / SOLAR_MASS
 
 
def energy(b):
    e = 0.0
    for i in range(len(b)):
        bi = b[i]
        e += 0.5 * bi[6] * (bi[3] * bi[3] + bi[4] * bi[4] + bi[5] * bi[5])
        for j in range(i + 1, len(b)):
            bj = b[j]
            dx, dy, dz = bi[0] - bj[0], bi[1] - bj[1], bi[2] - bj[2]
            e -= bi[6] * bj[6] / sqrt(dx * dx + dy * dy + dz * dz)
    return e
 
 
def run(n, dt=0.01):
    pairs = [(BODIES[i], BODIES[j]) for i in range(5) for j in range(i + 1, 5)]
    for _ in range(n):
        for a, c in pairs:
            dx, dy, dz = a[0] - c[0], a[1] - c[1], a[2] - c[2]
            d2 = dx * dx + dy * dy + dz * dz
            mag = dt / (d2 * sqrt(d2))
            ma, mc = a[6], c[6]
            a[3] -= dx * mc * mag
            a[4] -= dy * mc * mag
            a[5] -= dz * mc * mag
            c[3] += dx * ma * mag
            c[4] += dy * ma * mag
            c[5] += dz * ma * mag
        for o in BODIES:
            o[0] += dt * o[3]
            o[1] += dt * o[4]
            o[2] += dt * o[5]
 
 
n = int(sys.argv[1])
offset_momentum(BODIES)
print("%.9f" % energy(BODIES))
run(n)
print("%.9f" % energy(BODIES)) 

Spectral norm

spectralnorm.co

 --- spectral norm (benchmarks game): the largest singular value of the
--- infinite matrix A(i, j) = 1 / ((i+j)(i+j+1)/2 + i + 1), by power
--- iteration on A'A. Each product is a `for` over the output rows, so it
--- runs on every core; `cpu[1]` makes it single-threaded.
 
--- A(i, j)
fn a[i, j]
    return 1.0 / float[(i + j) * (i + j + 1) / 2 + i + 1]
 
--- row i of A v
fn row_av[i, v, n]
    s = 0.0
    j = 0
    while j lt n
        s = s + a[i, j] * v[j]
        j = j + 1
    return s
 
--- row i of A' v
fn row_atv[i, v, n]
    s = 0.0
    j = 0
    while j lt n
        s = s + a[j, i] * v[j]
        j = j + 1
    return s
 
n = 5500
 
u = for i in range[n]
    1.0
v = u
step = 0
while step lt 10
    t = for i in range[n]
        row_av[i, u, n]
    v = for i in range[n]
        row_atv[i, t, n]
    t = for i in range[n]
        row_av[i, v, n]
    u = for i in range[n]
        row_atv[i, t, n]
    step = step + 1
 
vbv = 0.0
vv = 0.0
for i in range[n]
    vbv = vbv + u[i] * v[i]
    vv = vv + v[i] * v[i]
log[fmt[sqrt[vbv / vv], 9]] 

spectralnorm.rs

 // usage: spectralnorm N THREADS   (THREADS = 1: single-threaded)
fn a(i: usize, j: usize) -> f64 {
    1.0 / (((i + j) * (i + j + 1) / 2 + i + 1) as f64)
}
 
// out[i] = sum_j A(i,j) v[j]   (transpose: A(j,i))
fn mul(out: &mut [f64], v: &[f64], transpose: bool, threads: usize) {
    let n = v.len();
    let row = |i: usize| -> f64 {
        let mut s = 0.0;
        for j in 0..n {
            s += if transpose { a(j, i) } else { a(i, j) } * v[j];
        }
        s
    };
    if threads == 1 {
        for i in 0..n {
            out[i] = row(i);
        }
    } else {
        let chunk = (n + threads - 1) / threads;
        std::thread::scope(|s| {
            for (c, o) in out.chunks_mut(chunk).enumerate() {
                let row = &row;
                s.spawn(move || {
                    for (k, oi) in o.iter_mut().enumerate() {
                        *oi = row(c * chunk + k);
                    }
                });
            }
        });
    }
}
 
fn main() {
    let args: Vec<usize> = std::env::args().skip(1).map(|s| s.parse().unwrap()).collect();
    let (n, threads) = (args[0], args[1]);
    let mut u = vec![1.0; n];
    let mut v = vec![0.0; n];
    let mut t = vec![0.0; n];
    for _ in 0..10 {
        mul(&mut t, &u, false, threads);
        mul(&mut v, &t, true, threads);
        mul(&mut t, &v, false, threads);
        mul(&mut u, &t, true, threads);
    }
    let (mut vbv, mut vv) = (0.0, 0.0);
    for i in 0..n {
        vbv += u[i] * v[i];
        vv += v[i] * v[i];
    }
    println!("{:.9}", (vbv / vv).sqrt());
} 

spectralnorm.go

 package main
 
// usage: spectralnorm N THREADS   (THREADS = 1: single-threaded)
 
import (
	"fmt"
	"math"
	"os"
	"strconv"
	"sync"
)
 
func a(i, j int) float64 {
	return 1.0 / float64((i+j)*(i+j+1)/2+i+1)
}
 
func mul(out, v []float64, transpose bool, threads int) {
	n := len(v)
	rows := func(lo, hi int) {
		for i := lo; i < hi; i++ {
			s := 0.0
			for j := 0; j < n; j++ {
				if transpose {
					s += a(j, i) * v[j]
				} else {
					s += a(i, j) * v[j]
				}
			}
			out[i] = s
		}
	}
	if threads == 1 {
		rows(0, n)
		return
	}
	chunk := (n + threads - 1) / threads
	var wg sync.WaitGroup
	for lo := 0; lo < n; lo += chunk {
		hi := min(lo+chunk, n)
		wg.Add(1)
		go func() { defer wg.Done(); rows(lo, hi) }()
	}
	wg.Wait()
}
 
func main() {
	n, _ := strconv.Atoi(os.Args[1])
	threads, _ := strconv.Atoi(os.Args[2])
	u, v, t := make([]float64, n), make([]float64, n), make([]float64, n)
	for i := range u {
		u[i] = 1
	}
	for k := 0; k < 10; k++ {
		mul(t, u, false, threads)
		mul(v, t, true, threads)
		mul(t, v, false, threads)
		mul(u, t, true, threads)
	}
	var vbv, vv float64
	for i := 0; i < n; i++ {
		vbv += u[i] * v[i]
		vv += v[i] * v[i]
	}
	fmt.Printf("%.9f\n", math.Sqrt(vbv/vv))
} 

spectralnorm.py

 # usage: spectralnorm.py N PROCS   (PROCS = 1: single-process)
import sys
from math import sqrt
from multiprocessing import Pool
 
 
def rows(args):
    lo, hi, v, transpose = args
    n = len(v)
    out = []
    for i in range(lo, hi):
        s = 0.0
        if transpose:
            for j in range(n):
                s += v[j] / ((i + j) * (i + j + 1) // 2 + j + 1)
        else:
            for j in range(n):
                s += v[j] / ((i + j) * (i + j + 1) // 2 + i + 1)
        out.append(s)
    return out
 
 
def mul(v, transpose, pool, procs):
    n = len(v)
    chunk = (n + procs - 1) // procs
    jobs = [(lo, min(lo + chunk, n), v, transpose) for lo in range(0, n, chunk)]
    parts = pool.map(rows, jobs) if pool else [rows(j) for j in jobs]
    return [x for p in parts for x in p]
 
 
if __name__ == "__main__":
    n, procs = int(sys.argv[1]), int(sys.argv[2])
    pool = Pool(procs) if procs > 1 else None
    u = [1.0] * n
    for _ in range(10):
        v = mul(mul(u, False, pool, procs), True, pool, procs)
        u = mul(mul(v, False, pool, procs), True, pool, procs)
    vbv = vv = 0.0
    for i in range(n):
        vbv += u[i] * v[i]
        vv += v[i] * v[i]
    print("%.9f" % sqrt(vbv / vv)) 

K-nucleotide

knucleotide.co

 --- k-nucleotide (benchmarks game): the frequencies of the 1- and 2-mers of
--- section THREE of a fasta file, and the counts of five fixed k-mers.
---
--- The section's lines joined are one text, and every count is `occurs` of
--- it — a search at the speed of reading the text. A pattern that cannot
--- overlap itself (each of the five, and every pair of two different
--- letters) occurs as often as `occurs` counts it; a doubled letter XX
--- overlaps itself, so its count is the X's that have a next letter less
--- the X's followed by another letter. Each list of counts is a `for`: the
--- counts run on every core, and `cpu[1]` makes it single-threaded.
 
use io
 
--- the names by count, largest first, ties by name; one 'name percent' a line
fn report[names, counts, total]
    n = len[names]
    used = for i in range[n]
        false
    done = 0
    while done lt n
        best = -1
        j = 0
        while j lt n
            if not used[j]
                if best lt 0
                    best = j
                else
                    if counts[j] gt counts[best]
                        best = j
            j = j + 1
        used[best] = true
        log['`names[best]` `fmt[100.0 * float[counts[best]] / float[total], 3]`']
        done = done + 1
    log['']
    return 0
 
rows = lines['fasta.txt']
 
first = 0
while not starts[rows[first], '>THREE']
    first = first + 1
stop = len[rows]
if rows[stop - 1] eq ''
    stop = stop - 1
seq = upper[join[slice[rows, first + 1, stop], '']]
n = len[seq]
 
base = ['A', 'C', 'G', 'T']
pairs = ['AA', 'AC', 'AG', 'AT', 'CA', 'CC', 'CG', 'CT', 'GA', 'GC', 'GG', 'GT', 'TA', 'TC', 'TG', 'TT']
pats = ['GGT', 'GGTA', 'GGTATT', 'GGTATTTTAATT', 'GGTATTTTAATTTATAGT']
 
ones = for b in base
    occurs[seq, b]
apart = for p in pairs
    occurs[seq, p]
found = for p in pats
    occurs[seq, p]
 
--- a doubled letter: the X's with a next letter, less those followed by
--- another letter
last = seq[n - 1]
twos = for k in range[16]
    bx = k / 4
    by = k % 4
    if bx ne by
        apart[k]
    else
        others = 0
        for o in range[4]
            if o ne bx
                others = others + apart[4 * bx + o]
        trailing = 0
        if last eq base[bx]
            trailing = 1
        ones[bx] - trailing - others
 
one = report[base, ones, n]
two = report[pairs, twos, n - 1]
for t in range[5]
    log['`found[t]`\t`pats[t]`'] 

knucleotide.rs

 // k-nucleotide (benchmarks game): read fasta on stdin, take section THREE and
// report the frequencies of 1- and 2-mers and the counts of five fixed k-mers.
// One pass of rolling 2-bit codes per chunk of the sequence; chunks overlap by
// 17 bases of warm-up so no window is lost, and are counted on THREADS workers.
// usage: knucleotide THREADS < fasta
use std::io::Read;
use std::sync::atomic::{AtomicUsize, Ordering};
 
const PATTERNS: [&str; 5] = ["GGT", "GGTA", "GGTATT", "GGTATTTTAATT", "GGTATTTTAATTTATAGT"];
const CHUNK: usize = 1 << 20;
 
fn code(s: &str) -> u64 {
    s.bytes().fold(0, |c, b| c << 2 | b2c(b) as u64)
}
fn b2c(b: u8) -> u8 {
    match b {
        b'A' => 0,
        b'C' => 1,
        b'G' => 2,
        _ => 3,
    }
}
 
#[derive(Default, Clone)]
struct Counts {
    c1: [u64; 4],
    c2: [u64; 16],
    pat: [u64; 5],
}
 
fn count_chunk(seq: &[u8], s: usize, e: usize, targets: &[(usize, u64); 5]) -> Counts {
    let mut r = Counts::default();
    let mut code = 0u64;
    for j in s.saturating_sub(17)..e {
        code = (code << 2 | seq[j] as u64) & ((1u64 << 36) - 1);
        if j < s {
            continue;
        }
        let have = j + 1;
        r.c1[(code & 3) as usize] += 1;
        if have >= 2 {
            r.c2[(code & 15) as usize] += 1;
        }
        for (t, &(k, tc)) in targets.iter().enumerate() {
            if have >= k && code & ((1u64 << (2 * k)) - 1) == tc {
                r.pat[t] += 1;
            }
        }
    }
    r
}
 
fn report(names: &[String], counts: &[u64], total: u64) {
    let mut idx: Vec<usize> = (0..names.len()).collect();
    idx.sort_by(|&a, &b| counts[b].cmp(&counts[a]).then(names[a].cmp(&names[b])));
    for i in idx {
        println!("{} {:.3}", names[i], 100.0 * counts[i] as f64 / total as f64);
    }
    println!();
}
 
fn main() {
    let threads: usize = std::env::args().nth(1).unwrap().parse().unwrap();
    let mut input = Vec::new();
    std::io::stdin().read_to_end(&mut input).unwrap();
    let mut seq: Vec<u8> = Vec::new();
    let mut in_three = false;
    for line in input.split(|&b| b == b'\n') {
        if line.starts_with(b">") {
            in_three = line.starts_with(b">THREE");
        } else if in_three {
            seq.extend(line.iter().map(|&b| b2c(b.to_ascii_uppercase())));
        }
    }
    let n = seq.len();
    let targets: [(usize, u64); 5] = std::array::from_fn(|i| (PATTERNS[i].len(), code(PATTERNS[i])));
    let nchunks = (n + CHUNK - 1) / CHUNK;
    let next = AtomicUsize::new(0);
    let total = std::thread::scope(|s| {
        let hs: Vec<_> = (0..threads)
            .map(|_| {
                s.spawn(|| {
                    let mut acc = Counts::default();
                    loop {
                        let c = next.fetch_add(1, Ordering::Relaxed);
                        if c >= nchunks {
                            return acc;
                        }
                        let r = count_chunk(&seq, c * CHUNK, ((c + 1) * CHUNK).min(n), &targets);
                        for i in 0..4 { acc.c1[i] += r.c1[i]; }
                        for i in 0..16 { acc.c2[i] += r.c2[i]; }
                        for i in 0..5 { acc.pat[i] += r.pat[i]; }
                    }
                })
            })
            .collect();
        let mut t = Counts::default();
        for h in hs {
            let r = h.join().unwrap();
            for i in 0..4 { t.c1[i] += r.c1[i]; }
            for i in 0..16 { t.c2[i] += r.c2[i]; }
            for i in 0..5 { t.pat[i] += r.pat[i]; }
        }
        t
    });
    let l1: Vec<String> = "ACGT".chars().map(|c| c.to_string()).collect();
    let l2: Vec<String> = "ACGT".chars().flat_map(|a| "ACGT".chars().map(move |b| format!("{}{}", a, b))).collect();
    report(&l1, &total.c1, n as u64);
    report(&l2, &total.c2, n as u64 - 1);
    for (i, p) in PATTERNS.iter().enumerate() {
        println!("{}\t{}", total.pat[i], p);
    }
} 

knucleotide.go

 package main
 
// k-nucleotide (benchmarks game): read fasta on stdin, take section THREE and
// report the frequencies of 1- and 2-mers and the counts of five fixed k-mers.
// One pass of rolling 2-bit codes per chunk of the sequence; chunks overlap by
// 17 bases of warm-up so no window is lost, and are counted on THREADS workers.
// usage: knucleotide THREADS < fasta
 
import (
	"bytes"
	"fmt"
	"io"
	"os"
	"sort"
	"strconv"
	"sync"
	"sync/atomic"
)
 
var patterns = []string{"GGT", "GGTA", "GGTATT", "GGTATTTTAATT", "GGTATTTTAATTTATAGT"}
 
const chunk = 1 << 20
 
func b2c(b byte) byte {
	switch b {
	case 'A', 'a':
		return 0
	case 'C', 'c':
		return 1
	case 'G', 'g':
		return 2
	}
	return 3
}
 
type counts struct {
	c1  [4]uint64
	c2  [16]uint64
	pat [5]uint64
}
 
func (a *counts) add(b *counts) {
	for i := range a.c1 {
		a.c1[i] += b.c1[i]
	}
	for i := range a.c2 {
		a.c2[i] += b.c2[i]
	}
	for i := range a.pat {
		a.pat[i] += b.pat[i]
	}
}
 
type target struct {
	k    int
	code uint64
}
 
func countChunk(seq []byte, s, e int, targets []target) counts {
	var r counts
	var code uint64
	start := s - 17
	if start < 0 {
		start = 0
	}
	for j := start; j < e; j++ {
		code = (code<<2 | uint64(seq[j])) & (1<<36 - 1)
		if j < s {
			continue
		}
		have := j + 1
		r.c1[code&3]++
		if have >= 2 {
			r.c2[code&15]++
		}
		for t, tg := range targets {
			if have >= tg.k && code&(1<<(2*uint(tg.k))-1) == tg.code {
				r.pat[t]++
			}
		}
	}
	return r
}
 
func report(names []string, cnt []uint64, total uint64) {
	idx := make([]int, len(names))
	for i := range idx {
		idx[i] = i
	}
	sort.Slice(idx, func(a, b int) bool {
		if cnt[idx[a]] != cnt[idx[b]] {
			return cnt[idx[a]] > cnt[idx[b]]
		}
		return names[idx[a]] < names[idx[b]]
	})
	for _, i := range idx {
		fmt.Printf("%s %.3f\n", names[i], 100.0*float64(cnt[i])/float64(total))
	}
	fmt.Println()
}
 
func main() {
	threads, _ := strconv.Atoi(os.Args[1])
	input, _ := io.ReadAll(os.Stdin)
	seq := make([]byte, 0, len(input))
	inThree := false
	for _, line := range bytes.Split(input, []byte{'\n'}) {
		if len(line) > 0 && line[0] == '>' {
			inThree = bytes.HasPrefix(line, []byte(">THREE"))
		} else if inThree {
			for _, b := range line {
				seq = append(seq, b2c(b))
			}
		}
	}
	n := len(seq)
	targets := make([]target, len(patterns))
	for i, p := range patterns {
		var c uint64
		for j := 0; j < len(p); j++ {
			c = c<<2 | uint64(b2c(p[j]))
		}
		targets[i] = target{len(p), c}
	}
	nchunks := (n + chunk - 1) / chunk
	var next int64 = -1
	res := make([]counts, threads)
	var wg sync.WaitGroup
	for w := 0; w < threads; w++ {
		wg.Add(1)
		go func(w int) {
			defer wg.Done()
			for {
				c := int(atomic.AddInt64(&next, 1))
				if c >= nchunks {
					return
				}
				r := countChunk(seq, c*chunk, min((c+1)*chunk, n), targets)
				res[w].add(&r)
			}
		}(w)
	}
	wg.Wait()
	var total counts
	for w := range res {
		total.add(&res[w])
	}
	l1 := []string{"A", "C", "G", "T"}
	var l2 []string
	for _, a := range l1 {
		for _, b := range l1 {
			l2 = append(l2, a+b)
		}
	}
	report(l1, total.c1[:], uint64(n))
	report(l2, total.c2[:], uint64(n-1))
	for i, p := range patterns {
		fmt.Printf("%d\t%s\n", total.pat[i], p)
	}
} 

knucleotide.py

 # k-nucleotide (benchmarks game): read fasta on stdin, take section THREE and
# report the frequencies of 1- and 2-mers and the counts of five fixed k-mers.
# usage: knucleotide.py < fasta
import sys
from collections import Counter
 
PATTERNS = ["GGT", "GGTA", "GGTATT", "GGTATTTTAATT", "GGTATTTTAATTTATAGT"]
 
 
def read_three():
    parts, in_three = [], False
    for line in sys.stdin:
        if line.startswith(">"):
            in_three = line.startswith(">THREE")
        elif in_three:
            parts.append(line.strip().upper())
    return "".join(parts)
 
 
def frequencies(seq, k):
    counts = Counter(seq[i:i + k] for i in range(len(seq) - k + 1))
    total = len(seq) - k + 1
    for name, c in sorted(counts.items(), key=lambda kv: (-kv[1], kv[0])):
        print("%s %.3f" % (name, 100.0 * c / total))
    print()
 
 
def count_overlapping(seq, pat):
    n, i = 0, seq.find(pat)
    while i >= 0:
        n += 1
        i = seq.find(pat, i + 1)
    return n
 
 
seq = read_three()
frequencies(seq, 1)
frequencies(seq, 2)
for p in PATTERNS:
    print("%d\t%s" % (count_overlapping(seq, p), p)) 

Reverse complement

revcomp.co

 --- reverse-complement (benchmarks game): each sequence of a fasta file,
--- reverse-complemented (IUB codes) and written in lines of 60.
---
--- A section's lines joined are one text: `translate` maps each code to its
--- complement in one pass, `reverse` turns the text round, and the answer
--- is cut into lines of 60, a `for` over them (they run on every core, and
--- `cpu[1]` makes it single-threaded).
 
use io
 
fn revcomp[body]
    seq = reverse[translate[join[body, ''], 'ACGTUMRWSYKVHDBNacgtumrwsykvhdbn', 'TGCAAKYWSRMBDHVNTGCAAKYWSRMBDHVN']]
    n = len[seq]
    outs = for k in range[(n + 59) / 60]
        slice[seq, k * 60, min[n, k * 60 + 60]]
    return join[outs, '\n']
 
rows = lines['fasta.txt']
stop = len[rows]
if rows[stop - 1] eq ''
    stop = stop - 1
 
--- the section headers
heads = []
i = 0
while i lt stop
    if starts[rows[i], '>']
        heads = push[heads, i]
    i = i + 1
heads = push[heads, stop]
 
s = 0
while s lt len[heads] - 1
    log[rows[heads[s]]]
    log[revcomp[slice[rows, heads[s] + 1, heads[s + 1]]]]
    s = s + 1 

revcomp.rs

 // reverse-complement (benchmarks game): read fasta on stdin, write each
// sequence reverse-complemented (IUB codes) in lines of 60.
// Output lines are filled independently, THREADS at a time.
// usage: revcomp THREADS < fasta > output
use std::io::{Read, Write};
use std::sync::Mutex;
 
const WIDTH: usize = 60;
const CHUNK_LINES: usize = 4096;
 
fn table() -> [u8; 256] {
    let mut t = [0u8; 256];
    for i in 0..256 {
        t[i] = i as u8;
    }
    for (a, b) in "ACGTUMRWSYKVHDBN".bytes().zip("TGCAAKYWSRMBDHVN".bytes()) {
        t[a as usize] = b;
        t[a.to_ascii_lowercase() as usize] = b;
    }
    t
}
 
fn rc_section(seq: &[u8], t: &[u8; 256], threads: usize) -> Vec<u8> {
    let n = seq.len();
    let lines = (n + WIDTH - 1) / WIDTH;
    let mut out = vec![0u8; n + lines];
    let it = Mutex::new(out.chunks_mut(CHUNK_LINES * (WIDTH + 1)).enumerate());
    std::thread::scope(|s| {
        for _ in 0..threads {
            s.spawn(|| loop {
                let item = it.lock().unwrap().next();
                let Some((c, buf)) = item else { break };
                let mut o = 0;
                let mut line = c * CHUNK_LINES;
                while o < buf.len() {
                    let w = WIDTH.min(buf.len() - o - 1);
                    for k in 0..w {
                        buf[o + k] = t[seq[n - 1 - (line * WIDTH + k)] as usize];
                    }
                    buf[o + w] = b'\n';
                    o += w + 1;
                    line += 1;
                }
            });
        }
    });
    out
}
 
fn main() {
    let threads: usize = std::env::args().nth(1).unwrap().parse().unwrap();
    let mut input = Vec::new();
    std::io::stdin().read_to_end(&mut input).unwrap();
    let t = table();
    let out = std::io::stdout();
    let mut out = out.lock();
    let mut header: Option<&[u8]> = None;
    let mut seq: Vec<u8> = Vec::new();
    let mut flush = |header: &Option<&[u8]>, seq: &mut Vec<u8>, out: &mut std::io::StdoutLock| {
        if let Some(h) = header {
            out.write_all(h).unwrap();
            out.write_all(b"\n").unwrap();
            out.write_all(&rc_section(seq, &t, threads)).unwrap();
        }
        seq.clear();
    };
    for line in input.split(|&b| b == b'\n') {
        if line.first() == Some(&b'>') {
            flush(&header, &mut seq, &mut out);
            header = Some(line);
        } else {
            seq.extend_from_slice(line);
        }
    }
    flush(&header, &mut seq, &mut out);
} 

revcomp.go

 package main
 
// reverse-complement (benchmarks game): read fasta on stdin, write each
// sequence reverse-complemented (IUB codes) in lines of 60.
// Output lines are filled independently, THREADS at a time.
// usage: revcomp THREADS < fasta > output
 
import (
	"bufio"
	"bytes"
	"io"
	"os"
	"strconv"
	"sync"
	"sync/atomic"
)
 
const width = 60
const chunkLines = 4096
 
func table() [256]byte {
	var t [256]byte
	for i := range t {
		t[i] = byte(i)
	}
	from, to := "ACGTUMRWSYKVHDBN", "TGCAAKYWSRMBDHVN"
	for i := 0; i < len(from); i++ {
		t[from[i]] = to[i]
		t[from[i]+32] = to[i]
	}
	return t
}
 
func rcSection(seq []byte, t *[256]byte, threads int) []byte {
	n := len(seq)
	lines := (n + width - 1) / width
	out := make([]byte, n+lines)
	step := chunkLines * (width + 1)
	nchunks := (len(out) + step - 1) / step
	var next int64 = -1
	var wg sync.WaitGroup
	for w := 0; w < threads; w++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for {
				c := int(atomic.AddInt64(&next, 1))
				if c >= nchunks {
					return
				}
				buf := out[c*step:min((c+1)*step, len(out))]
				line := c * chunkLines
				for o := 0; o < len(buf); {
					w := min(width, len(buf)-o-1)
					for k := 0; k < w; k++ {
						buf[o+k] = t[seq[n-1-(line*width+k)]]
					}
					buf[o+w] = '\n'
					o += w + 1
					line++
				}
			}
		}()
	}
	wg.Wait()
	return out
}
 
func main() {
	threads, _ := strconv.Atoi(os.Args[1])
	input, _ := io.ReadAll(os.Stdin)
	t := table()
	out := bufio.NewWriterSize(os.Stdout, 1<<20)
	defer out.Flush()
	var header []byte
	var seq []byte
	flush := func() {
		if header != nil {
			out.Write(header)
			out.WriteByte('\n')
			out.Write(rcSection(seq, &t, threads))
		}
		seq = seq[:0]
	}
	for _, line := range bytes.Split(input, []byte{'\n'}) {
		if len(line) > 0 && line[0] == '>' {
			flush()
			header = line
		} else {
			seq = append(seq, line...)
		}
	}
	flush()
} 

revcomp.py

 # reverse-complement (benchmarks game): read fasta on stdin, write each
# sequence reverse-complemented (IUB codes) in lines of 60.
# usage: revcomp.py < fasta > output
import sys
 
TABLE = bytes.maketrans(b"ACGTUMRWSYKVHDBNacgtumrwsykvhdbn", b"TGCAAKYWSRMBDHVNTGCAAKYWSRMBDHVN")
 
 
def emit(header, parts, out):
    if header is None:
        return
    seq = b"".join(parts).translate(TABLE)[::-1]
    out.write(header + b"\n")
    out.write(b"\n".join(seq[i:i + 60] for i in range(0, len(seq), 60)) + b"\n")
 
 
out = sys.stdout.buffer
header, parts = None, []
for line in sys.stdin.buffer.read().split(b"\n"):
    if line.startswith(b">"):
        emit(header, parts, out)
        header, parts = line, []
    else:
        parts.append(line)
emit(header, parts, out) 

Fasta, the input of k-nucleotide and reverse complement

fasta.go

 package main
 
// fasta (benchmarks game). The LCG is jumped ahead per chunk of lines, so the
// chunks are independent and the output is the same for any thread count.
// usage: fasta N THREADS   (THREADS = 1: single-threaded)   > output
 
import (
	"bufio"
	"os"
	"strconv"
	"sync"
	"sync/atomic"
)
 
const im, ia, ic = 139968, 3877, 29573
const width = 60
const chunkLines = 1024
 
const alu = "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA"
 
type sym struct {
	c byte
	p float64
}
 
var iub = []sym{{'a', 0.27}, {'c', 0.12}, {'g', 0.12}, {'t', 0.27}, {'B', 0.02}, {'D', 0.02}, {'H', 0.02}, {'K', 0.02}, {'M', 0.02}, {'N', 0.02}, {'R', 0.02}, {'S', 0.02}, {'V', 0.02}, {'W', 0.02}, {'Y', 0.02}}
var homo = []sym{{'a', 0.3029549426680}, {'c', 0.1979883004921}, {'g', 0.1975473066391}, {'t', 0.3015094502008}}
 
func jump(s, k uint64) uint64 {
	ra, rc := uint64(1), uint64(0)
	a, c := uint64(ia), uint64(ic)
	for ; k > 0; k >>= 1 {
		if k&1 == 1 {
			rc = (ra*c + rc) % im
			ra = ra * a % im
		}
		c = (a*c + c) % im
		a = a * a % im
	}
	return (ra*s + rc) % im
}
 
func runSection(header string, total, workers int, fill func(c int, buf []byte)) []byte {
	lines := (total + width - 1) / width
	out := make([]byte, total+lines)
	step := chunkLines * (width + 1)
	nchunks := (len(out) + step - 1) / step
	var next int64 = -1
	var wg sync.WaitGroup
	for w := 0; w < workers; w++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for {
				c := int(atomic.AddInt64(&next, 1))
				if c >= nchunks {
					return
				}
				fill(c, out[c*step:min((c+1)*step, len(out))])
			}
		}()
	}
	wg.Wait()
	return append([]byte(header+"\n"), out...)
}
 
func aluFill(c int, buf []byte) {
	pos := c * chunkLines * width
	for o := 0; o < len(buf); {
		w := min(width, len(buf)-o-1)
		for k := 0; k < w; k++ {
			buf[o+k] = alu[(pos+k)%len(alu)]
		}
		buf[o+w] = '\n'
		o += w + 1
		pos += w
	}
}
 
func randFill(seed uint64, table []sym, c int, buf []byte) {
	cum := make([]float64, len(table))
	acc := 0.0
	for i, s := range table {
		acc += s.p
		cum[i] = acc
	}
	last := len(table) - 1
	st := jump(seed, uint64(c*chunkLines*width))
	for o := 0; o < len(buf); {
		w := min(width, len(buf)-o-1)
		for k := 0; k < w; k++ {
			st = (st*ia + ic) % im
			r := float64(st) / float64(im)
			i := 0
			for i < last && r >= cum[i] {
				i++
			}
			buf[o+k] = table[i].c
		}
		buf[o+w] = '\n'
		o += w + 1
	}
}
 
func main() {
	n, _ := strconv.Atoi(os.Args[1])
	workers, _ := strconv.Atoi(os.Args[2])
	seed2 := uint64(42)
	seed3 := jump(seed2, uint64(3*n))
	out := bufio.NewWriterSize(os.Stdout, 1<<20)
	defer out.Flush()
	out.Write(runSection(">ONE Homo sapiens alu", 2*n, workers, aluFill))
	out.Write(runSection(">TWO IUB ambiguity codes", 3*n, workers, func(c int, b []byte) { randFill(seed2, iub, c, b) }))
	out.Write(runSection(">THREE Homo sapiens frequency", 5*n, workers, func(c int, b []byte) { randFill(seed3, homo, c, b) }))
} 

Pidigits

pidigits.co

 --- pidigits (benchmarks game): Gibbons' unbounded spigot. An int is a whole
--- number of any size (spec, Numbers That Keep Every Digit), so the spigot
--- is its arithmetic, as Python's is: the compiled program holds its growing
--- numbers in the runtime's big ints and its counters in 64 bits.
---
--- With u = r + 3q (never negative) the spigot needs no signed numbers:
---   emit m:  u <- 10(u - m t), m <- floor(u / t) of the new u, q <- 10q
---   else:    m <- floor((q(k-1) + u l) / (t l)), u <- (u - q) l + 3qk,
---            q <- qk, t <- tl, l <- l+2, k <- k+1
--- and it emits m when q + u < (m+1) t. The sequential algorithm has no
--- loop to run on several cores.
 
n = 5000
 
q = 1
u = 3
t = 1
k = 1
l = 3
m = 3
count = 0
line = ''
while count lt n
    if q + u lt (m + 1) * t
        line = '`line``m`'
        count = count + 1
        if count % 10 eq 0
            log['`line`\t:`count`']
            line = ''
        u = 10 * (u - m * t)
        m = u / t
        q = 10 * q
    else
        m = (q * (k - 1) + u * l) / (t * l)
        u = (u - q) * l + 3 * q * k
        q = q * k
        t = t * l
        l = l + 2
        k = k + 1
if line ne ''
    log['`fmt[line, width = 10, align = \'left\']`\t:`n`'] 

pidigits.rs

 // pidigits (benchmarks game): Gibbons' unbounded spigot with num-bigint
// (pure Rust; the site's fast Rust programs use GMP).
// usage: pidigits N
use num_bigint::BigInt;
use num_traits::{One, Zero};
 
fn main() {
    let n: usize = std::env::args().nth(1).unwrap().parse().unwrap();
    let (mut q, mut r, mut t) = (BigInt::one(), BigInt::zero(), BigInt::one());
    let (mut k, mut m, mut x) = (BigInt::one(), BigInt::from(3), BigInt::from(3));
    let mut line = String::new();
    let mut out = 0;
    while out < n {
        if (&q << 2) + &r - &t < &m * &t {
            line.push_str(&m.to_string());
            out += 1;
            if out % 10 == 0 {
                println!("{}\t:{}", line, out);
                line.clear();
            }
            let nm = (BigInt::from(10) * (&q * 3 + &r)) / &t - &m * 10;
            r = (&r - &m * &t) * 10;
            q *= 10;
            m = nm;
        } else {
            let tx = &t * &x;
            let nm = (&q * (&k * 7 + 2) + &r * &x) / &tx;
            r = (&q * 2 + &r) * &x;
            q *= &k;
            t = tx;
            k += 1;
            m = nm;
            x += 2;
        }
    }
    if !line.is_empty() {
        println!("{:<10}\t:{}", line, n);
    }
} 

pidigits-Cargo.toml

 [package]
name = "pidigits"
version = "0.1.0"
edition = "2021"
[dependencies]
num-bigint = "0.4"
num-traits = "0.2"
num-integer = "0.1"
[profile.release]
opt-level = 3
lto = "fat"
codegen-units = 1 

pidigits.go

 package main
 
// pidigits (benchmarks game): Gibbons' unbounded spigot with math/big.
// usage: pidigits N
 
import (
	"fmt"
	"math/big"
	"os"
	"strconv"
	"strings"
)
 
func main() {
	n, _ := strconv.Atoi(os.Args[1])
	q, r, t := big.NewInt(1), big.NewInt(0), big.NewInt(1)
	k, m, x := big.NewInt(1), big.NewInt(3), big.NewInt(3)
	var tmp1, tmp2, tmp3 big.Int
	ten, two, seven := big.NewInt(10), big.NewInt(2), big.NewInt(7)
	var line strings.Builder
	out := 0
	for out < n {
		// 4q + r - t < m t
		tmp1.Lsh(q, 2)
		tmp1.Add(&tmp1, r)
		tmp1.Sub(&tmp1, t)
		tmp2.Mul(m, t)
		if tmp1.Cmp(&tmp2) < 0 {
			line.WriteString(m.String())
			out++
			if out%10 == 0 {
				fmt.Printf("%s\t:%d\n", line.String(), out)
				line.Reset()
			}
			// q, r, m = 10q, 10(r - m t), 10(3q + r)/t - 10m
			tmp1.Mul(q, big.NewInt(3))
			tmp1.Add(&tmp1, r)
			tmp1.Mul(&tmp1, ten)
			tmp1.Quo(&tmp1, t)
			tmp3.Mul(m, ten)
			tmp1.Sub(&tmp1, &tmp3)
			r.Sub(r, &tmp2)
			r.Mul(r, ten)
			q.Mul(q, ten)
			m.Set(&tmp1)
		} else {
			// q, r, t, k, m, x = qk, (2q + r)x, tx, k+1, (q(7k+2) + rx)/(tx), x+2
			tmp1.Mul(k, seven)
			tmp1.Add(&tmp1, two)
			tmp1.Mul(&tmp1, q)
			tmp2.Mul(r, x)
			tmp1.Add(&tmp1, &tmp2)
			tmp3.Mul(t, x)
			tmp1.Quo(&tmp1, &tmp3)
			r.Add(r, new(big.Int).Lsh(q, 1))
			r.Mul(r, x)
			q.Mul(q, k)
			t.Set(&tmp3)
			k.Add(k, big.NewInt(1))
			m.Set(&tmp1)
			x.Add(x, two)
		}
	}
	if line.Len() > 0 {
		fmt.Printf("%-10s\t:%d\n", line.String(), n)
	}
} 

pidigits.py

 # pidigits (benchmarks game): Gibbons' unbounded spigot with Python's ints.
# usage: pidigits.py N
import sys
 
 
def digits(n):
    q, r, t, k, m, x = 1, 0, 1, 1, 3, 3
    out = 0
    while out < n:
        if 4 * q + r - t < m * t:
            yield m
            out += 1
            q, r, m = 10 * q, 10 * (r - m * t), (10 * (3 * q + r)) // t - 10 * m
        else:
            q, r, t, k, m, x = q * k, (2 * q + r) * x, t * x, k + 1, (q * (7 * k + 2) + r * x) // (t * x), x + 2
 
 
n = int(sys.argv[1])
line = ""
for i, d in enumerate(digits(n), 1):
    line += str(d)
    if i % 10 == 0:
        print("%s\t:%d" % (line, i))
        line = ""
if line:
    print("%s\t:%d" % (line.ljust(10), n)) 

Binary trees

binarytrees.co

 --- binary-trees (benchmarks game): build and check many trees of growing
--- depth. At each depth the trees are independent, so they are a `for`: they
--- run on every core, and `cpu[1]` makes it single-threaded.
 
--- a leaf is told by its own flag: a child is a Tree or 0, and a Tree is not
--- compared with 0
struct Tree [left, right, leaf]
 
fn make_tree[depth]
    if depth eq 0
        return Tree[0, 0, true]
    return Tree[make_tree[depth - 1], make_tree[depth - 1], false]
 
fn check_tree[tree]
    if tree.leaf
        return 1
    return 1 + check_tree[tree.left] + check_tree[tree.right]
 
--- the check of one tree of this depth
fn tree_check[depth]
    return check_tree[make_tree[depth]]
 
n = 18
min_depth = 4
max_depth = max[n, min_depth + 2]
 
stretch = max_depth + 1
log['stretch tree of depth `stretch`\t check: `tree_check[stretch]`']
 
long_lived = make_tree[max_depth]
 
depth = min_depth
while depth lte max_depth
    iterations = 2 ^ (max_depth - depth + min_depth)
    checks = for j in range[iterations]
        tree_check[depth]
    total = 0
    for c in checks
        total = total + c
    log['`iterations`\t trees of depth `depth`\t check: `total`']
    depth = depth + 2
 
log['long lived tree of depth `max_depth`\t check: `check_tree[long_lived]`'] 

binarytrees.rs

 // binary-trees (benchmarks game). At each depth the trees are built and
// checked THREADS at a time (1 = single-threaded).
// usage: binarytrees N THREADS
use std::sync::atomic::{AtomicU64, Ordering};
 
struct Node(Option<Box<Node>>, Option<Box<Node>>);
 
fn make(d: u32) -> Node {
    if d == 0 {
        Node(None, None)
    } else {
        Node(Some(Box::new(make(d - 1))), Some(Box::new(make(d - 1))))
    }
}
 
fn check(n: &Node) -> u64 {
    1 + n.0.as_ref().map_or(0, |c| check(c)) + n.1.as_ref().map_or(0, |c| check(c))
}
 
fn main() {
    let a: Vec<usize> = std::env::args().skip(1).map(|s| s.parse().unwrap()).collect();
    let (n, threads) = (a[0] as u32, a[1]);
    let min_depth = 4u32;
    let max_depth = n.max(min_depth + 2);
    let stretch = max_depth + 1;
    println!("stretch tree of depth {}\t check: {}", stretch, check(&make(stretch)));
    let long_lived = make(max_depth);
    let mut d = min_depth;
    while d <= max_depth {
        let iterations = 1u64 << (max_depth - d + min_depth);
        let next = AtomicU64::new(0);
        let total = AtomicU64::new(0);
        std::thread::scope(|s| {
            for _ in 0..threads {
                s.spawn(|| {
                    let mut sum = 0;
                    // take iterations in blocks to keep the counter cold
                    loop {
                        let start = next.fetch_add(64, Ordering::Relaxed);
                        if start >= iterations {
                            break;
                        }
                        for _ in start..(start + 64).min(iterations) {
                            sum += check(&make(d));
                        }
                    }
                    total.fetch_add(sum, Ordering::Relaxed);
                });
            }
        });
        println!("{}\t trees of depth {}\t check: {}", iterations, d, total.load(Ordering::Relaxed));
        d += 2;
    }
    println!("long lived tree of depth {}\t check: {}", max_depth, check(&long_lived));
} 

binarytrees-mimalloc-Cargo.toml

 [package]
name = "bt_mi"
version = "0.1.0"
edition = "2021"
[dependencies]
mimalloc = "0.1"
[profile.release]
opt-level = 3
lto = "fat"
codegen-units = 1 

binarytrees.go

 package main
 
// binary-trees (benchmarks game). At each depth the trees are built and
// checked THREADS at a time (1 = single-threaded).
// usage: binarytrees N THREADS
 
import (
	"fmt"
	"os"
	"strconv"
	"sync"
	"sync/atomic"
)
 
type node struct{ l, r *node }
 
func make_(d int) *node {
	if d == 0 {
		return &node{}
	}
	return &node{make_(d - 1), make_(d - 1)}
}
 
func check(n *node) int64 {
	if n.l == nil {
		return 1
	}
	return 1 + check(n.l) + check(n.r)
}
 
func main() {
	n, _ := strconv.Atoi(os.Args[1])
	threads, _ := strconv.Atoi(os.Args[2])
	minDepth := 4
	maxDepth := max(n, minDepth+2)
	stretch := maxDepth + 1
	fmt.Printf("stretch tree of depth %d\t check: %d\n", stretch, check(make_(stretch)))
	longLived := make_(maxDepth)
	for d := minDepth; d <= maxDepth; d += 2 {
		iterations := int64(1) << uint(maxDepth-d+minDepth)
		var next, total int64
		var wg sync.WaitGroup
		for t := 0; t < threads; t++ {
			wg.Add(1)
			go func() {
				defer wg.Done()
				var sum int64
				for {
					start := atomic.AddInt64(&next, 64) - 64
					if start >= iterations {
						break
					}
					for i := start; i < min(start+64, iterations); i++ {
						sum += check(make_(d))
					}
				}
				atomic.AddInt64(&total, sum)
			}()
		}
		wg.Wait()
		fmt.Printf("%d\t trees of depth %d\t check: %d\n", iterations, d, total)
	}
	fmt.Printf("long lived tree of depth %d\t check: %d\n", maxDepth, check(longLived))
} 

binarytrees.py

 # binary-trees (benchmarks game). At each depth the trees are built and
# checked PROCS at a time (1 = single-process).
# usage: binarytrees.py N PROCS
import sys
from multiprocessing import Pool
 
 
def make(d):
    if d == 0:
        return (None, None)
    return (make(d - 1), make(d - 1))
 
 
def check(t):
    l, r = t
    if l is None:
        return 1
    return 1 + check(l) + check(r)
 
 
def work(args):
    d, count = args
    return sum(check(make(d)) for _ in range(count))
 
 
if __name__ == "__main__":
    n, procs = int(sys.argv[1]), int(sys.argv[2])
    min_depth = 4
    max_depth = max(n, min_depth + 2)
    stretch = max_depth + 1
    print("stretch tree of depth %d\t check: %d" % (stretch, check(make(stretch))))
    long_lived = make(max_depth)
    pool = Pool(procs) if procs > 1 else None
    for d in range(min_depth, max_depth + 1, 2):
        iterations = 1 << (max_depth - d + min_depth)
        if pool:
            blocks = max(procs * 4, 1)
            sizes = [iterations // blocks + (1 if i < iterations % blocks else 0) for i in range(blocks)]
            total = sum(pool.map(work, [(d, c) for c in sizes if c]))
        else:
            total = work((d, iterations))
        print("%d\t trees of depth %d\t check: %d" % (iterations, d, total))
    print("long lived tree of depth %d\t check: %d" % (max_depth, check(long_lived)))