Skip to content
CompStats PlaygroundMAST90083 · 2023 S2

R ↔ TypeScript

Same seeds, same numbers.

Each port was written line by line against the original R and its libraries: glmnet's Fortran coordinate descent, LIBSVM's SMO solver as used by e1071, R's Mersenne-Twister with inversion normals and rejection sampling, and the submitted functions themselves. This page reruns them while the site is built and compares the results with the knitted 2023 PDFs.

19 / 22 checks identical or equal to print precisionrecomputed in 3.65 s at build timeR 4.6.1 · glmnet 5.1 · e1071 1.7-17 fixtures

elnet(), cvGlmnet(), ols() + RRandom(10)

Assignment 1 · Q1 · ridge and lasso (glmnet)

  • ridge λmin (index)

    identical
    2023 (R)
    300.8959 (76)
    Port (TS)
    300.8959 (76)
  • ridge λ1se (index)

    identical
    2023 (R)
    2122.8 (55)
    Port (TS)
    2122.8 (55)
  • CV MSE at λmin ± SE

    identical
    2023 (R)
    95596 ± 15574
    Port (TS)
    95596 ± 15574
  • ridge test MSE

    identical
    2023 (R)
    143261.3
    Port (TS)
    143261.3
  • lasso λmin

    identical
    2023 (R)
    4.468208
    Port (TS)
    4.468208
  • lasso test MSE

    differs (explained)
    2023 (R)
    143261.3 (printed)
    Port (TS)
    141632.7

    The notebook printed mse (the ridge value) instead of mse.lasso, so the port reports the lasso's own test error.

  • coefficient table, 20 × 3

    equal to print precision
    2023 (R)
    8 significant digits
    Port (TS)
    max rel. diff 2.9e-7
  • predictors zeroed by the lasso

    identical
    2023 (R)
    HmRun, Runs, RBI, CAtBat, CHits, NewLeagueN
    Port (TS)
    HmRun, Runs, RBI, CAtBat, CHits, NewLeagueN

submittedSamples(), icTable(), simulateAndEvaluateIC(), probOverfitSubmitted()

Assignment 1 · Q2 · AR order selection

  • Q2.5 IC tables (20 × 3, salary-scale bug included)

    equal to print precision
    2023 (R)
    5 decimals
    Port (TS)
    max |diff| 4.9e-6
  • Q2.6 M1, n = 100, 1,000 sims

    identical
    2023 (R)
    15 / 204 / 370 / 180 / 78 / 43 / 34 / 29 / 17 / 30 (IC₁ column)
    Port (TS)
    all 30 counts identical
  • Q2.8 M2, n = 100, 1,000 sims

    identical
    2023 (R)
    30 / 577 / 128 / 82 / 45 / 39 / 21 / 31 / 24 / 23 (IC₁ column)
    Port (TS)
    all 30 counts identical
  • Q2.7 M1, n = 15

    within round-off
    2023 (R)
    p = 8: 921 / 981 / 889
    Port (TS)
    p = 8: 904 / 976 / 870 (max cell diff 22)

    Near-singular fits (≤ 7 rows for ≥ 8 coefficients) make the arg-min depend on floating-point round-off; R 4.6 itself differs from the 2023 run by a similar amount. Port counts here come from Node.js at build time; a browser replay can differ by a few counts.

  • Q2.8 M2, n = 15

    within round-off
    2023 (R)
    p = 8: 890 / 964 / 833
    Port (TS)
    p = 8: 864 / 957 / 807 (max cell diff 26)

    Same round-off sensitivity as M1. Computed in Node.js at build time; browsers may differ by a few counts.

  • Q2.11 overfitting probabilities (16 × 3)

    equal to print precision
    2023 (R)
    5 decimals
    Port (TS)
    max |diff| 4.9e-6

svmTrain(), tuneSvm(), RRandom(50 / 100)

Assignment 3 · Q1 · multiclass SVM (e1071 / LIBSVM)

  • linear, C = 10: support vectors

    identical
    2023 (R)
    67 ( 31 19 17 )
    Port (TS)
    67 ( 31 19 17 )
  • tune(): linear CV errors (7 costs)

    equal to print precision
    2023 (R)
    0.770 0.100 0.107 0.080 0.090 0.090 0.083
    Port (TS)
    max |diff| 3.3e-9
  • best linear cost, support vectors

    identical
    2023 (R)
    C = 1, 81 ( 37 22 22 )
    Port (TS)
    C = 1, 81 ( 37 22 22 )
  • linear test confusion table

    identical
    2023 (R)
    73 6 3 / 7 91 3 / 6 3 108
    Port (TS)
    73 6 3 / 7 91 3 / 6 3 108
  • misclassified (linear)

    identical
    2023 (R)
    28
    Port (TS)
    28
  • radial tune: best (cost, γ), CV error

    identical
    2023 (R)
    (100, 2), 0.07333333
    Port (TS)
    (100, 2), 0.07333333
  • best radial: support vectors

    identical
    2023 (R)
    88 ( 32 30 26 )
    Port (TS)
    88 ( 32 30 26 )
  • radial test confusion table

    identical
    2023 (R)
    71 5 4 / 9 90 2 / 6 5 108
    Port (TS)
    71 5 4 / 9 90 2 / 6 5 108

pnpm test

How parity is tested

scripts/export_artefacts.R reruns the original assignment code in R and writes reference outputs: glmnet paths, CV curves and fold ids, the AR tables, e1071 support vectors, decision values and tuning errors. The Vitest parity suite in web/src/lib compares the ports with those fixtures and with numbers transcribed from the PDFs.

Tolerances are tight: ridge paths agree to about 1e-10 relative, CV curves to 1e-15, SVM tuning errors exactly. The only loose comparisons are the n = 15 Monte Carlo tables, where seven or fewer observations meet eight or more coefficients and the residual sum of squares is pure round-off.

The original R Markdown is preserved unchanged in the repository's coursework/ folder.

regenerate fixtures and run the parity suite
# from the repository root (R >= 4.3)
Rscript -e 'install.packages(c("ISLR","glmnet","e1071","tidyr","jsonlite"))'
Rscript scripts/export_artefacts.R

cd web && pnpm install && pnpm test

Why replay R's random numbers?

Statistical similarity would be easy, but it would not show that the port is faithful. Reproducing R's set.seed() stream means the browser draws the same 131 training players, the same CV folds, the same 4,000 simulated series and the same Gaussian clouds as the 2023 run. Matching to the last printed digit is then strong evidence that every algorithm is ported correctly.