kumi 0.0.25 → 0.0.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/CLAUDE.md +4 -0
- data/README.md +86 -78
- data/data/functions/agg/boolean.yaml +6 -2
- data/data/functions/agg/numeric.yaml +32 -16
- data/data/functions/agg/string.yaml +4 -3
- data/data/functions/core/arithmetic.yaml +62 -14
- data/data/functions/core/boolean.yaml +12 -6
- data/data/functions/core/comparison.yaml +25 -13
- data/data/functions/core/constructor.yaml +16 -8
- data/data/functions/core/conversion.yaml +32 -0
- data/data/functions/core/select.yaml +3 -1
- data/data/functions/core/stencil.yaml +14 -5
- data/data/functions/core/string.yaml +9 -4
- data/data/kernels/javascript/core/coercion.yaml +20 -0
- data/data/kernels/ruby/agg/numeric.yaml +1 -1
- data/data/kernels/ruby/core/coercion.yaml +20 -0
- data/docs/ARCHITECTURE.md +277 -0
- data/docs/DEVELOPMENT.md +62 -0
- data/docs/FUNCTIONS.md +955 -0
- data/docs/SYNTAX.md +8 -0
- data/docs/UNSAT_DETECTION.md +83 -0
- data/docs/VSCODE_EXTENSION.md +114 -0
- data/docs/functions-reference.json +1821 -0
- data/golden/array_element/expected/nast.txt +1 -1
- data/golden/array_element/expected/schema_ruby.rb +1 -1
- data/golden/array_index/expected/nast.txt +7 -7
- data/golden/array_index/expected/schema_ruby.rb +1 -1
- data/golden/array_operations/expected/nast.txt +2 -2
- data/golden/array_operations/expected/schema_ruby.rb +1 -1
- data/golden/array_operations/expected/snast.txt +3 -3
- data/golden/cascade_logic/expected/schema_ruby.rb +1 -1
- data/golden/cascade_logic/expected/snast.txt +2 -2
- data/golden/chained_fusion/expected/nast.txt +2 -2
- data/golden/chained_fusion/expected/schema_ruby.rb +1 -1
- data/golden/decimal_explicit/expected/ast.txt +38 -0
- data/golden/decimal_explicit/expected/input_plan.txt +3 -0
- data/golden/decimal_explicit/expected/lir_00_unoptimized.txt +30 -0
- data/golden/decimal_explicit/expected/lir_01_hoist_scalar_references.txt +30 -0
- data/golden/decimal_explicit/expected/lir_02_inlined.txt +44 -0
- data/golden/decimal_explicit/expected/lir_03_cse.txt +40 -0
- data/golden/decimal_explicit/expected/lir_04_1_loop_fusion.txt +40 -0
- data/golden/decimal_explicit/expected/lir_04_loop_invcm.txt +40 -0
- data/golden/decimal_explicit/expected/lir_06_const_prop.txt +40 -0
- data/golden/decimal_explicit/expected/nast.txt +30 -0
- data/golden/decimal_explicit/expected/schema_javascript.mjs +31 -0
- data/golden/decimal_explicit/expected/schema_ruby.rb +57 -0
- data/golden/decimal_explicit/expected/snast.txt +30 -0
- data/golden/decimal_explicit/expected.json +1 -0
- data/golden/decimal_explicit/input.json +5 -0
- data/golden/decimal_explicit/schema.kumi +14 -0
- data/golden/element_arrays/expected/nast.txt +2 -2
- data/golden/element_arrays/expected/schema_ruby.rb +1 -1
- data/golden/element_arrays/expected/snast.txt +1 -1
- data/golden/empty_and_null_inputs/expected/nast.txt +3 -3
- data/golden/empty_and_null_inputs/expected/schema_ruby.rb +1 -1
- data/golden/function_overload/expected/ast.txt +29 -0
- data/golden/function_overload/expected/input_plan.txt +4 -0
- data/golden/function_overload/expected/lir_00_unoptimized.txt +18 -0
- data/golden/function_overload/expected/lir_01_hoist_scalar_references.txt +18 -0
- data/golden/function_overload/expected/lir_02_inlined.txt +20 -0
- data/golden/function_overload/expected/lir_03_cse.txt +20 -0
- data/golden/function_overload/expected/lir_04_1_loop_fusion.txt +20 -0
- data/golden/function_overload/expected/lir_04_loop_invcm.txt +20 -0
- data/golden/function_overload/expected/lir_06_const_prop.txt +20 -0
- data/golden/function_overload/expected/nast.txt +22 -0
- data/golden/function_overload/expected/schema_javascript.mjs +12 -0
- data/golden/function_overload/expected/schema_ruby.rb +39 -0
- data/golden/function_overload/expected/snast.txt +22 -0
- data/golden/function_overload/input.json +8 -0
- data/golden/function_overload/schema.kumi +19 -0
- data/golden/game_of_life/expected/lir_00_unoptimized.txt +4 -4
- data/golden/game_of_life/expected/lir_01_hoist_scalar_references.txt +4 -4
- data/golden/game_of_life/expected/lir_02_inlined.txt +16 -16
- data/golden/game_of_life/expected/lir_03_cse.txt +20 -16
- data/golden/game_of_life/expected/lir_04_1_loop_fusion.txt +20 -16
- data/golden/game_of_life/expected/lir_04_loop_invcm.txt +20 -16
- data/golden/game_of_life/expected/lir_06_const_prop.txt +20 -16
- data/golden/game_of_life/expected/nast.txt +4 -4
- data/golden/game_of_life/expected/schema_javascript.mjs +4 -2
- data/golden/game_of_life/expected/schema_ruby.rb +5 -3
- data/golden/game_of_life/expected/snast.txt +10 -10
- data/golden/hash_keys/expected/schema_ruby.rb +1 -1
- data/golden/hash_value/expected/nast.txt +1 -1
- data/golden/hash_value/expected/schema_ruby.rb +1 -1
- data/golden/hash_value/expected/snast.txt +1 -1
- data/golden/hierarchical_complex/expected/nast.txt +3 -3
- data/golden/hierarchical_complex/expected/schema_ruby.rb +1 -1
- data/golden/hierarchical_complex/expected/snast.txt +3 -3
- data/golden/inline_rename_scope_leak/expected/nast.txt +3 -3
- data/golden/inline_rename_scope_leak/expected/schema_ruby.rb +1 -1
- data/golden/input_reference/expected/nast.txt +2 -2
- data/golden/input_reference/expected/schema_ruby.rb +1 -1
- data/golden/interleaved_fusion/expected/nast.txt +2 -2
- data/golden/interleaved_fusion/expected/schema_ruby.rb +1 -1
- data/golden/let_inline/expected/nast.txt +4 -4
- data/golden/let_inline/expected/schema_ruby.rb +1 -1
- data/golden/loop_fusion/expected/nast.txt +1 -1
- data/golden/loop_fusion/expected/schema_ruby.rb +1 -1
- data/golden/min_reduce_scope/expected/nast.txt +3 -3
- data/golden/min_reduce_scope/expected/schema_ruby.rb +1 -1
- data/golden/min_reduce_scope/expected/snast.txt +1 -1
- data/golden/mixed_dimensions/expected/nast.txt +2 -2
- data/golden/mixed_dimensions/expected/schema_ruby.rb +1 -1
- data/golden/multirank_hoisting/expected/nast.txt +7 -7
- data/golden/multirank_hoisting/expected/schema_ruby.rb +1 -1
- data/golden/nested_hash/expected/nast.txt +1 -1
- data/golden/nested_hash/expected/schema_ruby.rb +1 -1
- data/golden/reduction_broadcast/expected/nast.txt +3 -3
- data/golden/reduction_broadcast/expected/schema_ruby.rb +1 -1
- data/golden/reduction_broadcast/expected/snast.txt +1 -1
- data/golden/roll/expected/schema_ruby.rb +1 -1
- data/golden/shift/expected/schema_ruby.rb +1 -1
- data/golden/shift_2d/expected/schema_ruby.rb +1 -1
- data/golden/simple_math/expected/lir_00_unoptimized.txt +1 -1
- data/golden/simple_math/expected/lir_01_hoist_scalar_references.txt +1 -1
- data/golden/simple_math/expected/lir_02_inlined.txt +1 -1
- data/golden/simple_math/expected/lir_03_cse.txt +1 -1
- data/golden/simple_math/expected/lir_04_1_loop_fusion.txt +1 -1
- data/golden/simple_math/expected/lir_04_loop_invcm.txt +1 -1
- data/golden/simple_math/expected/lir_06_const_prop.txt +1 -1
- data/golden/simple_math/expected/nast.txt +5 -5
- data/golden/simple_math/expected/schema_ruby.rb +1 -1
- data/golden/simple_math/expected/snast.txt +2 -2
- data/golden/streaming_basics/expected/nast.txt +8 -8
- data/golden/streaming_basics/expected/schema_ruby.rb +1 -1
- data/golden/streaming_basics/expected/snast.txt +1 -1
- data/golden/tuples/expected/lir_00_unoptimized.txt +5 -5
- data/golden/tuples/expected/lir_01_hoist_scalar_references.txt +5 -5
- data/golden/tuples/expected/lir_02_inlined.txt +5 -5
- data/golden/tuples/expected/lir_03_cse.txt +5 -5
- data/golden/tuples/expected/lir_04_1_loop_fusion.txt +5 -5
- data/golden/tuples/expected/lir_04_loop_invcm.txt +5 -5
- data/golden/tuples/expected/lir_06_const_prop.txt +5 -5
- data/golden/tuples/expected/nast.txt +4 -4
- data/golden/tuples/expected/schema_ruby.rb +1 -1
- data/golden/tuples/expected/snast.txt +6 -6
- data/golden/tuples_and_arrays/expected/lir_00_unoptimized.txt +1 -1
- data/golden/tuples_and_arrays/expected/lir_01_hoist_scalar_references.txt +1 -1
- data/golden/tuples_and_arrays/expected/lir_02_inlined.txt +2 -2
- data/golden/tuples_and_arrays/expected/lir_03_cse.txt +2 -2
- data/golden/tuples_and_arrays/expected/lir_04_1_loop_fusion.txt +2 -2
- data/golden/tuples_and_arrays/expected/lir_04_loop_invcm.txt +2 -2
- data/golden/tuples_and_arrays/expected/lir_06_const_prop.txt +2 -2
- data/golden/tuples_and_arrays/expected/nast.txt +3 -3
- data/golden/tuples_and_arrays/expected/schema_ruby.rb +1 -1
- data/golden/tuples_and_arrays/expected/snast.txt +2 -2
- data/golden/us_tax_2024/expected/ast.txt +63 -670
- data/golden/us_tax_2024/expected/input_plan.txt +8 -45
- data/golden/us_tax_2024/expected/lir_00_unoptimized.txt +253 -863
- data/golden/us_tax_2024/expected/lir_01_hoist_scalar_references.txt +253 -863
- data/golden/us_tax_2024/expected/lir_02_inlined.txt +1215 -5139
- data/golden/us_tax_2024/expected/lir_03_cse.txt +587 -2460
- data/golden/us_tax_2024/expected/lir_04_1_loop_fusion.txt +632 -2480
- data/golden/us_tax_2024/expected/lir_04_loop_invcm.txt +587 -2460
- data/golden/us_tax_2024/expected/lir_06_const_prop.txt +587 -2460
- data/golden/us_tax_2024/expected/nast.txt +123 -826
- data/golden/us_tax_2024/expected/schema_javascript.mjs +127 -581
- data/golden/us_tax_2024/expected/schema_ruby.rb +135 -610
- data/golden/us_tax_2024/expected/snast.txt +155 -858
- data/golden/us_tax_2024/expected.json +120 -1
- data/golden/us_tax_2024/input.json +18 -9
- data/golden/us_tax_2024/schema.kumi +48 -178
- data/golden/with_constants/expected/lir_00_unoptimized.txt +1 -1
- data/golden/with_constants/expected/lir_01_hoist_scalar_references.txt +1 -1
- data/golden/with_constants/expected/lir_02_inlined.txt +1 -1
- data/golden/with_constants/expected/lir_03_cse.txt +1 -1
- data/golden/with_constants/expected/lir_04_1_loop_fusion.txt +1 -1
- data/golden/with_constants/expected/lir_04_loop_invcm.txt +1 -1
- data/golden/with_constants/expected/lir_06_const_prop.txt +1 -1
- data/golden/with_constants/expected/nast.txt +2 -2
- data/golden/with_constants/expected/schema_ruby.rb +1 -1
- data/golden/with_constants/expected/snast.txt +2 -2
- data/lib/kumi/analyzer.rb +12 -12
- data/lib/kumi/configuration.rb +6 -0
- data/lib/kumi/core/analyzer/passes/formal_constraint_propagator.rb +236 -0
- data/lib/kumi/core/analyzer/passes/input_collector.rb +22 -4
- data/lib/kumi/core/analyzer/passes/nast_dimensional_analyzer_pass.rb +64 -18
- data/lib/kumi/core/analyzer/passes/normalize_to_nast_pass.rb +9 -4
- data/lib/kumi/core/analyzer/passes/snast_pass.rb +3 -1
- data/lib/kumi/core/analyzer/passes/unsat_detector.rb +172 -198
- data/lib/kumi/core/error_reporter.rb +36 -1
- data/lib/kumi/core/errors.rb +33 -1
- data/lib/kumi/core/functions/function_spec.rb +5 -4
- data/lib/kumi/core/functions/loader.rb +17 -1
- data/lib/kumi/core/functions/overload_resolver.rb +164 -0
- data/lib/kumi/core/functions/type_error_reporter.rb +118 -0
- data/lib/kumi/core/functions/type_rules.rb +155 -35
- data/lib/kumi/core/input/type_matcher.rb +8 -1
- data/lib/kumi/core/ruby_parser/input_builder.rb +2 -2
- data/lib/kumi/core/types/inference.rb +29 -22
- data/lib/kumi/core/types/normalizer.rb +30 -45
- data/lib/kumi/core/types/validator.rb +17 -28
- data/lib/kumi/core/types/value_objects.rb +116 -0
- data/lib/kumi/core/types.rb +45 -37
- data/lib/kumi/dev/golden/reporter.rb +9 -0
- data/lib/kumi/dev/golden/result.rb +3 -1
- data/lib/kumi/dev/golden/runtime_test.rb +25 -0
- data/lib/kumi/dev/golden/suite.rb +4 -4
- data/lib/kumi/dev/golden/value_normalizer.rb +80 -0
- data/lib/kumi/dev/golden.rb +21 -12
- data/lib/kumi/doc_generator/formatters/json.rb +39 -0
- data/lib/kumi/doc_generator/formatters/markdown.rb +175 -0
- data/lib/kumi/doc_generator/loader.rb +37 -0
- data/lib/kumi/doc_generator/merger.rb +54 -0
- data/lib/kumi/doc_generator.rb +4 -0
- data/lib/kumi/registry_v2/loader.rb +90 -0
- data/lib/kumi/registry_v2.rb +18 -1
- data/lib/kumi/version.rb +1 -1
- data/vscode-extension/.gitignore +4 -0
- data/vscode-extension/README.md +59 -0
- data/vscode-extension/TESTING.md +151 -0
- data/vscode-extension/package.json +51 -0
- data/vscode-extension/src/extension.ts +295 -0
- data/vscode-extension/tsconfig.json +15 -0
- metadata +57 -7
- data/lib/kumi/core/analyzer/unsat_constant_evaluator.rb +0 -59
- data/lib/kumi/core/atom_unsat_solver.rb +0 -396
- data/lib/kumi/core/constraint_relationship_solver.rb +0 -641
- data/lib/kumi/core/types/builder.rb +0 -23
- data/lib/kumi/core/types/compatibility.rb +0 -96
- data/lib/kumi/core/types/formatter.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a850b47be185d9e65a5b86121f6208b80eac6eba1f8a4bc78879893304cd02ea
|
4
|
+
data.tar.gz: f8a14f4516963be8c6ff8e4b9839189ead2ee134f790ea46f8945e2be6b06876
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f4e71671cf52c9fbbdede6da6d401f44c4e55a6562fdda0b5d866f11d284a1a2645138e8f469d21fe0f7ab3546e5509348b6223f08d914a60a133b21ca9f57b
|
7
|
+
data.tar.gz: 7fa1e8c26b801ce265310f4dc8837ec7ec7f4218798d10360c4ab707f856ef8bb833c80f04cd08f52e1590df502c1d54fa44f270db384e7269abbda79de3eeec
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.0.27] – 2025-10-20
|
4
|
+
### Added
|
5
|
+
- Decimal type system for precise money/bignum calculations
|
6
|
+
- Conversion functions (to_decimal, to_integer, to_float, to_string)
|
7
|
+
- Automatic documentation generation system for IDE support
|
8
|
+
- VSCode extension with schema block detection
|
9
|
+
|
10
|
+
## [0.0.26] – 2025-10-17
|
11
|
+
### Added
|
12
|
+
- UNSAT detection via constraint propagation through operations
|
13
|
+
- Documentation for UNSAT detection in `docs/UNSAT_DETECTION.md`
|
14
|
+
|
15
|
+
### Changed
|
16
|
+
- Moved `UnsatDetector` to work over SNAST for full resolution context (axes/types)
|
17
|
+
- Refactored Typing system, added proper typing metadata on data/functions
|
18
|
+
|
3
19
|
## [0.0.25] – 2025-10-17
|
4
20
|
### Fixed
|
5
21
|
- Fix inlining bug caused by previous fix
|
data/CLAUDE.md
CHANGED
@@ -25,6 +25,10 @@ Axes align by identity (lineage), not by name
|
|
25
25
|
`bin/kumi golden verify [name]` - Verify current vs expected
|
26
26
|
`bin/kumi golden diff <name>` - Show diffs when verification fails
|
27
27
|
|
28
|
+
# Documentation Generation
|
29
|
+
`bin/kumi-doc-gen` - Generate IDE-friendly JSON + Markdown docs from function/kernel definitions
|
30
|
+
See docs/DEVELOPMENT.md for details
|
31
|
+
|
28
32
|
# Kernels Invariants
|
29
33
|
All reducers are pure binary combiner f : T × T → T applied over the last axis of a value. Example: agg.sum(a,b) = a+b.
|
30
34
|
|
data/README.md
CHANGED
@@ -7,103 +7,98 @@
|
|
7
7
|
|
8
8
|
---
|
9
9
|
|
10
|
-
**
|
11
|
-
|
12
|
-
**Feedback**: have a use case or a paper cut? Open an issue or reach out.
|
10
|
+
**Declarative, typed, vectorized calculation DSL (Ruby-embedded) that builds a deterministic dependency graph.**
|
11
|
+
Normalized, typed **AST → IR → LIR**. Static checks and **constraint UNSAT** at compile time. Codegen is thin.
|
13
12
|
|
14
13
|
---
|
15
14
|
|
15
|
+
**Status**: experimental. Public API may change. Typing and some static checks are still evolving.
|
16
16
|
|
17
|
-
**
|
18
|
-
|
19
|
-
Kumi compiles high-level schemas into standalone Ruby and JavaScript with no runtime dependencies.
|
20
|
-
|
21
|
-
**Built for:** finance, tax, pricing, insurance, payroll, analytics—domains where correctness and transparency matter.
|
17
|
+
**Feedback**: have a use case or a paper cut? Open an issue or reach out.
|
22
18
|
|
23
19
|
---
|
24
20
|
|
25
|
-
## Example:
|
21
|
+
## Example: US Tax Calculator (2024)
|
26
22
|
|
23
|
+
See the [interactive demo](https://kumi-play-web.fly.dev/) or browse the [golden test files](golden/us_tax_2024/) (schema, input, expected output, generated code).
|
27
24
|
|
28
25
|
<details>
|
29
26
|
<summary><strong>Schema</strong></summary>
|
30
27
|
|
31
28
|
```ruby
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
29
|
+
schema do
|
30
|
+
input do
|
31
|
+
float :income
|
32
|
+
float :state_rate
|
33
|
+
float :local_rate
|
34
|
+
float :retirement_contrib
|
35
|
+
string :filing_status
|
36
|
+
|
37
|
+
array :statuses do
|
38
|
+
hash :status do
|
39
|
+
string :name
|
40
|
+
float :std
|
41
|
+
float :addl_threshold
|
42
|
+
array :rates do
|
43
|
+
hash :bracket do
|
44
|
+
float :lo
|
45
|
+
float :hi # -1 = open-ended
|
46
|
+
float :rate
|
47
|
+
end
|
40
48
|
end
|
41
49
|
end
|
42
50
|
end
|
43
|
-
|
44
|
-
let :a, input.rows.col.alive
|
45
|
-
|
46
|
-
# axis_offset: 0 = x, 1 = y
|
47
|
-
let :n, shift(a, -1, axis_offset: 1)
|
48
|
-
let :s, shift(a, 1, axis_offset: 1)
|
49
|
-
let :w, shift(a, -1)
|
50
|
-
let :e, shift(a, 1)
|
51
|
-
let :nw, shift(n, -1)
|
52
|
-
let :ne, shift(n, 1)
|
53
|
-
let :sw, shift(s, -1)
|
54
|
-
let :se, shift(s, 1)
|
55
|
-
|
56
|
-
let :neighbors, fn(:sum, [n, s, w, e, nw, ne, sw, se])
|
57
|
-
|
58
|
-
# Conway rules
|
59
|
-
let :alive, a > 0
|
60
|
-
let :n3_alive, neighbors == 3
|
61
|
-
let :n2_alive, neighbors == 2
|
62
|
-
let :keep_alive, n2_alive & alive
|
63
|
-
|
64
|
-
let :next_alive, n3_alive | keep_alive
|
65
|
-
|
66
|
-
value :next_state, select(next_alive, 1, 0)
|
67
51
|
end
|
68
52
|
|
53
|
+
# shared
|
54
|
+
let :big_hi, 100_000_000_000.0
|
55
|
+
let :state_tax, input.income * input.state_rate
|
56
|
+
let :local_tax, input.income * input.local_rate
|
57
|
+
|
58
|
+
# FICA constants
|
59
|
+
let :ss_wage_base, 168_600.0
|
60
|
+
let :ss_rate, 0.062
|
61
|
+
let :med_base_rate, 0.0145
|
62
|
+
let :addl_med_rate, 0.009
|
63
|
+
|
64
|
+
# per-status federal
|
65
|
+
let :taxable, fn(:max, [input.income - input.statuses.status.std, 0])
|
66
|
+
let :lo, input.statuses.status.rates.bracket.lo
|
67
|
+
let :hi, input.statuses.status.rates.bracket.hi
|
68
|
+
let :rate, input.statuses.status.rates.bracket.rate
|
69
|
+
let :hi_eff, select(hi == -1, big_hi, hi)
|
70
|
+
let :amt, fn(:clamp, taxable - lo, 0, hi_eff - lo)
|
71
|
+
let :fed_tax, fn(:sum, amt * rate)
|
72
|
+
let :in_br, (taxable >= lo) & (taxable < hi_eff)
|
73
|
+
let :fed_marg, fn(:sum_if, rate, in_br)
|
74
|
+
let :fed_eff, fed_tax / fn(:max, [input.income, 1.0])
|
75
|
+
|
76
|
+
# per-status FICA
|
77
|
+
let :ss_tax, fn(:min, [input.income, ss_wage_base]) * ss_rate
|
78
|
+
let :med_tax, input.income * med_base_rate
|
79
|
+
let :addl_med_tax, fn(:max, [input.income - input.statuses.status.addl_threshold, 0]) * addl_med_rate
|
80
|
+
let :fica_tax, ss_tax + med_tax + addl_med_tax
|
81
|
+
let :fica_eff, fica_tax / fn(:max, [input.income, 1.0])
|
82
|
+
|
83
|
+
# totals per status
|
84
|
+
let :total_tax, fed_tax + fica_tax + state_tax + local_tax
|
85
|
+
let :total_eff, total_tax / fn(:max, [input.income, 1.0])
|
86
|
+
let :after_tax, input.income - total_tax
|
87
|
+
let :take_home, after_tax - input.retirement_contrib
|
88
|
+
|
89
|
+
# array of result objects, one per status
|
90
|
+
value :summary, {
|
91
|
+
filing_status: input.statuses.status.name,
|
92
|
+
federal: { marginal: fed_marg, effective: fed_eff, tax: fed_tax },
|
93
|
+
fica: { effective: fica_eff, tax: fica_tax },
|
94
|
+
state: { marginal: input.state_rate, effective: input.state_rate, tax: state_tax },
|
95
|
+
local: { marginal: input.local_rate, effective: input.local_rate, tax: local_tax },
|
96
|
+
total: { effective: total_eff, tax: total_tax },
|
97
|
+
after_tax: after_tax,
|
98
|
+
retirement_contrib: input.retirement_contrib,
|
99
|
+
take_home: take_home
|
100
|
+
}
|
69
101
|
end
|
70
|
-
````
|
71
|
-
|
72
|
-
</details>
|
73
|
-
|
74
|
-
|
75
|
-
<details>
|
76
|
-
<summary><strong>Generated JavaScript (excerpt)</strong></summary>
|
77
|
-
|
78
|
-
```js
|
79
|
-
export function _next_state(input) {
|
80
|
-
let out = [];
|
81
|
-
let t285 = input["rows"];
|
82
|
-
let t1539 = t285.length;
|
83
|
-
const t1540 = -1;
|
84
|
-
const t1542 = 0;
|
85
|
-
const t1546 = 1;
|
86
|
-
const t1334 = 3;
|
87
|
-
const t1339 = 2;
|
88
|
-
let t1547 = t1539 - t1546;
|
89
|
-
t285.forEach((rows_el_286, rows_i_287) => {
|
90
|
-
let out_1 = [];
|
91
|
-
let t1541 = rows_i_287 - t1540;
|
92
|
-
let t1561 = rows_i_287 - t1546;
|
93
|
-
let t1580 = ((rows_i_287 % t1539) + t1539) % t1539;
|
94
|
-
// ... neighbor calculations, Conway's rules
|
95
|
-
let t1332 = [t1557, t1577, t1597, t1617, t1645, t1673, t1701, t1729];
|
96
|
-
let t1333 = t1332.reduce((a, b) => a + b, 0);
|
97
|
-
let t1335 = t1333 == t1334;
|
98
|
-
let t1340 = t1333 == t1339;
|
99
|
-
let t1344 = col_el_288 > t1542;
|
100
|
-
let t1345 = t1340 && t1344;
|
101
|
-
let t528 = t1335 || t1345;
|
102
|
-
let t293 = t528 ? t1546 : t1542;
|
103
|
-
out_1.push(t293);
|
104
|
-
});
|
105
|
-
return out;
|
106
|
-
}
|
107
102
|
```
|
108
103
|
|
109
104
|
</details>
|
@@ -146,6 +141,19 @@ Double.write_source("output.mjs", platform: :javascript)
|
|
146
141
|
|
147
142
|
---
|
148
143
|
|
144
|
+
## Documentation
|
145
|
+
|
146
|
+
Auto-generated reference for all functions and kernels:
|
147
|
+
|
148
|
+
- **[Functions Reference](docs/FUNCTIONS.md)** - Human-readable docs with parameters and kernels
|
149
|
+
- **[functions-reference.json](docs/functions-reference.json)** - Machine-readable format for IDEs (VSCode, Monaco, etc.)
|
150
|
+
|
151
|
+
To regenerate: `bin/kumi-doc-gen`
|
152
|
+
|
153
|
+
See [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) for development workflows.
|
154
|
+
|
155
|
+
---
|
156
|
+
|
149
157
|
## License
|
150
158
|
|
151
159
|
MIT License. See [LICENSE](LICENSE).
|
@@ -2,13 +2,17 @@ functions:
|
|
2
2
|
- id: agg.any
|
3
3
|
kind: reduce
|
4
4
|
params: [{ name: source_value }]
|
5
|
-
dtype:
|
5
|
+
dtype:
|
6
|
+
rule: scalar
|
7
|
+
kind: boolean
|
6
8
|
aliases: ["any", "any?"]
|
7
9
|
folding_class_method: any?
|
8
10
|
|
9
11
|
- id: agg.all
|
10
12
|
kind: reduce
|
11
13
|
params: [{ name: source_value }]
|
12
|
-
dtype:
|
14
|
+
dtype:
|
15
|
+
rule: scalar
|
16
|
+
kind: boolean
|
13
17
|
aliases: ["all", "all?"]
|
14
18
|
folding_class_method: all?
|
@@ -2,65 +2,79 @@ functions:
|
|
2
2
|
- id: agg.sum
|
3
3
|
kind: reduce
|
4
4
|
params: [{ name: source_value }]
|
5
|
-
dtype:
|
5
|
+
dtype:
|
6
|
+
rule: same_as
|
7
|
+
param: source_value
|
6
8
|
reduction_strategy: identity # This function has a true identity value.
|
7
9
|
aliases: ["sum"]
|
8
|
-
|
10
|
+
|
9
11
|
- id: agg.count
|
10
12
|
kind: reduce
|
11
13
|
params: [{ name: source_value }]
|
12
|
-
dtype:
|
14
|
+
dtype:
|
15
|
+
rule: scalar
|
16
|
+
kind: integer
|
13
17
|
reduction_strategy: identity # This function has a true identity value.
|
14
18
|
aliases: ["count"]
|
15
19
|
|
16
20
|
- id: agg.min
|
17
21
|
kind: reduce
|
18
22
|
params: [{ name: source_value }]
|
19
|
-
dtype:
|
23
|
+
dtype:
|
24
|
+
rule: element_of
|
25
|
+
param: source_value
|
20
26
|
reduction_strategy: first_element
|
21
27
|
aliases: ["min"]
|
22
28
|
|
23
29
|
- id: agg.max
|
24
30
|
kind: reduce
|
25
31
|
params: [{ name: source_value }]
|
26
|
-
dtype:
|
32
|
+
dtype:
|
33
|
+
rule: element_of
|
34
|
+
param: source_value
|
27
35
|
reduction_strategy: first_element
|
28
36
|
aliases: ["max"]
|
29
|
-
|
37
|
+
|
30
38
|
- id: agg.mean
|
31
39
|
kind: reduce
|
32
40
|
params: [{ name: source_value }]
|
33
|
-
dtype:
|
41
|
+
dtype:
|
42
|
+
rule: scalar
|
43
|
+
kind: float
|
34
44
|
aliases: ["mean", "avg"]
|
35
45
|
expand:
|
36
46
|
fn: div
|
37
47
|
args:
|
38
48
|
- fn: sum
|
39
|
-
args: [
|
49
|
+
args: ["$1"] # $1 is source_value
|
40
50
|
- fn: count
|
41
|
-
args: [
|
51
|
+
args: ["$1"]
|
42
52
|
|
43
53
|
- id: agg.sum_if
|
44
54
|
kind: reduce
|
45
55
|
params: [{ name: source_value }, { name: condition }]
|
46
|
-
dtype:
|
56
|
+
dtype:
|
57
|
+
rule: same_as
|
58
|
+
param: source_value
|
47
59
|
aliases: ["sum_if"]
|
48
60
|
expand:
|
49
61
|
fn: sum
|
50
62
|
args:
|
51
63
|
- fn: __select__
|
52
|
-
args: [
|
64
|
+
args: ["$2", "$1", { const: 0 }] # $1=source_value, $2=condition
|
53
65
|
|
54
66
|
- id: agg.count_if
|
55
67
|
kind: reduce
|
56
68
|
params: [{ name: condition }, { name: source_value }]
|
57
|
-
dtype:
|
69
|
+
dtype:
|
70
|
+
rule: scalar
|
71
|
+
kind: integer
|
58
72
|
aliases: ["count_if"]
|
59
73
|
expand:
|
60
74
|
fn: sum # Summing 1s and 0s is equivalent to a conditional count
|
61
75
|
args:
|
62
76
|
- fn: __select__
|
63
|
-
args:
|
77
|
+
args:
|
64
78
|
- fn: eq
|
65
79
|
args: ["$1", "$2"]
|
66
80
|
- { const: 1 }
|
@@ -69,12 +83,14 @@ functions:
|
|
69
83
|
- id: agg.mean_if
|
70
84
|
kind: reduce
|
71
85
|
params: [{ name: source_value }, { name: condition }]
|
72
|
-
dtype:
|
86
|
+
dtype:
|
87
|
+
rule: scalar
|
88
|
+
kind: float
|
73
89
|
aliases: ["avg_if", "mean_if"]
|
74
90
|
expand:
|
75
91
|
fn: div
|
76
92
|
args:
|
77
93
|
- fn: sum_if
|
78
|
-
args: [
|
94
|
+
args: ["$1", "$2"] # Sum the values where the condition is true
|
79
95
|
- fn: count_if
|
80
|
-
args: [
|
96
|
+
args: ["$1", "$2"] # Count the values where the condition is true
|
@@ -2,49 +2,97 @@ functions:
|
|
2
2
|
- id: core.abs
|
3
3
|
kind: elementwise
|
4
4
|
params: [{ name: number }]
|
5
|
-
dtype:
|
5
|
+
dtype:
|
6
|
+
rule: same_as
|
7
|
+
param: number
|
6
8
|
aliases: ["abs"]
|
7
9
|
|
8
10
|
- id: core.add
|
9
|
-
kind: elementwise
|
11
|
+
kind: elementwise
|
10
12
|
params: [{ name: left_operand }, { name: right_operand }]
|
11
|
-
dtype:
|
13
|
+
dtype:
|
14
|
+
rule: promote
|
15
|
+
params: [left_operand, right_operand]
|
12
16
|
aliases: ["add"]
|
17
|
+
constraint_semantics:
|
18
|
+
domain_effect: EXTEND
|
19
|
+
pure_combiner: true
|
20
|
+
commutativity: true
|
21
|
+
associativity: true
|
22
|
+
identity: 0
|
23
|
+
forward_propagation:
|
24
|
+
# If we know left == L and right == R, then result == L + R
|
25
|
+
equality: "result = left + right"
|
26
|
+
# If result is in [a, b] and left/right in domains, derive tighter bounds
|
27
|
+
range: "result_min = left_min + right_min; result_max = left_max + right_max"
|
28
|
+
reverse_propagation:
|
29
|
+
# If result == V, then left == V - right
|
30
|
+
equality: "left = result - right; right = result - left"
|
31
|
+
# If result in [a, b] and left in [l1, l2], then right in [a - l2, b - l1]
|
32
|
+
range: "left_min = result_min - right_max; left_max = result_max - right_min; right_min = result_min - left_max; right_max = result_max - left_min"
|
13
33
|
|
14
34
|
- id: core.sub
|
15
35
|
kind: elementwise
|
16
|
-
params: [{ name: left_operand }, { name: right_operand }]
|
17
|
-
dtype:
|
36
|
+
params: [{ name: left_operand }, { name: right_operand }]
|
37
|
+
dtype:
|
38
|
+
rule: promote
|
39
|
+
params: [left_operand, right_operand]
|
18
40
|
aliases: ["sub", "subtract"]
|
19
41
|
|
20
42
|
- id: core.mul
|
21
43
|
kind: elementwise
|
22
44
|
params: [{ name: left_operand }, { name: right_operand }]
|
23
|
-
dtype:
|
45
|
+
dtype:
|
46
|
+
rule: promote
|
47
|
+
params: [left_operand, right_operand]
|
24
48
|
aliases: ["mul", "multiply"]
|
49
|
+
constraint_semantics:
|
50
|
+
domain_effect: SCALE
|
51
|
+
pure_combiner: true
|
52
|
+
commutativity: true
|
53
|
+
associativity: true
|
54
|
+
identity: 1
|
55
|
+
forward_propagation:
|
56
|
+
# If we know left == L and right == R, then result == L * R
|
57
|
+
equality: "result = left * right"
|
58
|
+
# For multiplication: result bounds depend on sign of operands
|
59
|
+
range: "result = combinations of {left_min*right_min, left_min*right_max, left_max*right_min, left_max*right_max} -> [min, max]"
|
60
|
+
reverse_propagation:
|
61
|
+
# If result == V and right != 0, then left == V / right
|
62
|
+
equality: "left = result / right (if right != 0); right = result / left (if left != 0)"
|
63
|
+
# For multiplication: divide by absolute values considering sign changes
|
64
|
+
range: "derive from result bounds and operand bounds considering sign combinations"
|
25
65
|
|
26
66
|
- id: core.pow
|
27
67
|
kind: elementwise
|
28
68
|
params: [{ name: base }, { name: exponent }]
|
29
|
-
dtype:
|
69
|
+
dtype:
|
70
|
+
rule: promote
|
71
|
+
params: [base, exponent]
|
30
72
|
aliases: ["pow", "power"]
|
31
73
|
|
32
74
|
- id: core.div
|
33
|
-
kind: elementwise
|
75
|
+
kind: elementwise
|
34
76
|
params: [{ name: left_operand }, { name: right_operand }]
|
35
|
-
dtype:
|
77
|
+
dtype:
|
78
|
+
rule: scalar
|
79
|
+
kind: float
|
36
80
|
aliases: ["div", "divide"]
|
37
81
|
|
38
82
|
- id: core.mod
|
39
83
|
kind: elementwise
|
40
84
|
params:
|
41
|
-
- { name: left_operand}
|
42
|
-
- { name: right_operand}
|
43
|
-
dtype:
|
85
|
+
- { name: left_operand }
|
86
|
+
- { name: right_operand }
|
87
|
+
dtype:
|
88
|
+
rule: promote
|
89
|
+
params: [left_operand, right_operand]
|
44
90
|
aliases: ["mod", "modulo", "%"]
|
45
91
|
|
46
92
|
- id: core.clamp
|
47
93
|
kind: elementwise
|
48
|
-
params: [{name: x},{name: lo},{name: hi}]
|
49
|
-
dtype:
|
94
|
+
params: [{ name: x }, { name: lo }, { name: hi }]
|
95
|
+
dtype:
|
96
|
+
rule: same_as
|
97
|
+
param: x
|
50
98
|
aliases: ["clamp"]
|
@@ -2,17 +2,23 @@ functions:
|
|
2
2
|
- id: core.and
|
3
3
|
kind: elementwise
|
4
4
|
params: [{ name: left_operand }, { name: right_operand }]
|
5
|
-
dtype:
|
6
|
-
|
5
|
+
dtype:
|
6
|
+
rule: scalar
|
7
|
+
kind: boolean
|
8
|
+
aliases: ["and", "&"]
|
7
9
|
|
8
10
|
- id: core.or
|
9
11
|
kind: elementwise
|
10
12
|
params: [{ name: left_operand }, { name: right_operand }]
|
11
|
-
dtype:
|
12
|
-
|
13
|
+
dtype:
|
14
|
+
rule: scalar
|
15
|
+
kind: boolean
|
16
|
+
aliases: ["or", "|"]
|
13
17
|
|
14
18
|
- id: core.not
|
15
19
|
kind: elementwise
|
16
20
|
params: [{ name: operand }]
|
17
|
-
dtype:
|
18
|
-
|
21
|
+
dtype:
|
22
|
+
rule: scalar
|
23
|
+
kind: boolean
|
24
|
+
aliases: ["not", "!"]
|
@@ -2,41 +2,53 @@ functions:
|
|
2
2
|
- id: core.gte
|
3
3
|
kind: elementwise
|
4
4
|
params: [{ name: left_operand }, { name: right_operand }]
|
5
|
-
dtype:
|
6
|
-
|
5
|
+
dtype:
|
6
|
+
rule: scalar
|
7
|
+
kind: boolean
|
8
|
+
aliases: ["gte", "ge", "greater_than_or_equal", ">="]
|
7
9
|
folding_class_method: gte
|
8
10
|
|
9
11
|
- id: core.gt
|
10
12
|
kind: elementwise
|
11
13
|
params: [{ name: left_operand }, { name: right_operand }]
|
12
|
-
dtype:
|
13
|
-
|
14
|
+
dtype:
|
15
|
+
rule: scalar
|
16
|
+
kind: boolean
|
17
|
+
aliases: ["gt", "greater_than", ">"]
|
14
18
|
folding_class_method: gt
|
15
19
|
|
16
20
|
- id: core.lte
|
17
21
|
kind: elementwise
|
18
22
|
params: [{ name: left_operand }, { name: right_operand }]
|
19
|
-
dtype:
|
20
|
-
|
23
|
+
dtype:
|
24
|
+
rule: scalar
|
25
|
+
kind: boolean
|
26
|
+
aliases: ["lte", "le", "less_than_or_equal", "<="]
|
21
27
|
folding_class_method: lte
|
22
28
|
|
23
29
|
- id: core.lt
|
24
30
|
kind: elementwise
|
25
31
|
params: [{ name: left_operand }, { name: right_operand }]
|
26
|
-
dtype:
|
27
|
-
|
32
|
+
dtype:
|
33
|
+
rule: scalar
|
34
|
+
kind: boolean
|
35
|
+
aliases: ["lt", "less_than", "<"]
|
28
36
|
folding_class_method: lt
|
29
37
|
|
30
38
|
- id: core.eq
|
31
|
-
kind: elementwise
|
39
|
+
kind: elementwise
|
32
40
|
params: [{ name: left_operand }, { name: right_operand }]
|
33
|
-
dtype:
|
34
|
-
|
41
|
+
dtype:
|
42
|
+
rule: scalar
|
43
|
+
kind: boolean
|
44
|
+
aliases: ["eq", "equal", "=="]
|
35
45
|
folding_class_method: eq
|
36
46
|
|
37
47
|
- id: core.neq
|
38
48
|
kind: elementwise
|
39
49
|
params: [{ name: left_operand }, { name: right_operand }]
|
40
|
-
dtype:
|
41
|
-
|
50
|
+
dtype:
|
51
|
+
rule: scalar
|
52
|
+
kind: boolean
|
53
|
+
aliases: ["neq", "not_equal", "!="]
|
42
54
|
folding_class_method: neq
|
@@ -1,32 +1,40 @@
|
|
1
1
|
functions:
|
2
|
-
# length is probably in the wrong place
|
2
|
+
# length is probably in the wrong place
|
3
3
|
- id: core.length
|
4
4
|
kind: elementwise
|
5
5
|
params: [{ name: collection, dtype: string }]
|
6
|
-
dtype:
|
6
|
+
dtype:
|
7
|
+
rule: scalar
|
8
|
+
kind: integer
|
7
9
|
aliases: ["length", "len", "size"]
|
8
10
|
folding_class_method: length
|
9
11
|
|
10
12
|
- id: core.array_size
|
11
13
|
kind: elementwise
|
12
14
|
params: [{ name: collection, dtype: array }]
|
13
|
-
dtype:
|
14
|
-
|
15
|
+
dtype:
|
16
|
+
rule: scalar
|
17
|
+
kind: integer
|
18
|
+
aliases: ["array_size", "size"]
|
15
19
|
folding_class_method: length
|
16
20
|
|
17
21
|
- id: core.at
|
18
22
|
kind: elementwise
|
19
|
-
params:
|
23
|
+
params:
|
20
24
|
- { name: collection }
|
21
25
|
- { name: index, dtype: integer }
|
22
|
-
dtype:
|
26
|
+
dtype:
|
27
|
+
rule: element_of
|
28
|
+
param: collection
|
23
29
|
aliases: ["at", "get", "[]"]
|
24
30
|
folding_class_method: at
|
25
31
|
|
26
32
|
- id: core.hash_fetch
|
27
33
|
kind: elementwise
|
28
|
-
params:
|
34
|
+
params:
|
29
35
|
- { name: key, dtype: hash }
|
30
|
-
dtype:
|
36
|
+
dtype:
|
37
|
+
rule: scalar
|
38
|
+
kind: any
|
31
39
|
aliases: ["fetch"]
|
32
40
|
folding_class_method: "[]"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
functions:
|
2
|
+
- id: core.to_decimal
|
3
|
+
kind: elementwise
|
4
|
+
params: [{ name: value }]
|
5
|
+
dtype:
|
6
|
+
rule: scalar
|
7
|
+
kind: decimal
|
8
|
+
aliases: ["to_decimal"]
|
9
|
+
|
10
|
+
- id: core.to_integer
|
11
|
+
kind: elementwise
|
12
|
+
params: [{ name: value }]
|
13
|
+
dtype:
|
14
|
+
rule: scalar
|
15
|
+
kind: integer
|
16
|
+
aliases: ["to_integer", "to_int"]
|
17
|
+
|
18
|
+
- id: core.to_float
|
19
|
+
kind: elementwise
|
20
|
+
params: [{ name: value }]
|
21
|
+
dtype:
|
22
|
+
rule: scalar
|
23
|
+
kind: float
|
24
|
+
aliases: ["to_float"]
|
25
|
+
|
26
|
+
- id: core.to_string
|
27
|
+
kind: elementwise
|
28
|
+
params: [{ name: value }]
|
29
|
+
dtype:
|
30
|
+
rule: scalar
|
31
|
+
kind: string
|
32
|
+
aliases: ["to_string", "to_str"]
|