Repository navigation
Data: live What-If data tables with the Data Table dialog (completes #548) - #1195
Open
Herr-Enklo wants to merge 11 commits into
Open
Herr-Enklo wants to merge 11 commits into
Herr-Enklo wants to merge 11 commits into
Conversation
…rmulas A What-If data table is now part of the model (Sheet::data_tables: its range and its row and column input cells) and of recalculation. After the formulas, every table with an edge cell (an input value or a formula) in the changed or dirty set is calculated again: each result substitutes the edge value into the input cell on a copy of the workbook and reads the formula (Trial, moved from the engine to calc). Results are written as values and their dependents recalculated; a table whose formulas read another table's results is calculated after it. F9 and opening a workbook calculate every table. Automatic Except for Data Tables and Manual calculation leave tables to F9. A table whose edge cells depend on its own results, directly or through other tables, is a circular reference: its results are #CIRC!. Calculation is bounded: at most 100,000 result cells per table and 1,000,000 per refresh, no table calculation inside a trial, and at most 64 passes.
data.dataTable now adds a live data table over the results instead of
writing a snapshot: the results recalculate when an input value, a formula
or a precedent of the formulas changes (on F9 in Automatic Except for Data
Tables mode), and undo removes the table with its results. The result
cells show {=TABLE(row_input,column_input)} in the formula bar, in Show
Formulas and in cell.get. Input cells must be single cells on the table's
sheet, outside it; a table may not overlap another one, and running Data
Table again over a table's range replaces that table.
`static: true` keeps the previous behaviour: every result is computed once
and written as a value, with input cells on any sheet. The response also
gains `formula`, and `static` is now false for a live table.
Like Excel, an edit of some of a table's results (typing, pasting,
clearing part of them, sorting) is refused with "Cannot change part of a
data table."; clearing all of them removes the table. Inserting or
deleting rows, columns or cells through a table, and pasting one table
onto another, are refused the same way; a table above or beside the edit,
or cut and pasted whole, moves with its input cells, and a table whose
input cell is deleted or ends up inside it keeps its results as values.
TABLE() typed into a cell is refused ("That function isn't valid.").
A data table is written as Excel stores it: the first result cell carries <f t="dataTable" ref="..." dt2D=".." dtr=".." r1=".." r2=".."/> for the whole results area, and every result cell its cached value. Reading rebuilds the table from that formula (previously it was dropped with a warning and only the values kept), so the table is live again after opening. Tables without a results area, with a deleted or misplaced input cell, with more than 100,000 result cells, overlapping an earlier table, or beyond 1,000 per sheet keep their values with a warning. Docs: target-app and file-format parity, ROADMAP progress log.
Brings storytold#548's live data tables up to date with main (413 commits). Conflicts were only in the docs and the calc tests (both sides' rows and tests kept). Main's Solver now has more trial users and Delete Rows/Columns takes several areas: Solver builds its trials through whatif::trial, and every deleted area is checked against the sheet's data tables. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… changed A data table runs one substitution per result row, column or cell. Each one cloned the workbook and wrote into the clone, which copied the 64-row cell bands around the input cells and formulas every time: with the results filled in, a 300 × 300 table over a 50-step model took 53 s to recalculate after an edit. Now the substitutions of a table run one after another on a single working copy (they all set the same input cells, so each one recalculates everything that depends on them and reads what a fresh copy would), and with input cells that hold constants they use the calculation's own dependency graph instead of a copy of it. The same edit takes 3.4 s, a 100,000-row one-variable table 2 s instead of 8 s, a small table in a large workbook 9 ms instead of 82 ms (release build). A refresh also recalculates less: a changed formula, or a changed precedent of one, recalculates the whole table, but an edited input value along an edge only its own row, column or cells (typing a value into a 100,000-row table: 29 ms). A random-edit test checks that this always agrees with a full recalculation. A work budget joins the cell budget: a refresh spends at most 25 million formula evaluations on tables (substitutions times the formulas that depend on the input cells), so a hostile file can't hang the application; a table past it keeps its values until the next refresh. GRIDCRAFT_PROFILE is read once instead of several times per pass, the substitutions don't print profile lines, and they leave the calculation's circular reference list, random state and cell count as they found them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eaving Manual recalculates
Observed in Excel 365: with Show Formulas on, a data table's results show `=TABLE(,B2)`
without the braces the formula bar adds, so `display::cell_text` drops them. `cell.get`
says which table a result cell belongs to (`dataTable: {range, rowInput, columnInput}`).
Switching from Manual to Automatic Except for Data Tables recalculates the formulas edited
in the meantime, as switching to Automatic already did (they stayed stale until F9).
Tests: an edited input value recalculates its own result and agrees with F9; Manual and
Automatic Except for Data Tables modes with F9 and the switch back to Automatic; clearing
the whole table removes it, with undo making it live again; clearing part is refused.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Observed black-box in Excel 365: it writes `dtr="1"` on two-variable tables as well (with `r1` the row input and `r2` the column input) and `ca="1"` on some tables, and it reads a two-variable table the same whatever `dtr` says. GridCraft now writes `dtr="1"` there too; the reader already ignored `dtr` and `ca` for two-variable tables, which a new test reading a sheet in Excel's form (row, column and two-variable tables, a shared-string result) pins. A workbook GridCraft wrote with all three kinds of table and text results opened in Excel 365 without repair, with live tables over the same ranges that recalculated when their inputs changed. The Excel-side files stay out of the repository. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Data › Forecast › What-If Analysis ▾ › Data Table… opened nothing: it ran `data.dataTable`
without parameters, which only reported the missing input cells. It now opens Excel's Data
Table dialog (Row input cell, Column input cell) over the selection; OK runs
`data.dataTable`, and an input cell Excel refuses ("Input cell reference is not valid.")
keeps the dialog open behind the message. The key tip Alt, A, W, T opens it too, and the
What-If Analysis menu has Excel's order: Scenario Manager…, Goal Seek…, Data Table….
Programmatic calls of `data.dataTable` still never open a dialog.
A data table's result shows its formula in the formula language: `{=TABLE(,B2)}` in the
formula bar (with `;` where the formula language separates arguments with it), `=TABLE(,B2)`
in the cell editor and, with Show Formulas on, in the grid. Enter on a result with the
formula unchanged changes nothing; anything else typed there gets Excel's "Cannot change
part of a data table."
German labels as German Excel has them: Datentabelle, Zeileneingabewert:,
Spalteneingabewert:, the Was-wäre-wenn-Analyse tooltip, "Automatisch außer bei
Datentabellen" in Calculation Options, and Abbrechen on dialog buttons.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found by the command-sequence fuzz once it made data tables. A data table's results are formula cells in Excel, so a dynamic array can't spill over them, even while they're blank; GridCraft let `=SEQUENCE(5,2)` spill into a table's empty results, and a full recalculation then disagreed with the incremental one. Spills are now blocked by a table's results (in the pass and when the results are written back). A dynamic array may spill along a table's edges, and the spilled values are then the table's input values or formulas. They aren't formula cells, so a refresh missed them: the table is now triggered by the areas the recalculated formulas spill over before and after the pass, as well as by the cells that changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`data.dataTable` joins the curated commands of the command-sequence fuzz: live (mostly) and static tables near the data, one- and two-variable, with input cells near the data too (sometimes inside the table, which is refused). Every step then checks that undo/redo, an XLSX save and reload and a full recalculation agree with the live tables. A soak of 150 seeds × 120 steps found the spill bug fixed in the previous commit. The other failing seeds shrink to known problems outside data tables: dynamic-array spills (28, 29, 133), `SUBTOTAL` structured references to deleted columns (75, 132), Page Break Preview and undo (138), and a `#SPILL!` result that a static table writes as a constant, which XLSX stores as `#VALUE!` like any `#SPILL!` constant (78). Seeds 15, 79 and 110 are slow in fill down and whole-column merges, with no data table. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… trip ROADMAP progress log, target-app parity (What-if row), file-format parity (XLSX data tables checked against Excel 365 both ways) and UI parity (Data Table dialog), with their Last updated lines and revision history. No score changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This completes #548 by @prxnvt: live What-If data tables,
{=TABLE()}that recalculate, with XLSX round-trip.#548's three commits are kept unchanged. The branch merges current
mainand adds the following on top. The merge needed two adaptations tomain: Solver's new trial callers, and per-area checks for multi-area row/column delete.Data Table dialog and menu
data.dataTable {}still returns an error and never opens a dialog.Formula text, editing, calculation modes
{=TABLE(,B2)}with the formula language's separators. The cell editor and Show Formulas show=TABLE(B1,B2), as Excel does.cell.getnames the table a result belongs to.Recalculation speed
Measured in release builds, against #548:
Spills
The command-sequence fuzz now builds data tables, and it found one bug:
XLSX
dtr="1", as Excel writes them.ca, shared-string results) is read.static: truekeeps the old snapshot behaviour.Notes
#CIRC!. Excel accepts them, but its values drift on every recalculation.TABLEasMEHRFACHOPERATION. That belongs in the German formula table (M12: formulas in German, Brazilian Portuguese, Russian and French, full Spanish table #443) and needs no change here.Tests
cargo xtask ci: all 8 steps pass (1625 tests).🤖 Generated with Claude Code