From c6fd4164451ec24951fc9995bd297ebdd820681f Mon Sep 17 00:00:00 2001 From: lantua <16190491+lantua@users.noreply.github.com> Date: Sun, 11 Aug 2024 14:52:32 -0400 Subject: [PATCH 01/12] Add basic documentation --- libs/pando/engine/doc/doc.md | 90 ++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 libs/pando/engine/doc/doc.md diff --git a/libs/pando/engine/doc/doc.md b/libs/pando/engine/doc/doc.md new file mode 100644 index 0000000000..fbf26b2857 --- /dev/null +++ b/libs/pando/engine/doc/doc.md @@ -0,0 +1,90 @@ +# Tag and Tag Database + +A tag is dictionary of tag category (key) and tag value (value) pairs. +We denote a tag category using `cat:`, and a tag value using `cat:val`. + +We also define "tag combination", where tags `T1` and `T2` are combined to create a new tag, denoted `T1/T2`. The resulting tag `T` satisfies the following, +- If `cat:v` ∈ `T2`, then `cat:v` ∈ `T`, +- If `cat:` ∉ `T2` and `cat:v` ∈ `T1`, then `cat:v` ∈ `T`, +- If `cat:` ∉ `T2` and `cat:` ∉ `T1`, then `cat:` ∉ `T`. +That is, `T2` overrides tag entries in `T1`. +Note the asymmetry between `T1` and `T2`. + +## Tag Database and Gathering + +A calculator `calc` contains an array of tag-node pairs, called Tag Database. +Each entry `{ tag, val }` in the tag database signifies that the value of `tag` should include the calculation of `val`. +With tag database, `calc` can *gather a tag `T`* using `calc.get(T)`, which returns all entries in the tag database with matching tags. +An entry `{ tag, val }` in the tag database is included in a gathering iff for every `k:v` ∈ `tag`, `k:v` is also in `T`. + +TODO: discuss what happens when gathering a reread entry + +# Node Operations + +This section outlines all operations supported by Pando. +Operations are separated into three types, arithmetic, branching, and tag-related. + +## Arithmetic Operations + +- `constant(c)`: values of a constant `c` (converting it into a `Node`), + - This is normally unneeded as most functions permit both `Node` and constants, +- `sum(x1, x2, ...) := x1 + x2 + ...`, +- `prod(x1, x2, ...) := x1 * x2 * ...`, +- `min(x1, x2, ...) := Math.min(x1, x2, ...)`, +- `max(x1, x2, ...) := Math.max(x1, x2, ...)`, +- `sumfrac(x1, x2) := x1 / (x1 + x2)`, +- `subscript(index, array) := array[index]`. `array` can be either array of strings or of numbers, +- `custom(op, x1, x2, ...)` is for custom node for non-standard computations, + - See [TODO] on how to add support for custom operations. + +## Branching Operations + +Most branching functions are of the form `cmp<>(x1, x2, pass, fail)` where a comparator CMP (e.g., `Eq`) is used to compare `x1` and `x2`. +If the comparison yields true (e.g., `x1 == x2` for `cmpEq`), then `pass` branch is chosen. Otherwise, `fail` branch is chosen. +Unchosen branch is not evaluated. +`fail` can be omitted if it is 0. +Supported comparators include +- `Eq` (`x1 == x2`) and `NE` (`x1 != x2`), +- `GE` (`x1 >= x2`) and `GT` (`x1 > x2`), and +- `LE` (`x1 <= x2`) and `LT` (`x1 < x2`). + +Another branching function is `lookup(key, table, defaultV) := table[key] ?? defaultV`. +There are two main distinctions between `subscript` and `lookup`: +- `lookup` indices are strings while `subscript` indices are numbers, and +- `lookup` `table` may contain complex nodes while `subscript` `array` can contain only constants. +Nodes other than `table[key]` are not evaluated. +When both `lookup` and `subscript` are applicable, prefer `subscript` for performance reason. + +## Tag-Related Operations + +By default, all arithmetic and branching operations preserve the tags, e.g., calculating `sum(x1, x2)` with a tag `T`, the calculation of `x1` and `x2` also use the same tag `T`. + +- `tagVal(cat)` reads the value of the current tag at category `cat`, or `""` if `cat:` ∉ current tag, +- `tag(v, tag)` calculates `v` using the tag combination `current tag/tag`, +- `dynTag(v, tag)` calculates `v` using the tag combination `current tag/tag`. The main difference compared to `tag` operation is that the tag values in `dynTag` can be other nodes, which are computed with `Tbase` tag. When both `dynTax` and `tag` are applicable, prefer `tag` for performance reason. + +### Read and Reread Operations + +TODO: explain read and reread + +As an example, when performing `calc.compute(read({ c1:v1 c2:v3 }, "sum"))` with a calculator `calc` that has a Tag Database: +``` +[ + { tag: { c1:v1 }, val: node1 }, // entry 1 + { tag: { c1:v2 }, val: node2 }, // entry 2 + { tag: { c1:v1 c2:vA }, val: node3 }, // entry 3 + { tag: { c1:v1 c2:vB }, val: node4 }, // entry 4 + { tag: { c2:vA }, val: node5 }, // entry 5 + { tag: { c1:v1 c2:vA }, val: reread({ c2:v4 }) } // entry 6 +] +``` +the calculator +- Gathers entries matching `{ c1:v1 c2:vA }` (entries 1, 3, 5, and 6), + - Computes `node1` with tag `{ c1:v1 c2:vA }` (node1A), + - Computes `node3` with tag `{ c1:v1 c2:vA }`, + - Computes `node5` with tag `{ c1:v1 c2:vA }`, + - As entry 6 is a `reread`, gathers entries matching `{ c1:v1 c2:vB }` (entries 1, 4, note the different `c2:` throughout this part) + - Computes `node1` with tag `{ c1:v1 c2:vB }` (node1B), + - Computes `node4` with tag `{ c1:v1 c2:vB }`, +- Apply `sum` accumulator, yielding `node1A + node3 + node5 + node1B + node4`. +Note that `node1` is computed twice, each with different tags, due to `reread` operation. From 860c7af8919982ed3a92a3b0cf4a8d953377a9cc Mon Sep 17 00:00:00 2001 From: lantua <16190491+lantua@users.noreply.github.com> Date: Sun, 11 Aug 2024 20:47:14 -0400 Subject: [PATCH 02/12] Update doc --- libs/pando/engine/doc/doc.md | 84 +++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/libs/pando/engine/doc/doc.md b/libs/pando/engine/doc/doc.md index fbf26b2857..c5965f7a25 100644 --- a/libs/pando/engine/doc/doc.md +++ b/libs/pando/engine/doc/doc.md @@ -1,23 +1,48 @@ -# Tag and Tag Database - -A tag is dictionary of tag category (key) and tag value (value) pairs. -We denote a tag category using `cat:`, and a tag value using `cat:val`. - -We also define "tag combination", where tags `T1` and `T2` are combined to create a new tag, denoted `T1/T2`. The resulting tag `T` satisfies the following, -- If `cat:v` ∈ `T2`, then `cat:v` ∈ `T`, -- If `cat:` ∉ `T2` and `cat:v` ∈ `T1`, then `cat:v` ∈ `T`, -- If `cat:` ∉ `T2` and `cat:` ∉ `T1`, then `cat:` ∉ `T`. -That is, `T2` overrides tag entries in `T1`. +# Tag System + +A tag is a dictionary of tag category (key) and tag value (value) pairs. +We denote a tag category and a tag value by `cat:` and `cat:val`, respectively. +When there is no ambiguity, `val` may be used instead of `cat:val`. +We also define a "combination" of tags `T1` and `T2`, denoted by `T1/T2`, as a tag that satisfies the following, for any tag category `cat:` +- If `cat:v` ∈ `T2`, then `cat:v` ∈ `T1/T2`, +- If `cat:` ∉ `T2` and `cat:v` ∈ `T1`, then `cat:v` ∈ `T1/T2`, +- If `cat:` ∉ `T2` and `cat:` ∉ `T1`, then `cat:` ∉ `T1/T2`. Note the asymmetry between `T1` and `T2`. -## Tag Database and Gathering +As an example, the combination `{ c1:v1 c2:v2 }/{ c2:v3 c3:v4 }` is the tag `{ c1:v1 c2:v3 c3:v4 }`. +In this example, `c1:` and `c3:` exist in only one of the tags, and so their values are used. +For `c2:`, both tags contain different values, and so the value in the right tag is preferred. + +## Tag Database Gathering A calculator `calc` contains an array of tag-node pairs, called Tag Database. -Each entry `{ tag, val }` in the tag database signifies that the value of `tag` should include the calculation of `val`. -With tag database, `calc` can *gather a tag `T`* using `calc.get(T)`, which returns all entries in the tag database with matching tags. -An entry `{ tag, val }` in the tag database is included in a gathering iff for every `k:v` ∈ `tag`, `k:v` is also in `T`. +Each entry `{ tag, value }` in the tag database signifies that the value of `tag` should include the calculation of `val`. +With tag database, `calc` can *gather a tag `T`* via`calc.get(T)`, returning all entries in the tag database with matching tags. +An entry `{ tag, value }` in the tag database is included in a gathering iff for every `k:v` ∈ `tag`, `k:v` ∈ `T`. -TODO: discuss what happens when gathering a reread entry +If the value in the included entry is a `node`, its value is computed using tag `T`. +If the value is a `Reread` with tag `T2`, another gather is performed using `T/T2`, and its result is appended to the final result. +For example, consider `calc.get({ c1:v1 c2:vA })` when the `calc`ulator has a Tag Database +``` +[ + { tag: { c1:v1 }, value: node1 }, // entry 1 + { tag: { c1:v2 }, value: node2 }, // entry 2 + { tag: { c1:v1 c2:vA }, value: node3 }, // entry 3 + { tag: { c1:v1 c2:vB }, value: node4 }, // entry 4 + { tag: { c2:vA }, value: node5 }, // entry 5 + { tag: { c1:v1 c2:vA }, value: reread({ c2:vB }) } // entry 6 +]. +``` +In this case, `calc` first selects the matching entries 1, 3, 5, and 6. +As entries 1, 3, and 5 contain nodes, `calc` computes nodes 1, 3, and 5 with tag `{ c1:v1 c2:vA }`. +Next, the the calculator resolves entry 6, by performing a gathering with tag `{ c1:v1 c2:vA }/{ c2:vB } = { c1:v1 c2:vB }`, computing nodes 1 and 4 with tag `{ c1:v1 c2:vB }`. +The calculator then returns the following: +- Value of `node1` computed with tag `{ c1:v1 c2:vA }`, +- Value of `node3` computed with tag `{ c1:v1 c2:vA }`, +- Value of `node5` computed with tag `{ c1:v1 c2:vA }`, +- Value of `node1` computed with tag `{ c1:v1 c2:vB }`, and +- Value of `node4` computed with tag `{ c1:v1 c2:vB }`. +Note that `node1` is computed twice, each with different tags, due to `reread` operation. # Node Operations @@ -26,7 +51,7 @@ Operations are separated into three types, arithmetic, branching, and tag-relate ## Arithmetic Operations -- `constant(c)`: values of a constant `c` (converting it into a `Node`), +- `constant(c)`: values of a constant `c` (converting it to a `Node`), - This is normally unneeded as most functions permit both `Node` and constants, - `sum(x1, x2, ...) := x1 + x2 + ...`, - `prod(x1, x2, ...) := x1 * x2 * ...`, @@ -62,29 +87,8 @@ By default, all arithmetic and branching operations preserve the tags, e.g., cal - `tagVal(cat)` reads the value of the current tag at category `cat`, or `""` if `cat:` ∉ current tag, - `tag(v, tag)` calculates `v` using the tag combination `current tag/tag`, - `dynTag(v, tag)` calculates `v` using the tag combination `current tag/tag`. The main difference compared to `tag` operation is that the tag values in `dynTag` can be other nodes, which are computed with `Tbase` tag. When both `dynTax` and `tag` are applicable, prefer `tag` for performance reason. +- `read(tag, accu)` performs a gather with tag `current tag/tag`, then combine the results using `accu`mulator the accumulators include `sum/prod/min/max`, corresponding to the arithmetic operations. It may also be `undefined`, in which case, the gathering is assumed to contain exactly one entry. -### Read and Reread Operations - -TODO: explain read and reread +# Calculator Customization -As an example, when performing `calc.compute(read({ c1:v1 c2:v3 }, "sum"))` with a calculator `calc` that has a Tag Database: -``` -[ - { tag: { c1:v1 }, val: node1 }, // entry 1 - { tag: { c1:v2 }, val: node2 }, // entry 2 - { tag: { c1:v1 c2:vA }, val: node3 }, // entry 3 - { tag: { c1:v1 c2:vB }, val: node4 }, // entry 4 - { tag: { c2:vA }, val: node5 }, // entry 5 - { tag: { c1:v1 c2:vA }, val: reread({ c2:v4 }) } // entry 6 -] -``` -the calculator -- Gathers entries matching `{ c1:v1 c2:vA }` (entries 1, 3, 5, and 6), - - Computes `node1` with tag `{ c1:v1 c2:vA }` (node1A), - - Computes `node3` with tag `{ c1:v1 c2:vA }`, - - Computes `node5` with tag `{ c1:v1 c2:vA }`, - - As entry 6 is a `reread`, gathers entries matching `{ c1:v1 c2:vB }` (entries 1, 4, note the different `c2:` throughout this part) - - Computes `node1` with tag `{ c1:v1 c2:vB }` (node1B), - - Computes `node4` with tag `{ c1:v1 c2:vB }`, -- Apply `sum` accumulator, yielding `node1A + node3 + node5 + node1B + node4`. -Note that `node1` is computed twice, each with different tags, due to `reread` operation. +TODO From ee5f9521a9e2fa709452a22b726bd558cb16e7af Mon Sep 17 00:00:00 2001 From: lantua <16190491+lantua@users.noreply.github.com> Date: Sun, 11 Aug 2024 20:57:00 -0400 Subject: [PATCH 03/12] Update doc --- libs/pando/engine/doc/doc.md | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/libs/pando/engine/doc/doc.md b/libs/pando/engine/doc/doc.md index c5965f7a25..af958c191e 100644 --- a/libs/pando/engine/doc/doc.md +++ b/libs/pando/engine/doc/doc.md @@ -3,12 +3,12 @@ A tag is a dictionary of tag category (key) and tag value (value) pairs. We denote a tag category and a tag value by `cat:` and `cat:val`, respectively. When there is no ambiguity, `val` may be used instead of `cat:val`. -We also define a "combination" of tags `T1` and `T2`, denoted by `T1/T2`, as a tag that satisfies the following, for any tag category `cat:` +We also define a "combination" of tags `T1` and `T2`, denoted by `T1/T2`, as a tag that satisfies the following, for any tag category `cat:`, - If `cat:v` ∈ `T2`, then `cat:v` ∈ `T1/T2`, - If `cat:` ∉ `T2` and `cat:v` ∈ `T1`, then `cat:v` ∈ `T1/T2`, - If `cat:` ∉ `T2` and `cat:` ∉ `T1`, then `cat:` ∉ `T1/T2`. -Note the asymmetry between `T1` and `T2`. +Note the asymmetry between `T1` and `T2`. As an example, the combination `{ c1:v1 c2:v2 }/{ c2:v3 c3:v4 }` is the tag `{ c1:v1 c2:v3 c3:v4 }`. In this example, `c1:` and `c3:` exist in only one of the tags, and so their values are used. For `c2:`, both tags contain different values, and so the value in the right tag is preferred. @@ -16,13 +16,13 @@ For `c2:`, both tags contain different values, and so the value in the right tag ## Tag Database Gathering A calculator `calc` contains an array of tag-node pairs, called Tag Database. -Each entry `{ tag, value }` in the tag database signifies that the value of `tag` should include the calculation of `val`. -With tag database, `calc` can *gather a tag `T`* via`calc.get(T)`, returning all entries in the tag database with matching tags. +Each entry `{ tag, value }` in the tag database signifies that the computation of `tag` should include `value`. +With tag database, `calc` can *gather a tag `T`* via `calc.get(T)`, returning all entries in the tag database with matching tags. An entry `{ tag, value }` in the tag database is included in a gathering iff for every `k:v` ∈ `tag`, `k:v` ∈ `T`. - If the value in the included entry is a `node`, its value is computed using tag `T`. If the value is a `Reread` with tag `T2`, another gather is performed using `T/T2`, and its result is appended to the final result. -For example, consider `calc.get({ c1:v1 c2:vA })` when the `calc`ulator has a Tag Database + +As an example, consider `calc.get({ c1:v1 c2:vA })` when the `calc`ulator has the following Tag Database, ``` [ { tag: { c1:v1 }, value: node1 }, // entry 1 @@ -58,14 +58,16 @@ Operations are separated into three types, arithmetic, branching, and tag-relate - `min(x1, x2, ...) := Math.min(x1, x2, ...)`, - `max(x1, x2, ...) := Math.max(x1, x2, ...)`, - `sumfrac(x1, x2) := x1 / (x1 + x2)`, -- `subscript(index, array) := array[index]`. `array` can be either array of strings or of numbers, +- `subscript(index, array) := array[index]`. + `array` can be either array of strings or of numbers, - `custom(op, x1, x2, ...)` is for custom node for non-standard computations, - - See [TODO] on how to add support for custom operations. + - See [Calculator Customization Section](#customization) on how to add support for custom operations. ## Branching Operations Most branching functions are of the form `cmp<>(x1, x2, pass, fail)` where a comparator CMP (e.g., `Eq`) is used to compare `x1` and `x2`. -If the comparison yields true (e.g., `x1 == x2` for `cmpEq`), then `pass` branch is chosen. Otherwise, `fail` branch is chosen. +If the comparison yields true (e.g., `x1 == x2` for `cmpEq`), then `pass` branch is chosen. +Otherwise, `fail` branch is chosen. Unchosen branch is not evaluated. `fail` can be omitted if it is 0. Supported comparators include @@ -86,9 +88,12 @@ By default, all arithmetic and branching operations preserve the tags, e.g., cal - `tagVal(cat)` reads the value of the current tag at category `cat`, or `""` if `cat:` ∉ current tag, - `tag(v, tag)` calculates `v` using the tag combination `current tag/tag`, -- `dynTag(v, tag)` calculates `v` using the tag combination `current tag/tag`. The main difference compared to `tag` operation is that the tag values in `dynTag` can be other nodes, which are computed with `Tbase` tag. When both `dynTax` and `tag` are applicable, prefer `tag` for performance reason. -- `read(tag, accu)` performs a gather with tag `current tag/tag`, then combine the results using `accu`mulator the accumulators include `sum/prod/min/max`, corresponding to the arithmetic operations. It may also be `undefined`, in which case, the gathering is assumed to contain exactly one entry. +- `dynTag(v, tag)` calculates `v` using the tag combination `current tag/tag`. + The main difference compared to `tag` operation is that the tag values in `dynTag` can be other nodes, which are computed with `Tbase` tag. + When both `dynTag` and `tag` are applicable, prefer `tag` for performance reason. +- `read(tag, accu)` performs a gather with tag `current tag/tag`, then combine the results using `accu`mulator the accumulators include `sum/prod/min/max`, corresponding to the arithmetic operations. + It may also be `undefined`, in which case, the gathering is assumed to contain exactly one entry. -# Calculator Customization +# Calculator Customization TODO From 4993d5423f3b7a907025e677e4cee2868b89f69c Mon Sep 17 00:00:00 2001 From: lantua <16190491+lantua@users.noreply.github.com> Date: Sun, 11 Aug 2024 21:11:57 -0400 Subject: [PATCH 04/12] Move document to README.md --- libs/pando/engine/README.md | 109 +++++++++++++++++++++++++++++++++-- libs/pando/engine/doc/doc.md | 99 ------------------------------- 2 files changed, 103 insertions(+), 105 deletions(-) delete mode 100644 libs/pando/engine/doc/doc.md diff --git a/libs/pando/engine/README.md b/libs/pando/engine/README.md index d03b821d44..f16b42b242 100644 --- a/libs/pando/engine/README.md +++ b/libs/pando/engine/README.md @@ -1,11 +1,108 @@ -# pando +# Tags -This library was generated with [Nx](https://nx.dev). +A tag is a dictionary of tag category (key) and tag value (value) pairs. +We denote a tag category and a tag value by `cat:` and `cat:val`, respectively. +When there is no ambiguity, `val` may be used instead of `cat:val`. +We also define a "combination" of tags `T1` and `T2`, denoted by `T1/T2`, as a tag that satisfies the following, for any tag category `cat:`, +- If `cat:v` ∈ `T2`, then `cat:v` ∈ `T1/T2`, +- If `cat:` ∉ `T2` and `cat:v` ∈ `T1`, then `cat:v` ∈ `T1/T2`, +- If `cat:` ∉ `T2` and `cat:` ∉ `T1`, then `cat:` ∉ `T1/T2`. -## Building +Note the asymmetry between `T1` and `T2`. +As an example, the combination `{ c1:v1 c2:v2 }/{ c2:v3 c3:v4 }` is the tag `{ c1:v1 c2:v3 c3:v4 }`. +In this example, `c1:` and `c3:` exist in only one of the tags, and so their values are used. +For `c2:`, both tags contain different values, and so the value in the right tag is preferred. -Run `nx build pando` to build the library. +## Tag Database Gathering -## Running unit tests +A calculator `calc` contains an array of tag-node pairs, called Tag Database. +Each entry `{ tag, value }` in the tag database signifies that the computation of `tag` should include `value`. +With tag database, `calc` can *gather a tag `T`* via `calc.get(T)`, returning all entries in the tag database with matching tags. +An entry `{ tag, value }` in the tag database is included in a gathering iff for every `k:v` ∈ `tag`, `k:v` ∈ `T`. +If the value in the included entry is a `node`, its value is computed using tag `T`. +If the value is a `Reread` with tag `T2`, another gather is performed using `T/T2`, and its result is appended to the final result. -Run `nx test pando` to execute the unit tests via [Jest](https://jestjs.io). +As an example, consider `calc.get({ c1:v1 c2:vA })` when the `calc`ulator has the following Tag Database, +``` +[ + { tag: { c1:v1 }, value: node1 }, // entry 1 + { tag: { c1:v2 }, value: node2 }, // entry 2 + { tag: { c1:v1 c2:vA }, value: node3 }, // entry 3 + { tag: { c1:v1 c2:vB }, value: node4 }, // entry 4 + { tag: { c2:vA }, value: node5 }, // entry 5 + { tag: { c1:v1 c2:vA }, value: reread({ c2:vB }) } // entry 6 +]. +``` +In this case, `calc` first selects the matching entries 1, 3, 5, and 6. +As entries 1, 3, and 5 contain nodes, `calc` computes nodes 1, 3, and 5 with tag `{ c1:v1 c2:vA }`. +Next, the the calculator resolves entry 6, by performing a gathering with tag `{ c1:v1 c2:vA }/{ c2:vB } = { c1:v1 c2:vB }`, computing nodes 1 and 4 with tag `{ c1:v1 c2:vB }`. +The calculator then returns the following: +- Value of `node1` computed with tag `{ c1:v1 c2:vA }`, +- Value of `node3` computed with tag `{ c1:v1 c2:vA }`, +- Value of `node5` computed with tag `{ c1:v1 c2:vA }`, +- Value of `node1` computed with tag `{ c1:v1 c2:vB }`, and +- Value of `node4` computed with tag `{ c1:v1 c2:vB }`. +Note that `node1` is computed twice, each with different tags, due to `reread` operation. + +# Node Operations + +This section outlines all operations supported by Pando. +Operations are separated into three types, arithmetic, branching, and tag-related. + +## Arithmetic Operations + +- `constant(c)`: values of a constant `c` (converting it to a `Node`), + - This is normally unneeded as most functions permit both `Node` and constants, +- `sum(x1, x2, ...) := x1 + x2 + ...`, +- `prod(x1, x2, ...) := x1 * x2 * ...`, +- `min(x1, x2, ...) := Math.min(x1, x2, ...)`, +- `max(x1, x2, ...) := Math.max(x1, x2, ...)`, +- `sumfrac(x1, x2) := x1 / (x1 + x2)`, +- `subscript(index, array) := array[index]`. + `array` can be either array of strings or of numbers, +- `custom(op, x1, x2, ...)` is for custom node for non-standard computations, + - See [Calculator Customization Section](#customize) on how to add support for custom operations. + +## Branching Operations + +Most branching functions are of the form `cmp<>(x1, x2, pass, fail)` where a comparator CMP (e.g., `Eq`) is used to compare `x1` and `x2`. +If the comparison yields true (e.g., `x1 == x2` for `cmpEq`), then `pass` branch is chosen. +Otherwise, `fail` branch is chosen. +Unchosen branch is not evaluated. +`fail` can be omitted if it is 0. +Supported comparators include +- `Eq` (`x1 == x2`) and `NE` (`x1 != x2`), +- `GE` (`x1 >= x2`) and `GT` (`x1 > x2`), and +- `LE` (`x1 <= x2`) and `LT` (`x1 < x2`). + +Another branching function is `lookup(key, table, defaultV) := table[key] ?? defaultV`. +There are two main distinctions between `subscript` and `lookup`: +- `lookup` indices are strings while `subscript` indices are numbers, and +- `lookup` `table` may contain complex nodes while `subscript` `array` can contain only constants. +Nodes other than `table[key]` are not evaluated. +When both `lookup` and `subscript` are applicable, prefer `subscript` for performance reason. + +## Tag-Related Operations + +By default, all arithmetic and branching operations preserve the tags, e.g., calculating `sum(x1, x2)` with a tag `T`, the calculation of `x1` and `x2` also use the same tag `T`. + +- `tagVal(cat)` reads the value of the current tag at category `cat`, or `""` if `cat:` ∉ current tag, +- `tag(v, tag)` calculates `v` using the tag combination `current tag/tag`, +- `dynTag(v, tag)` calculates `v` using the tag combination `current tag/tag`. + The main difference compared to `tag` operation is that the tag values in `dynTag` can be other nodes, which are computed with `Tbase` tag. + When both `dynTag` and `tag` are applicable, prefer `tag` for performance reason. +- `read(tag, accu)` performs a gather with tag `current tag/tag`, then combine the results using `accu`mulator the accumulators include `sum/prod/min/max`, corresponding to the arithmetic operations. + It may also be `undefined`, in which case, the gathering is assumed to contain exactly one entry. + +# Calculator Customization + +`Calculator` can be customized via subclassing. +Some functions are designed to be overriden by such subclasses, including + +``` +- computeMeta(n: AnyNode, value: number | string, + x: (CalcResult | undefined)[], + br: CalcResult[], + tag: Tag | undefined): M +- computeCustom(args: (number | string)[], op: string): any +``` diff --git a/libs/pando/engine/doc/doc.md b/libs/pando/engine/doc/doc.md deleted file mode 100644 index af958c191e..0000000000 --- a/libs/pando/engine/doc/doc.md +++ /dev/null @@ -1,99 +0,0 @@ -# Tag System - -A tag is a dictionary of tag category (key) and tag value (value) pairs. -We denote a tag category and a tag value by `cat:` and `cat:val`, respectively. -When there is no ambiguity, `val` may be used instead of `cat:val`. -We also define a "combination" of tags `T1` and `T2`, denoted by `T1/T2`, as a tag that satisfies the following, for any tag category `cat:`, -- If `cat:v` ∈ `T2`, then `cat:v` ∈ `T1/T2`, -- If `cat:` ∉ `T2` and `cat:v` ∈ `T1`, then `cat:v` ∈ `T1/T2`, -- If `cat:` ∉ `T2` and `cat:` ∉ `T1`, then `cat:` ∉ `T1/T2`. - -Note the asymmetry between `T1` and `T2`. -As an example, the combination `{ c1:v1 c2:v2 }/{ c2:v3 c3:v4 }` is the tag `{ c1:v1 c2:v3 c3:v4 }`. -In this example, `c1:` and `c3:` exist in only one of the tags, and so their values are used. -For `c2:`, both tags contain different values, and so the value in the right tag is preferred. - -## Tag Database Gathering - -A calculator `calc` contains an array of tag-node pairs, called Tag Database. -Each entry `{ tag, value }` in the tag database signifies that the computation of `tag` should include `value`. -With tag database, `calc` can *gather a tag `T`* via `calc.get(T)`, returning all entries in the tag database with matching tags. -An entry `{ tag, value }` in the tag database is included in a gathering iff for every `k:v` ∈ `tag`, `k:v` ∈ `T`. -If the value in the included entry is a `node`, its value is computed using tag `T`. -If the value is a `Reread` with tag `T2`, another gather is performed using `T/T2`, and its result is appended to the final result. - -As an example, consider `calc.get({ c1:v1 c2:vA })` when the `calc`ulator has the following Tag Database, -``` -[ - { tag: { c1:v1 }, value: node1 }, // entry 1 - { tag: { c1:v2 }, value: node2 }, // entry 2 - { tag: { c1:v1 c2:vA }, value: node3 }, // entry 3 - { tag: { c1:v1 c2:vB }, value: node4 }, // entry 4 - { tag: { c2:vA }, value: node5 }, // entry 5 - { tag: { c1:v1 c2:vA }, value: reread({ c2:vB }) } // entry 6 -]. -``` -In this case, `calc` first selects the matching entries 1, 3, 5, and 6. -As entries 1, 3, and 5 contain nodes, `calc` computes nodes 1, 3, and 5 with tag `{ c1:v1 c2:vA }`. -Next, the the calculator resolves entry 6, by performing a gathering with tag `{ c1:v1 c2:vA }/{ c2:vB } = { c1:v1 c2:vB }`, computing nodes 1 and 4 with tag `{ c1:v1 c2:vB }`. -The calculator then returns the following: -- Value of `node1` computed with tag `{ c1:v1 c2:vA }`, -- Value of `node3` computed with tag `{ c1:v1 c2:vA }`, -- Value of `node5` computed with tag `{ c1:v1 c2:vA }`, -- Value of `node1` computed with tag `{ c1:v1 c2:vB }`, and -- Value of `node4` computed with tag `{ c1:v1 c2:vB }`. -Note that `node1` is computed twice, each with different tags, due to `reread` operation. - -# Node Operations - -This section outlines all operations supported by Pando. -Operations are separated into three types, arithmetic, branching, and tag-related. - -## Arithmetic Operations - -- `constant(c)`: values of a constant `c` (converting it to a `Node`), - - This is normally unneeded as most functions permit both `Node` and constants, -- `sum(x1, x2, ...) := x1 + x2 + ...`, -- `prod(x1, x2, ...) := x1 * x2 * ...`, -- `min(x1, x2, ...) := Math.min(x1, x2, ...)`, -- `max(x1, x2, ...) := Math.max(x1, x2, ...)`, -- `sumfrac(x1, x2) := x1 / (x1 + x2)`, -- `subscript(index, array) := array[index]`. - `array` can be either array of strings or of numbers, -- `custom(op, x1, x2, ...)` is for custom node for non-standard computations, - - See [Calculator Customization Section](#customization) on how to add support for custom operations. - -## Branching Operations - -Most branching functions are of the form `cmp<>(x1, x2, pass, fail)` where a comparator CMP (e.g., `Eq`) is used to compare `x1` and `x2`. -If the comparison yields true (e.g., `x1 == x2` for `cmpEq`), then `pass` branch is chosen. -Otherwise, `fail` branch is chosen. -Unchosen branch is not evaluated. -`fail` can be omitted if it is 0. -Supported comparators include -- `Eq` (`x1 == x2`) and `NE` (`x1 != x2`), -- `GE` (`x1 >= x2`) and `GT` (`x1 > x2`), and -- `LE` (`x1 <= x2`) and `LT` (`x1 < x2`). - -Another branching function is `lookup(key, table, defaultV) := table[key] ?? defaultV`. -There are two main distinctions between `subscript` and `lookup`: -- `lookup` indices are strings while `subscript` indices are numbers, and -- `lookup` `table` may contain complex nodes while `subscript` `array` can contain only constants. -Nodes other than `table[key]` are not evaluated. -When both `lookup` and `subscript` are applicable, prefer `subscript` for performance reason. - -## Tag-Related Operations - -By default, all arithmetic and branching operations preserve the tags, e.g., calculating `sum(x1, x2)` with a tag `T`, the calculation of `x1` and `x2` also use the same tag `T`. - -- `tagVal(cat)` reads the value of the current tag at category `cat`, or `""` if `cat:` ∉ current tag, -- `tag(v, tag)` calculates `v` using the tag combination `current tag/tag`, -- `dynTag(v, tag)` calculates `v` using the tag combination `current tag/tag`. - The main difference compared to `tag` operation is that the tag values in `dynTag` can be other nodes, which are computed with `Tbase` tag. - When both `dynTag` and `tag` are applicable, prefer `tag` for performance reason. -- `read(tag, accu)` performs a gather with tag `current tag/tag`, then combine the results using `accu`mulator the accumulators include `sum/prod/min/max`, corresponding to the arithmetic operations. - It may also be `undefined`, in which case, the gathering is assumed to contain exactly one entry. - -# Calculator Customization - -TODO From 4fe8ded2a9be1a0840a735e1079a878ce0e4d6e3 Mon Sep 17 00:00:00 2001 From: lantua <16190491+lantua@users.noreply.github.com> Date: Sun, 11 Aug 2024 21:31:04 -0400 Subject: [PATCH 05/12] Update doc --- libs/pando/engine/README.md | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/libs/pando/engine/README.md b/libs/pando/engine/README.md index f16b42b242..99969d28b9 100644 --- a/libs/pando/engine/README.md +++ b/libs/pando/engine/README.md @@ -1,4 +1,10 @@ -# Tags +# Pando + +## Usage + +TODO + +## Tags A tag is a dictionary of tag category (key) and tag value (value) pairs. We denote a tag category and a tag value by `cat:` and `cat:val`, respectively. @@ -13,7 +19,7 @@ As an example, the combination `{ c1:v1 c2:v2 }/{ c2:v3 c3:v4 }` is the tag `{ c In this example, `c1:` and `c3:` exist in only one of the tags, and so their values are used. For `c2:`, both tags contain different values, and so the value in the right tag is preferred. -## Tag Database Gathering +### Tag Database Gathering A calculator `calc` contains an array of tag-node pairs, called Tag Database. Each entry `{ tag, value }` in the tag database signifies that the computation of `tag` should include `value`. @@ -42,14 +48,15 @@ The calculator then returns the following: - Value of `node5` computed with tag `{ c1:v1 c2:vA }`, - Value of `node1` computed with tag `{ c1:v1 c2:vB }`, and - Value of `node4` computed with tag `{ c1:v1 c2:vB }`. + Note that `node1` is computed twice, each with different tags, due to `reread` operation. -# Node Operations +## Node Operations This section outlines all operations supported by Pando. Operations are separated into three types, arithmetic, branching, and tag-related. -## Arithmetic Operations +### Arithmetic Operations - `constant(c)`: values of a constant `c` (converting it to a `Node`), - This is normally unneeded as most functions permit both `Node` and constants, @@ -63,7 +70,7 @@ Operations are separated into three types, arithmetic, branching, and tag-relate - `custom(op, x1, x2, ...)` is for custom node for non-standard computations, - See [Calculator Customization Section](#customize) on how to add support for custom operations. -## Branching Operations +### Branching Operations Most branching functions are of the form `cmp<>(x1, x2, pass, fail)` where a comparator CMP (e.g., `Eq`) is used to compare `x1` and `x2`. If the comparison yields true (e.g., `x1 == x2` for `cmpEq`), then `pass` branch is chosen. @@ -79,26 +86,27 @@ Another branching function is `lookup(key, table, defaultV) := table[key] ?? def There are two main distinctions between `subscript` and `lookup`: - `lookup` indices are strings while `subscript` indices are numbers, and - `lookup` `table` may contain complex nodes while `subscript` `array` can contain only constants. + Nodes other than `table[key]` are not evaluated. When both `lookup` and `subscript` are applicable, prefer `subscript` for performance reason. -## Tag-Related Operations +### Tag-Related Operations By default, all arithmetic and branching operations preserve the tags, e.g., calculating `sum(x1, x2)` with a tag `T`, the calculation of `x1` and `x2` also use the same tag `T`. +When computing with a current tag `Tcur` -- `tagVal(cat)` reads the value of the current tag at category `cat`, or `""` if `cat:` ∉ current tag, -- `tag(v, tag)` calculates `v` using the tag combination `current tag/tag`, -- `dynTag(v, tag)` calculates `v` using the tag combination `current tag/tag`. - The main difference compared to `tag` operation is that the tag values in `dynTag` can be other nodes, which are computed with `Tbase` tag. +- `tagVal(cat)` reads the value of `Tcur` at category `cat`, or `""` if `cat:` ∉ `Tcur`, +- `tag(v, tag)` calculates `v` using `Tcur/tag`, +- `dynTag(v, tag)` calculates `v` using `Tcur/tag`. + The main difference compared to `tag` operation is that the tag values in `dynTag` can be other nodes, which are computed with `Tcur` tag. When both `dynTag` and `tag` are applicable, prefer `tag` for performance reason. -- `read(tag, accu)` performs a gather with tag `current tag/tag`, then combine the results using `accu`mulator the accumulators include `sum/prod/min/max`, corresponding to the arithmetic operations. +- `read(tag, accu)` performs a gather with tag `Tcur/tag`, then combine the results using `accu`mulator the accumulators include `sum/prod/min/max`, corresponding to the arithmetic operations. It may also be `undefined`, in which case, the gathering is assumed to contain exactly one entry. -# Calculator Customization +## Calculator Customization `Calculator` can be customized via subclassing. -Some functions are designed to be overriden by such subclasses, including - +Functions that are designed to be overriden by such subclasses include ``` - computeMeta(n: AnyNode, value: number | string, x: (CalcResult | undefined)[], From 4a1840223daa0e096d55d66c39ca66f92f743f0a Mon Sep 17 00:00:00 2001 From: lantua <16190491+lantua@users.noreply.github.com> Date: Mon, 12 Aug 2024 11:38:36 -0400 Subject: [PATCH 06/12] - Add doc - Update doc --- libs/gi/formula/doc/tag_arch.md | 97 +++++++++++++++++++++++++++++++++ libs/pando/engine/README.md | 19 +++++-- 2 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 libs/gi/formula/doc/tag_arch.md diff --git a/libs/gi/formula/doc/tag_arch.md b/libs/gi/formula/doc/tag_arch.md new file mode 100644 index 0000000000..6046325727 --- /dev/null +++ b/libs/gi/formula/doc/tag_arch.md @@ -0,0 +1,97 @@ +# Tag Architecture + +Tag categories in this module identifies the calculation as follows + +- `name:` the top-level formula +- `preset:` TODO _Do we remove this?_ +- `src:` the character that is applying buffs +- `dst:` the character that is receiving buffs +- `sheet:` the sheet that contains the formula +- `et:` the entry type +- `qt:` and `q:` the query + +- `region:` the region of the character +- `move:` the type of the current dmg formula +- `ele:` the element of the current formula +- `trans:` the transformative reaction +- `amp:` the amplifying reaction +- `cata:` the catalytic reaction + +String representation of a tag (computed using `tagStr`) is of the form + +``` +{ #{name} {preset} {src} ({dst}) {sheet} {et} {qt}.{q} | {region} {move} {ele} {trans} {amp} {cata} } +``` + +Missing tags are omitted. + +## Query + +The current computation, called query, is identified by `qt: q:`. +It is always set when performing a `read` operation, and valid query combinations are specified in `data/util/tag.ts`. +All queries assume a certain `et: sheet:` and `accu` upon read, which is specified by `Desc` and enforced via `convert` (both declared in `tag.ts`). +As an example, to calculate the current character's skill talent level, use `read({ et:self qt:char q:skill sheet:agg }, 'sum')` or simply `self.char.skill`. +For more details on `et:` and `sheet:` see below. + +We split query identifier into `qt:` and `q:` to simplify formula specifications. +Some formulas apply to a large group of queries, most of which having a common `qt:` by design, e.g., +all `qt:premod` stats include the value from `qt:base` stats. + +## Top-level Formulas and Prep Phase + +Top-level formulas are queries that are used directly by the UI, e.g., character's dmg formula. +They are identified by `qt:formula`, and are declared in [prep.ts](../src/data/common/prep.ts). +We assume the following tags (in addition to `qt:formula`) to exist for the top-level formulas, + +- `q:dmg`: `et:self sheet: name: move:`, +- `q:heal`: `et:self sheet: name:`, +- `q:shield`: `et:self sheet: name: ele:`, +- `q:trans/swirl`: `et:self sheet: name: ele: trans:`. + +Most of these formulas begin by preparing appropriate tags for the rest of the formulas. +Tags (such as dmg element `ele:`) are assumed to exist throughout the formula specification, but computing the correct value requires a calculator. +So it cannot be set prior to calculator creation. +Instead we calculate them while the tags are not assumed ready, hence the `prep`are phase, identified by `qt:prep`. +In this phase, the formulas are more restricted in the avilable tags (e.g., `qt:prep q:ele`, of course, cannot use `ele:` tags). +Once each `prep:` calculation is completed, the tags are attached to the base formula with `dynTag`. + +## Entry Types and Sheets + +TODO + +## Sheet-Specific formulas + +TODO + +> Artifact use `sheet:art` instead of `sheet:` as all artifacts are always included together. This helps reduce the `read` needed due to the sheer number of artifacts. + +## Buffs and Conditionals + +TODO + +## Optional Tags + +Tags `name: region: move: ele: trans: amp: cata:` (`name:` and everything on the right of `|` in the string representation) are generally not assumed to be present in most formulas. +Instead, it is used to include additions to the current formula. +For example, reading `{ q:dmg_ ele:hydro }` gathers both entries any-element dmg bonus (`{ q:dmg_ }`) as well as hydro-only dmg bonus (`{ q:dmg_ ele:hydro }`). +Most formulas also retain these optional tags, so the specified optional tags at the top-level formula also applies to the deeper parts of the formula, e.g., character talent level. + +> `name:` is removed when crossing the team buff boundary to improve caching as team buffs do not need to know the original formula name. + +## Mechanisms + +## Non-Stacking (`Read.addOnce`) + +TODO + +## Priority String + +TODO + +## Team-Wide Stats + +TODO + +## Conditional and Top-level Formula Crawling (`meta.ts` generation) + +TODO diff --git a/libs/pando/engine/README.md b/libs/pando/engine/README.md index 99969d28b9..8f74d75b2a 100644 --- a/libs/pando/engine/README.md +++ b/libs/pando/engine/README.md @@ -9,9 +9,10 @@ TODO A tag is a dictionary of tag category (key) and tag value (value) pairs. We denote a tag category and a tag value by `cat:` and `cat:val`, respectively. When there is no ambiguity, `val` may be used instead of `cat:val`. -We also define a "combination" of tags `T1` and `T2`, denoted by `T1/T2`, as a tag that satisfies the following, for any tag category `cat:`, +We also define a "combination" of tags `T1` and `T2`, denoted by `T1/T2`, as a tag such that for any tag category `cat:`, + - If `cat:v` ∈ `T2`, then `cat:v` ∈ `T1/T2`, -- If `cat:` ∉ `T2` and `cat:v` ∈ `T1`, then `cat:v` ∈ `T1/T2`, +- If `cat:` ∉ `T2` and `cat:v` ∈ `T1`, then `cat:v` ∈ `T1/T2`, and - If `cat:` ∉ `T2` and `cat:` ∉ `T1`, then `cat:` ∉ `T1/T2`. Note the asymmetry between `T1` and `T2`. @@ -23,12 +24,13 @@ For `c2:`, both tags contain different values, and so the value in the right tag A calculator `calc` contains an array of tag-node pairs, called Tag Database. Each entry `{ tag, value }` in the tag database signifies that the computation of `tag` should include `value`. -With tag database, `calc` can *gather a tag `T`* via `calc.get(T)`, returning all entries in the tag database with matching tags. +With tag database, `calc` can _gather a tag `T`_ via `calc.get(T)`, returning all entries in the tag database with matching tags. An entry `{ tag, value }` in the tag database is included in a gathering iff for every `k:v` ∈ `tag`, `k:v` ∈ `T`. If the value in the included entry is a `node`, its value is computed using tag `T`. If the value is a `Reread` with tag `T2`, another gather is performed using `T/T2`, and its result is appended to the final result. As an example, consider `calc.get({ c1:v1 c2:vA })` when the `calc`ulator has the following Tag Database, + ``` [ { tag: { c1:v1 }, value: node1 }, // entry 1 @@ -39,10 +41,12 @@ As an example, consider `calc.get({ c1:v1 c2:vA })` when the `calc`ulator has th { tag: { c1:v1 c2:vA }, value: reread({ c2:vB }) } // entry 6 ]. ``` + In this case, `calc` first selects the matching entries 1, 3, 5, and 6. As entries 1, 3, and 5 contain nodes, `calc` computes nodes 1, 3, and 5 with tag `{ c1:v1 c2:vA }`. Next, the the calculator resolves entry 6, by performing a gathering with tag `{ c1:v1 c2:vA }/{ c2:vB } = { c1:v1 c2:vB }`, computing nodes 1 and 4 with tag `{ c1:v1 c2:vB }`. The calculator then returns the following: + - Value of `node1` computed with tag `{ c1:v1 c2:vA }`, - Value of `node3` computed with tag `{ c1:v1 c2:vA }`, - Value of `node5` computed with tag `{ c1:v1 c2:vA }`, @@ -70,7 +74,7 @@ Operations are separated into three types, arithmetic, branching, and tag-relate - `custom(op, x1, x2, ...)` is for custom node for non-standard computations, - See [Calculator Customization Section](#customize) on how to add support for custom operations. -### Branching Operations +### Branching Operations Most branching functions are of the form `cmp<>(x1, x2, pass, fail)` where a comparator CMP (e.g., `Eq`) is used to compare `x1` and `x2`. If the comparison yields true (e.g., `x1 == x2` for `cmpEq`), then `pass` branch is chosen. @@ -78,19 +82,21 @@ Otherwise, `fail` branch is chosen. Unchosen branch is not evaluated. `fail` can be omitted if it is 0. Supported comparators include + - `Eq` (`x1 == x2`) and `NE` (`x1 != x2`), - `GE` (`x1 >= x2`) and `GT` (`x1 > x2`), and - `LE` (`x1 <= x2`) and `LT` (`x1 < x2`). Another branching function is `lookup(key, table, defaultV) := table[key] ?? defaultV`. There are two main distinctions between `subscript` and `lookup`: + - `lookup` indices are strings while `subscript` indices are numbers, and - `lookup` `table` may contain complex nodes while `subscript` `array` can contain only constants. Nodes other than `table[key]` are not evaluated. When both `lookup` and `subscript` are applicable, prefer `subscript` for performance reason. -### Tag-Related Operations +### Tag-Related Operations By default, all arithmetic and branching operations preserve the tags, e.g., calculating `sum(x1, x2)` with a tag `T`, the calculation of `x1` and `x2` also use the same tag `T`. When computing with a current tag `Tcur` @@ -101,12 +107,13 @@ When computing with a current tag `Tcur` The main difference compared to `tag` operation is that the tag values in `dynTag` can be other nodes, which are computed with `Tcur` tag. When both `dynTag` and `tag` are applicable, prefer `tag` for performance reason. - `read(tag, accu)` performs a gather with tag `Tcur/tag`, then combine the results using `accu`mulator the accumulators include `sum/prod/min/max`, corresponding to the arithmetic operations. - It may also be `undefined`, in which case, the gathering is assumed to contain exactly one entry. + Accumulator may be `undefined`, in which case, the gathering is assumed to contain exactly one entry. ## Calculator Customization `Calculator` can be customized via subclassing. Functions that are designed to be overriden by such subclasses include + ``` - computeMeta(n: AnyNode, value: number | string, x: (CalcResult | undefined)[], From 1cdd5f0273013a691b44dd05a664ab13233e99a5 Mon Sep 17 00:00:00 2001 From: lantua <16190491+lantua@users.noreply.github.com> Date: Mon, 12 Aug 2024 13:01:14 -0400 Subject: [PATCH 07/12] Update doc --- libs/gi/formula/doc/tag_arch.md | 40 +++++++++++++++++++++++++++------ libs/pando/engine/README.md | 19 +++++++++------- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/libs/gi/formula/doc/tag_arch.md b/libs/gi/formula/doc/tag_arch.md index 6046325727..19aae7773e 100644 --- a/libs/gi/formula/doc/tag_arch.md +++ b/libs/gi/formula/doc/tag_arch.md @@ -53,17 +53,43 @@ Tags (such as dmg element `ele:`) are assumed to exist throughout the formula sp So it cannot be set prior to calculator creation. Instead we calculate them while the tags are not assumed ready, hence the `prep`are phase, identified by `qt:prep`. In this phase, the formulas are more restricted in the avilable tags (e.g., `qt:prep q:ele`, of course, cannot use `ele:` tags). -Once each `prep:` calculation is completed, the tags are attached to the base formula with `dynTag`. +Once `prep:` calculation is completed, the tags are attached to the base formula via `dynTag`. -## Entry Types and Sheets +## Entry Types and Sheet-Specific Formulas -TODO +On a `read` operation, `et:` tag specifies the type of calculation, whether the query computes the current character stat (`et:self`), the common enemy stat (`et:enemy`), team-wide stat (`et:team`), or the stat of the buff target (`et:target`). +As an entry tag, `et:` specifies the type of entry, whether it is a buff that only applies to the current character (`et:selfBuff`), the entire team (`et:teamBuff`), other members only (`et:notSelfBuff`), or if it is a debuff to enemy (`et:enemy`). + +The query starts with one of the read-side `et:`. +The gathering operation then maps to the appropriate `sheet:` and write-side `et:` via util functions. +Consider a read on a `et:self sheet:agg` query (e.g., `self.char.skill`), the following is the entries matched during the gathering + +- `{ et:self sheet:agg } <= { sheet:custom }` (`data/common/index.ts`) + - Custom contributions +- `{ sheet:agg src: } <= { src:<*> dst: et:selfBuff/teamBuff/notSelfBuff }` (`teamData`, insert the correct `et:`) + - `{ sheet:agg src: } <= { sheet: }` (`charData/weaponData/artData` with `withMember`, select sheets) + - Chararcter/weapon/artifact-specific `et:selfBuff/teamBuff/notSelfBuff` contributions (from appropriate members `src:` and `dst:`) +- No sheet-specific contributions at top-level as the sheet selection by above are wrapped within `withMember`. + So those formulas are only included when `teamData` adds the correct `src:` with `reread` above + +For `et:self sheet:iso` queries, this is a simpler, + +- `{ et:self sheet:agg } <= { sheet:custom }` (`data/common/index.ts`) + - Custom contributions +- `{ sheet:iso } <= { et:self sheet: }` (`charData` with `withMember`) + - `et:self` contributions from the current character + +Team-wide queries (`et:team`) utilize the computations of `et:self`, + +- `{ et:team } <- { src:* et:self }` (`teamData`) + - `et:self` query from each member with appropriate `sheet:` ## Sheet-Specific formulas TODO -> Artifact use `sheet:art` instead of `sheet:` as all artifacts are always included together. This helps reduce the `read` needed due to the sheer number of artifacts. +> Artifact use `sheet:art` instead of `sheet:` as all artifacts are always included together. +> This helps reduce the `read` needed due to the sheer number of artifacts. ## Buffs and Conditionals @@ -73,10 +99,10 @@ TODO Tags `name: region: move: ele: trans: amp: cata:` (`name:` and everything on the right of `|` in the string representation) are generally not assumed to be present in most formulas. Instead, it is used to include additions to the current formula. -For example, reading `{ q:dmg_ ele:hydro }` gathers both entries any-element dmg bonus (`{ q:dmg_ }`) as well as hydro-only dmg bonus (`{ q:dmg_ ele:hydro }`). -Most formulas also retain these optional tags, so the specified optional tags at the top-level formula also applies to the deeper parts of the formula, e.g., character talent level. +For example, reading `{ q:dmg_ ele:hydro }` gathers both any-element dmg bonus (`{ q:dmg_ }`) and hydro-only dmg bonus (`{ q:dmg_ ele:hydro }`). +Most formulas also retain these optional tags, so the specified optional tags at a top-level formula also apply to the deeper parts of the formula, e.g., character talent level. -> `name:` is removed when crossing the team buff boundary to improve caching as team buffs do not need to know the original formula name. +> `name:` is removed when crossing the team buff boundary to improve caching as team buffs do not need the formula name. ## Mechanisms diff --git a/libs/pando/engine/README.md b/libs/pando/engine/README.md index 8f74d75b2a..9ff887382c 100644 --- a/libs/pando/engine/README.md +++ b/libs/pando/engine/README.md @@ -24,21 +24,24 @@ For `c2:`, both tags contain different values, and so the value in the right tag A calculator `calc` contains an array of tag-node pairs, called Tag Database. Each entry `{ tag, value }` in the tag database signifies that the computation of `tag` should include `value`. +We denote a tag database entry with `tag <- value`. +If `value` is a reread to `tag2`, we may instead denote the entry with `tag <= tag2`. +Note the different arrow type between the two, as well as the type difference on the right side of the arrow. + With tag database, `calc` can _gather a tag `T`_ via `calc.get(T)`, returning all entries in the tag database with matching tags. -An entry `{ tag, value }` in the tag database is included in a gathering iff for every `k:v` ∈ `tag`, `k:v` ∈ `T`. +An entry `tag <- value` in the tag database is included in a gathering iff for every `k:v` ∈ `tag`, `v == null` or `k:v` ∈ `T`. If the value in the included entry is a `node`, its value is computed using tag `T`. If the value is a `Reread` with tag `T2`, another gather is performed using `T/T2`, and its result is appended to the final result. - As an example, consider `calc.get({ c1:v1 c2:vA })` when the `calc`ulator has the following Tag Database, ``` [ - { tag: { c1:v1 }, value: node1 }, // entry 1 - { tag: { c1:v2 }, value: node2 }, // entry 2 - { tag: { c1:v1 c2:vA }, value: node3 }, // entry 3 - { tag: { c1:v1 c2:vB }, value: node4 }, // entry 4 - { tag: { c2:vA }, value: node5 }, // entry 5 - { tag: { c1:v1 c2:vA }, value: reread({ c2:vB }) } // entry 6 + { c1:v1 } <- node1, // entry 1 + { c1:v2 } <- node2, // entry 2 + { c1:v1 c2:vA } <- node3, // entry 3 + { c1:v1 c2:vB } <- node4, // entry 4 + { c2:vA } <- node5, // entry 5 + { c1:v1 c2:vA } <= { c2:vB } // entry 6 ]. ``` From cf331f56dc58be1231266c161ebd1e178730385e Mon Sep 17 00:00:00 2001 From: lantua <16190491+lantua@users.noreply.github.com> Date: Mon, 12 Aug 2024 13:17:41 -0400 Subject: [PATCH 08/12] Update doc --- libs/gi/formula/doc/tag_arch.md | 36 ++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/libs/gi/formula/doc/tag_arch.md b/libs/gi/formula/doc/tag_arch.md index 19aae7773e..d67490024d 100644 --- a/libs/gi/formula/doc/tag_arch.md +++ b/libs/gi/formula/doc/tag_arch.md @@ -55,35 +55,43 @@ Instead we calculate them while the tags are not assumed ready, hence the `prep` In this phase, the formulas are more restricted in the avilable tags (e.g., `qt:prep q:ele`, of course, cannot use `ele:` tags). Once `prep:` calculation is completed, the tags are attached to the base formula via `dynTag`. -## Entry Types and Sheet-Specific Formulas +## `et:` and `sheet:` -On a `read` operation, `et:` tag specifies the type of calculation, whether the query computes the current character stat (`et:self`), the common enemy stat (`et:enemy`), team-wide stat (`et:team`), or the stat of the buff target (`et:target`). -As an entry tag, `et:` specifies the type of entry, whether it is a buff that only applies to the current character (`et:selfBuff`), the entire team (`et:teamBuff`), other members only (`et:notSelfBuff`), or if it is a debuff to enemy (`et:enemy`). +The tag categories `et:` and `sheet:` are separated into read-side, which is used by `read` operations, and write-side, which is used in as tags in tag database entries. -The query starts with one of the read-side `et:`. -The gathering operation then maps to the appropriate `sheet:` and write-side `et:` via util functions. -Consider a read on a `et:self sheet:agg` query (e.g., `self.char.skill`), the following is the entries matched during the gathering +- Read-side `et:` specifies the type of calculation, whether the query computes the current character stat (`et:self`), the common enemy stat (`et:enemy`), team-wide stat (`et:team`), or the stat of the buff target (`et:target`). +- Read-side `sheet:` speficies the sheets that will be used to gather particular query, whether to gather all sheets from all team members (`sheet:agg`), only character sheets of the current character (`sheet:iso`), or common listing outside of any specific sheets (`static`). +- Write-side `et:` specifies the type of entry, whether it is a buff that only applies to the current character (`et:selfBuff`), the entire team (`et:teamBuff`), other members only (`et:notSelfBuff`), or if it is a debuff to enemy (`et:enemy`). +- Write-side `sheet:` specifies the sheet that the entry belongs to (`sheet://`), or if the entry is a UI custom formula (`sheet:custom`). -- `{ et:self sheet:agg } <= { sheet:custom }` (`data/common/index.ts`) +The query starts with one of the read-side `sheet: et:` combination. +The gathering operation then maps to the appropriate write-side `sheet: et:` via util functions. +Consider a read on a `sheet:agg et:` query (e.g., `self.char.skill`), the following is the entries matched during the gathering + +- `{ sheet:agg et:self } <= { sheet:custom }` (`data/common/index.ts`) - Custom contributions -- `{ sheet:agg src: } <= { src:<*> dst: et:selfBuff/teamBuff/notSelfBuff }` (`teamData`, insert the correct `et:`) - - `{ sheet:agg src: } <= { sheet: }` (`charData/weaponData/artData` with `withMember`, select sheets) +- `{ src: sheet:agg } <= { src:<*> dst: et:selfBuff/teamBuff/notSelfBuff }` (`teamData`, insert the correct `et:`) + - `{ src: sheet:agg } <= { sheet: }` (`charData/weaponData/artData` with `withMember`, select sheets) - Chararcter/weapon/artifact-specific `et:selfBuff/teamBuff/notSelfBuff` contributions (from appropriate members `src:` and `dst:`) -- No sheet-specific contributions at top-level as the sheet selection by above are wrapped within `withMember`. +- No sheet-specific contributions at top-level as the sheet selection above are wrapped within `withMember`. So those formulas are only included when `teamData` adds the correct `src:` with `reread` above -For `et:self sheet:iso` queries, this is a simpler, +For `et:self sheet:iso` queries, the gathered entries are simpler, -- `{ et:self sheet:agg } <= { sheet:custom }` (`data/common/index.ts`) +- `{ sheet:agg et:self } <= { sheet:custom }` (`data/common/index.ts`) - Custom contributions -- `{ sheet:iso } <= { et:self sheet: }` (`charData` with `withMember`) +- `{ sheet:iso } <= { sheet: et:self }` (`charData` with `withMember`) - `et:self` contributions from the current character -Team-wide queries (`et:team`) utilize the computations of `et:self`, +> To avoid collision with `sheet:agg`, `sheet:iso` contributions use `et:self` instead of `et:selfBuff`. + +Team-wide queries (`et:team`) utilize the computations of `et:self`, with the following gathered entries, - `{ et:team } <- { src:* et:self }` (`teamData`) - `et:self` query from each member with appropriate `sheet:` +TODO: `et:enemy sheet:enemy`, `sheet:static`, and `sheet:dyn` + ## Sheet-Specific formulas TODO From 7021b54f47e7e898291984acfbfcc75901fb9834 Mon Sep 17 00:00:00 2001 From: lantua <16190491+lantua@users.noreply.github.com> Date: Mon, 12 Aug 2024 13:32:42 -0400 Subject: [PATCH 09/12] Update doc --- libs/gi/formula/doc/tag_arch.md | 93 ++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 43 deletions(-) diff --git a/libs/gi/formula/doc/tag_arch.md b/libs/gi/formula/doc/tag_arch.md index d67490024d..7800a391fd 100644 --- a/libs/gi/formula/doc/tag_arch.md +++ b/libs/gi/formula/doc/tag_arch.md @@ -55,53 +55,64 @@ Instead we calculate them while the tags are not assumed ready, hence the `prep` In this phase, the formulas are more restricted in the avilable tags (e.g., `qt:prep q:ele`, of course, cannot use `ele:` tags). Once `prep:` calculation is completed, the tags are attached to the base formula via `dynTag`. -## `et:` and `sheet:` +## Entry Type and Sheet Specifier The tag categories `et:` and `sheet:` are separated into read-side, which is used by `read` operations, and write-side, which is used in as tags in tag database entries. -- Read-side `et:` specifies the type of calculation, whether the query computes the current character stat (`et:self`), the common enemy stat (`et:enemy`), team-wide stat (`et:team`), or the stat of the buff target (`et:target`). -- Read-side `sheet:` speficies the sheets that will be used to gather particular query, whether to gather all sheets from all team members (`sheet:agg`), only character sheets of the current character (`sheet:iso`), or common listing outside of any specific sheets (`static`). -- Write-side `et:` specifies the type of entry, whether it is a buff that only applies to the current character (`et:selfBuff`), the entire team (`et:teamBuff`), other members only (`et:notSelfBuff`), or if it is a debuff to enemy (`et:enemy`). +- Read-side `et:` specifies the type of calculation, whether the query computes the current character stat (`et:self`), team-wide stat (`et:team`), the stat of the buff target (`et:target`), or the common enemy stat (`et:enemy`). +- Write-side `et:` specifies the type of entry, whether it applies only to the current character (`et:selfBuff`), the entire team (`et:teamBuff`), other members (`et:notSelfBuff`), or if it is a debuff to the enemy (`et:enemy`). +- Read-side `sheet:` speficies the sheets that will be included in gathering, whether to gather all sheets from all team members (`sheet:agg`), only character sheets of the current character (`sheet:iso`), or common listing outside of any specific sheets (`static`). - Write-side `sheet:` specifies the sheet that the entry belongs to (`sheet://`), or if the entry is a UI custom formula (`sheet:custom`). -The query starts with one of the read-side `sheet: et:` combination. +Every query starts with one of the read-side `sheet: et:` combination. The gathering operation then maps to the appropriate write-side `sheet: et:` via util functions. -Consider a read on a `sheet:agg et:` query (e.g., `self.char.skill`), the following is the entries matched during the gathering +Following is the gathered entries on different `sheet: et:` combinations: + +- `sheet:agg et:self` queries (e.g., `self.char.skill`) + - `{ sheet:agg et:self } <= { sheet:custom }` (`data/common/index.ts`) + - Custom contributions + - `{ src: sheet:agg } <= { src:* dst: et:selfBuff/teamBuff/notSelfBuff }` (`teamData`, add `src:/dst:` and switch to write-side `et:`) + - `{ src: sheet:agg } <= { sheet: }` (`charData/weaponData/artData` with `withMember`, select sheets) + - Sheet-specific contributions from appropriate members `src: dst:` and write-side `sheet: et:` + - No sheet-specific contributions at top-level as the sheet selection above are wrapped within `withMember`. + So those formulas are only included when `teamData` adds the correct `src:` with `reread` above +- `et:self sheet:iso` queries (e.g., `self.char.lvl`) + - `{ sheet:agg et:self } <= { sheet:custom }` (`data/common/index.ts`) + - Custom contributions + - `{ sheet:iso } <= { sheet: et:self }` (`charData` with `withMember`, select sheets) + - `et:self` contributions from the current character +- `et:team sheet:agg/iso` queries (e.g., `team.final.atk`) + - `{ et:team } <- { src:* et:self }` (`teamData`) + - `et:self` query from each member with appropriate `sheet:` +- TODO: `et:enemy sheet:enemy`, `sheet:static`, and `sheet:dyn` + +Notes: + +- `sheet:iso` contributions use `et:self` instead of `et:selfBuff`. +- Artifact use `sheet:art` instead of `sheet:` as all artifacts are always included together. This helps reduce the `read` needed due to the sheer number of artifacts. + - `sheet:` is used only for counting the number equipped artifact of that set. + +## Conditionals + +Conditional query tags are of the form -- `{ sheet:agg et:self } <= { sheet:custom }` (`data/common/index.ts`) - - Custom contributions -- `{ src: sheet:agg } <= { src:<*> dst: et:selfBuff/teamBuff/notSelfBuff }` (`teamData`, insert the correct `et:`) - - `{ src: sheet:agg } <= { sheet: }` (`charData/weaponData/artData` with `withMember`, select sheets) - - Chararcter/weapon/artifact-specific `et:selfBuff/teamBuff/notSelfBuff` contributions (from appropriate members `src:` and `dst:`) -- No sheet-specific contributions at top-level as the sheet selection above are wrapped within `withMember`. - So those formulas are only included when `teamData` adds the correct `src:` with `reread` above - -For `et:self sheet:iso` queries, the gathered entries are simpler, - -- `{ sheet:agg et:self } <= { sheet:custom }` (`data/common/index.ts`) - - Custom contributions -- `{ sheet:iso } <= { sheet: et:self }` (`charData` with `withMember`) - - `et:self` contributions from the current character - -> To avoid collision with `sheet:agg`, `sheet:iso` contributions use `et:self` instead of `et:selfBuff`. - -Team-wide queries (`et:team`) utilize the computations of `et:self`, with the following gathered entries, - -- `{ et:team } <- { src:* et:self }` (`teamData`) - - `et:self` query from each member with appropriate `sheet:` - -TODO: `et:enemy sheet:enemy`, `sheet:static`, and `sheet:dyn` - -## Sheet-Specific formulas - -TODO - -> Artifact use `sheet:art` instead of `sheet:` as all artifacts are always included together. -> This helps reduce the `read` needed due to the sheer number of artifacts. +``` +{ + et: 'self', qt: 'cond', // Fixed tags + sheet:, q:, // Conditional identifier + src:, // Character that is applying (src:) buff + dst:, // Character that is receiving (dst:) buff + // Unused tags + name:null, region:null, ele:null, move:null, + trans:null, amp:null, cata:null +} +``` -## Buffs and Conditionals +Since the tag requires both `src:` and `dst:`, conditionals are only valid when both are guaranteed to exist. +A notable class of entries that satisfy the condition are entries with `et:selfBuff/teamBuff/notSelfBuff/enemyDebuff` tags. +We call those entries _buff context_, as those entries are missing when calculating stats without team information. -TODO +> Unused tags are set to `null` when reading conditionals to improve caching. ## Optional Tags @@ -122,10 +133,6 @@ TODO TODO -## Team-Wide Stats - -TODO - -## Conditional and Top-level Formula Crawling (`meta.ts` generation) +## `meta.ts` generation TODO From fe2db45dc2ba3c1ec6b4717204e11e8c02560b2c Mon Sep 17 00:00:00 2001 From: lantua <16190491+lantua@users.noreply.github.com> Date: Mon, 12 Aug 2024 14:27:22 -0400 Subject: [PATCH 10/12] Update doc --- libs/gi/formula/doc/tag_arch.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/gi/formula/doc/tag_arch.md b/libs/gi/formula/doc/tag_arch.md index 7800a391fd..f7b20f90fc 100644 --- a/libs/gi/formula/doc/tag_arch.md +++ b/libs/gi/formula/doc/tag_arch.md @@ -51,8 +51,8 @@ We assume the following tags (in addition to `qt:formula`) to exist for the top- Most of these formulas begin by preparing appropriate tags for the rest of the formulas. Tags (such as dmg element `ele:`) are assumed to exist throughout the formula specification, but computing the correct value requires a calculator. So it cannot be set prior to calculator creation. -Instead we calculate them while the tags are not assumed ready, hence the `prep`are phase, identified by `qt:prep`. -In this phase, the formulas are more restricted in the avilable tags (e.g., `qt:prep q:ele`, of course, cannot use `ele:` tags). +Instead, we calculate them while the tags are not assumed ready, hence the `prep` phase, identified by `qt:prep`. +In this phase, the formulas are more restricted in the avilable tags (e.g., `qt:prep q:ele` cannot use `ele:`). Once `prep:` calculation is completed, the tags are attached to the base formula via `dynTag`. ## Entry Type and Sheet Specifier @@ -121,7 +121,7 @@ Instead, it is used to include additions to the current formula. For example, reading `{ q:dmg_ ele:hydro }` gathers both any-element dmg bonus (`{ q:dmg_ }`) and hydro-only dmg bonus (`{ q:dmg_ ele:hydro }`). Most formulas also retain these optional tags, so the specified optional tags at a top-level formula also apply to the deeper parts of the formula, e.g., character talent level. -> `name:` is removed when crossing the team buff boundary to improve caching as team buffs do not need the formula name. +> `name:null` is applied when crossing team buff boundaries to improve caching. ## Mechanisms From df3e545ba71555215bcd07a63e992c19b044ade7 Mon Sep 17 00:00:00 2001 From: lantua <16190491+lantua@users.noreply.github.com> Date: Mon, 12 Aug 2024 16:14:10 -0400 Subject: [PATCH 11/12] Update doc --- libs/gi/formula/doc/tag_arch.md | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/libs/gi/formula/doc/tag_arch.md b/libs/gi/formula/doc/tag_arch.md index f7b20f90fc..d51f352ba4 100644 --- a/libs/gi/formula/doc/tag_arch.md +++ b/libs/gi/formula/doc/tag_arch.md @@ -57,33 +57,33 @@ Once `prep:` calculation is completed, the tags are attached to the base formula ## Entry Type and Sheet Specifier -The tag categories `et:` and `sheet:` are separated into read-side, which is used by `read` operations, and write-side, which is used in as tags in tag database entries. +The tag categories `et:` and `sheet:` are separated into read-side, which is used by `read` operations, and write-side, which is used as tags in tag database entries. -- Read-side `et:` specifies the type of calculation, whether the query computes the current character stat (`et:self`), team-wide stat (`et:team`), the stat of the buff target (`et:target`), or the common enemy stat (`et:enemy`). -- Write-side `et:` specifies the type of entry, whether it applies only to the current character (`et:selfBuff`), the entire team (`et:teamBuff`), other members (`et:notSelfBuff`), or if it is a debuff to the enemy (`et:enemy`). -- Read-side `sheet:` speficies the sheets that will be included in gathering, whether to gather all sheets from all team members (`sheet:agg`), only character sheets of the current character (`sheet:iso`), or common listing outside of any specific sheets (`static`). -- Write-side `sheet:` specifies the sheet that the entry belongs to (`sheet://`), or if the entry is a UI custom formula (`sheet:custom`). +- Read-side `et:` specifies whether the query computes the current character stat (`et:self`), team-wide stat (`et:team`), the stat of the buff target (`et:target`), or the common enemy stat (`et:enemy`). +- Write-side `et:` specifies whether the entry applies only to the current character (`et:selfBuff`), the entire team (`et:teamBuff`), other members (`et:notSelfBuff`), or the enemy (`et:enemy`). +- Read-side `sheet:` speficies the sheets to include in gathering, whether to gather all sheets from all members (`sheet:agg`), only character sheets of the current member (`sheet:iso`), or common listing outside of any specific sheets (`static`). +- Write-side `sheet:` specifies the sheet the entry belongs to (`sheet://`), or if the entry is a UI custom formula (`sheet:custom`). -Every query starts with one of the read-side `sheet: et:` combination. +Every query starts with a read-side `sheet: et:` combination. The gathering operation then maps to the appropriate write-side `sheet: et:` via util functions. Following is the gathered entries on different `sheet: et:` combinations: - `sheet:agg et:self` queries (e.g., `self.char.skill`) - `{ sheet:agg et:self } <= { sheet:custom }` (`data/common/index.ts`) - Custom contributions - - `{ src: sheet:agg } <= { src:* dst: et:selfBuff/teamBuff/notSelfBuff }` (`teamData`, add `src:/dst:` and switch to write-side `et:`) - - `{ src: sheet:agg } <= { sheet: }` (`charData/weaponData/artData` with `withMember`, select sheets) + - `{ src: sheet:agg } <= { src:* dst: et:selfBuff/teamBuff/notSelfBuff }` (`teamData`) + - `{ src: sheet:agg } <= { sheet: }` (`char/weapon/artData` with `withMember`) - Sheet-specific contributions from appropriate members `src: dst:` and write-side `sheet: et:` - No sheet-specific contributions at top-level as the sheet selection above are wrapped within `withMember`. So those formulas are only included when `teamData` adds the correct `src:` with `reread` above - `et:self sheet:iso` queries (e.g., `self.char.lvl`) - `{ sheet:agg et:self } <= { sheet:custom }` (`data/common/index.ts`) - Custom contributions - - `{ sheet:iso } <= { sheet: et:self }` (`charData` with `withMember`, select sheets) + - `{ sheet:iso } <= { sheet: et:self }` (`charData` with `withMember`) - `et:self` contributions from the current character - `et:team sheet:agg/iso` queries (e.g., `team.final.atk`) - `{ et:team } <- { src:* et:self }` (`teamData`) - - `et:self` query from each member with appropriate `sheet:` + - `et:self` query from each member with the same `sheet:` - TODO: `et:enemy sheet:enemy`, `sheet:static`, and `sheet:dyn` Notes: @@ -125,14 +125,18 @@ Most formulas also retain these optional tags, so the specified optional tags at ## Mechanisms -## Non-Stacking (`Read.addOnce`) +### Formula Listing TODO -## Priority String +### Non-Stacking (`Read.addOnce`) TODO -## `meta.ts` generation +### Priority String + +TODO + +### `meta.ts` generation TODO From 3ef0e48e1d3227e4e95ec48ec7cab2ea18d8ae88 Mon Sep 17 00:00:00 2001 From: lantua <16190491+lantua@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:26:39 -0400 Subject: [PATCH 12/12] Update doc --- libs/gi/formula/doc/tag_arch.md | 67 +++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/libs/gi/formula/doc/tag_arch.md b/libs/gi/formula/doc/tag_arch.md index d51f352ba4..93f9a9dd17 100644 --- a/libs/gi/formula/doc/tag_arch.md +++ b/libs/gi/formula/doc/tag_arch.md @@ -59,37 +59,66 @@ Once `prep:` calculation is completed, the tags are attached to the base formula The tag categories `et:` and `sheet:` are separated into read-side, which is used by `read` operations, and write-side, which is used as tags in tag database entries. -- Read-side `et:` specifies whether the query computes the current character stat (`et:self`), team-wide stat (`et:team`), the stat of the buff target (`et:target`), or the common enemy stat (`et:enemy`). -- Write-side `et:` specifies whether the entry applies only to the current character (`et:selfBuff`), the entire team (`et:teamBuff`), other members (`et:notSelfBuff`), or the enemy (`et:enemy`). -- Read-side `sheet:` speficies the sheets to include in gathering, whether to gather all sheets from all members (`sheet:agg`), only character sheets of the current member (`sheet:iso`), or common listing outside of any specific sheets (`static`). -- Write-side `sheet:` specifies the sheet the entry belongs to (`sheet://`), or if the entry is a UI custom formula (`sheet:custom`). - +- Read-side `et:` specifies whether the query computes + - The current character stat (`et:self`), + - Team-wide stat (`et:team`), + - The stat of the buff target (`et:target`), or + - The common enemy stat (`et:enemy`). +- Write-side `et:` specifies whether the entry applies + - To the current character (`et:self`), + - To the entire team (`et:teamBuff`, inside sheets only), + - To other members (`et:notSelfBuff`, inside sheets only), or + - To the (common) enemy (`et:enemyDeBuff` inside sheets and `et:enemy` outside sheets). +- Read-side `sheet:` speficies the sheets to include in gathering, whether to gather + - All sheets from all members (`sheet:agg`), + - Only character sheets of the current member (`sheet:iso`), or + - Common listing outside any specific sheets (`static`). +- Write-side `sheet:` specifies + - The sheet the entry belongs to (`sheet://`), or + - That the entry is a UI custom formula (`sheet:custom`). + +Note that some tags are both read- and write-sides. Every query starts with a read-side `sheet: et:` combination. The gathering operation then maps to the appropriate write-side `sheet: et:` via util functions. Following is the gathered entries on different `sheet: et:` combinations: - `sheet:agg et:self` queries (e.g., `self.char.skill`) - - `{ sheet:agg et:self } <= { sheet:custom }` (`data/common/index.ts`) + - Non-specific non-sheet contributions + - `{ sheet:agg et:self } <= { sheet:custom }` from `data/common/index.ts` - Custom contributions - - `{ src: sheet:agg } <= { src:* dst: et:selfBuff/teamBuff/notSelfBuff }` (`teamData`) - - `{ src: sheet:agg } <= { sheet: }` (`char/weapon/artData` with `withMember`) - - Sheet-specific contributions from appropriate members `src: dst:` and write-side `sheet: et:` - - No sheet-specific contributions at top-level as the sheet selection above are wrapped within `withMember`. - So those formulas are only included when `teamData` adds the correct `src:` with `reread` above -- `et:self sheet:iso` queries (e.g., `self.char.lvl`) - - `{ sheet:agg et:self } <= { sheet:custom }` (`data/common/index.ts`) + - `{ sheet:agg } <= { sheet: }` from `char/weapon/artData` with `withMember` + - Sheet-specific `et:self` contributions from appropriate members + - (Artifact only) `{ sheet:art qt:premod } <= { sheet:dyn }` + - Hook for conversion to untagged graph. + - `{ src: sheet:agg } <= { src:* dst: et:teamBuff/notSelfBuff }` from `teamData` + - `{ src: sheet:agg } <= { sheet: }` from `char/weapon/artData` with `withMember` + - Sheet-specific `et:*Buff` contributions from appropriate members `src: dst:` +- `sheet:iso et:self` queries (e.g., `self.char.lvl`) + - Non-specific non-sheet contributions + - `{ sheet:iso et:self } <= { sheet:custom }` from `data/common/index.ts` - Custom contributions - - `{ sheet:iso } <= { sheet: et:self }` (`charData` with `withMember`) - - `et:self` contributions from the current character + - `{ sheet:iso } <= { sheet: }` from `charData` with `withMember` + - Char-sheet-specific `et:self` contributions from the current character +- `sheet:agg et:enemy` queries (e.g., `enemy.common.defIgn`) + - `{ src: sheet:agg } <= { src:* dst: et:enemyDeBuff }` from `teamData` + - `{ src: sheet:agg } <= { sheet: }` from `char/weapon/artData` with `withMember` + - Sheet-specific contributions from appropriate members `src: dst:` and write-side `sheet: et:` +- `sheet:iso et:enemy` queries (unused so far) + - `{ sheet:iso } <= { sheet: }` from `charData` with `withMember` + - Char-sheet-specific contributions from the current character +- `sheet:static et:self/enemy` (e.g., `self.commin.critMode`) + - Non-sheet contributions from the same tag - `et:team sheet:agg/iso` queries (e.g., `team.final.atk`) - `{ et:team } <- { src:* et:self }` (`teamData`) - - `et:self` query from each member with the same `sheet:` -- TODO: `et:enemy sheet:enemy`, `sheet:static`, and `sheet:dyn` + - `et:self` query from each member (with the same `sheet:`) Notes: -- `sheet:iso` contributions use `et:self` instead of `et:selfBuff`. -- Artifact use `sheet:art` instead of `sheet:` as all artifacts are always included together. This helps reduce the `read` needed due to the sheer number of artifacts. +- Write-side `et:*Buff` can only be used inside a sheet as they require the `teamData` entry to insert `src:` and `char/weapon/artData` (with `withMember`) to override `sheet:`. + Outside of a sheet, `et:self/enemy` must be used instead as the `teamData` entry overrides `et:` in the process. + - The convention is to use `selfBuff/teamBuff/notSelfBuff/enemyDebuff` _variables_ for all entry creations, and "fix" the `et:` for sheets when it is `register`ed. +- Artifact use `sheet:art` instead of `sheet:` as all artifacts are always included together. + This helps reduce the `read` needed due to the sheer number of artifacts. - `sheet:` is used only for counting the number equipped artifact of that set. ## Conditionals