Skip to content

feat: data tables + arbitrary-model regression (roadmap #2)#78

Merged
ABCrimson merged 4 commits into
mainfrom
feat/wave1-tables-regression
Jul 11, 2026
Merged

feat: data tables + arbitrary-model regression (roadmap #2)#78
ABCrimson merged 4 commits into
mainfrom
feat/wave1-tables-regression

Conversation

@ABCrimson

Copy link
Copy Markdown
Owner

Summary

  • math-engine: parseTildeModel (Desmos-style y1 ~ a*exp(b*x1)) + damped Levenberg–Marquardt fitModel with analytic Jacobians from the symbolic differentiator, per-family seeds, box bounds, and a discriminated result (converged / honest failure) with structured warnings
  • web: fifth Data & Regression plot tab — editable data table with spreadsheet paste, draggable data points, six canned-model chips, fit stats (R², RMSE, std errors, residual toggle); 37 i18n keys × 8 locales

Adversarial-review fixes included

  • canned chips rename parameter letters colliding with column names (previously produced a vacuous "converged, R²=1" self-fit); columns shadowing built-in constants rejected; duplicate column names gate the fit honestly
  • drag anchors the grab offset (sloppy clicks no longer move data); comma-decimal locale paste no longer mangled; ragged columns warn instead of silently truncating; tiny-magnitude regressors no longer misreport as singular (Marquardt column-scaled fallback)
  • draggable-point markup now actually exercised in tests (the global no-op ResizeObserver mock had kept it unmounted in every prior test)

Verification

math-engine 2235 tests, web 288 tests — green; typecheck + biome clean. Wave-1 roadmap item #2.

🤖 Generated with Claude Code

ABCrimson and others added 3 commits July 10, 2026 19:28
…d analytic Jacobians

parseTildeModel splits Desmos-style 'y1 ~ a*exp(b*x1)' models (the tilde
never reaches mathjs), extracts fit parameters vs regressors via
extractVariables, and returns a discriminated union with explicit error
codes. fitModel runs damped LM with per-parameter analytic Jacobians from
the symbolic differentiator, optional box bounds (clamped + warned), smart
initial seeds for the canned families (log-linear seeding for exponential,
median-centered logistic, range-based sinusoid frequency), and an honest
discriminated FitResult: failures carry invalid-model / insufficient-data /
singular / diverged statuses, successes report converged vs max-iterations
plus structured warnings (dropped-rows, bound-hit, zero-variance) so the UI
can localize them. buildCannedModel emits the six prebaked model strings.

28 new tests: parse error paths, exact-string canned models, parameter
recovery for all six families, agreement with linearRegression, residual /
rmse / predict invariants, NaN-row dropping, insufficient-data, degenerate
all-identical-x hygiene (never ok with non-finite params), bounds clamping,
and a fast-check property test recovering arbitrary slope/intercept.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-model fitting

Fifth /plot tab composed entirely in components/plots/regression/*:

- DataTable: native-table columnar editor with spreadsheet TSV clipboard
  paste (anchored at the focused cell, auto-growing rows/columns), editable
  identifier-validated column headers (user-invalid + aria-invalid),
  field-sizing-content tabular-nums cells, Enter-to-next-row.
- DataPointsOverlay: SVG overlay over Plot2D reusing Annotations.tsx's exact
  math-to-pixel mapping; pointer-capture dragging with finger-sized hit
  targets, keyboard arrow nudging, muted residual segments.
- RegressionModelInput: tilde-syntax row with live parse feedback and six
  canned-model chips (buildCannedModel).
- FitStatsPanel: tabular-nums parameters (with standard errors), R2/RMSE/
  iterations, converged vs max-iterations badge, localized structured
  warnings, destructive alert for explicit fit failures - never silent.
- DataRegressionTab: derived parse/fit computed in render (React Compiler
  memoizes - no manual memo hooks), useDeferredValue defers the LM refit
  during drag, fitted curve added as a Plot2DCartesianConfig function only
  for single-regressor models (NaN = renderer break markers), viewport
  auto-fit to data extent +12% on table edits.
- Plot2D: new opt-in syncViewportToConfig prop - pushes external
  config.viewport changes into the interaction controller so the first drag
  after an auto-fit no longer snaps back to the stale seed viewport (legacy
  uncontrolled contract unchanged for existing tabs).
- i18n: full plots.regression.* key set + plots.tab.dataRegression in all 8
  locales, properly translated.
- Tests: component behavior (TSV paste, canned chips, converged stats,
  invalid-model failure, aria-invalid headers, degenerate-data honesty) and
  jest-axe accessibility (empty + fitted states, native table semantics).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- canned-model chips rename parameter letters that collide with column
  names (renaming a column to "b" + Linear chip previously produced a
  vacuous self-referential fit reported as converged, R^2=1)
- parseTildeModel rejects column names shadowed by built-in constants
  (e/pi/tau/i/phi) instead of silently using the constant's value
- duplicate column names now gate the fit with an honest invalid-model
  failure instead of fitting against silently-collapsed data
- point drag anchors the grab offset so a sloppy click on the 12px hit
  target no longer snaps the point (and the data) to the cursor
- comma-decimal locales: "," is a decimal separator on paste, never a
  field separator (";" remains the non-TSV field fallback)
- ragged columns emit the promised dropped-rows warning instead of
  silent truncation to the shortest column
- tiny-magnitude regressors (e.g. SI meters) no longer misreport as
  "singular": Marquardt column-scaled fallback solve when the raw
  normal equations trip the absolute pivot threshold
- draggable points' interactive markup is now actually exercised in
  tests: local firing ResizeObserver stub (the global mock is a no-op
  that left the overlay in its empty early-return branch), dedicated
  DataPointsOverlay test file with axe coverage

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nextcalc-pro Ready Ready Preview, Comment Jul 11, 2026 5:23pm

…les-regression

Union-merged the 8 locale files (plots.relation.* + plots.regression.*
key sets are disjoint), combined both new plot-page tabs and the plots
barrel exports. Verified: typecheck clean, 312 web tests green, biome
clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ABCrimson
ABCrimson merged commit 3fa63ee into main Jul 11, 2026
7 checks passed
@ABCrimson
ABCrimson deleted the feat/wave1-tables-regression branch July 11, 2026 19:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant