kumi 0.0.24 → 0.0.26
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 +14 -0
- data/README.md +70 -71
- 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/select.yaml +3 -1
- data/data/functions/core/stencil.yaml +14 -5
- data/data/functions/core/string.yaml +9 -4
- data/data/kernels/ruby/agg/numeric.yaml +1 -1
- data/docs/UNSAT_DETECTION.md +83 -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/lir_02_inlined.txt +8 -8
- data/golden/cascade_logic/expected/schema_ruby.rb +1 -1
- data/golden/cascade_logic/expected/snast.txt +2 -2
- data/golden/chained_fusion/expected/lir_02_inlined.txt +36 -36
- data/golden/chained_fusion/expected/lir_03_cse.txt +23 -23
- data/golden/chained_fusion/expected/lir_04_1_loop_fusion.txt +25 -25
- data/golden/chained_fusion/expected/lir_04_loop_invcm.txt +23 -23
- data/golden/chained_fusion/expected/lir_06_const_prop.txt +23 -23
- data/golden/chained_fusion/expected/nast.txt +2 -2
- data/golden/chained_fusion/expected/schema_javascript.mjs +23 -23
- data/golden/chained_fusion/expected/schema_ruby.rb +28 -28
- 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/lir_02_inlined.txt +18 -18
- data/golden/empty_and_null_inputs/expected/lir_03_cse.txt +17 -17
- data/golden/empty_and_null_inputs/expected/lir_04_1_loop_fusion.txt +17 -17
- data/golden/empty_and_null_inputs/expected/lir_04_loop_invcm.txt +17 -17
- data/golden/empty_and_null_inputs/expected/lir_06_const_prop.txt +17 -17
- data/golden/empty_and_null_inputs/expected/nast.txt +3 -3
- data/golden/empty_and_null_inputs/expected/schema_javascript.mjs +13 -13
- data/golden/empty_and_null_inputs/expected/schema_ruby.rb +18 -18
- 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 +1294 -1294
- data/golden/game_of_life/expected/lir_03_cse.txt +403 -399
- data/golden/game_of_life/expected/lir_04_1_loop_fusion.txt +403 -399
- data/golden/game_of_life/expected/lir_04_loop_invcm.txt +403 -399
- data/golden/game_of_life/expected/lir_06_const_prop.txt +403 -399
- data/golden/game_of_life/expected/nast.txt +4 -4
- data/golden/game_of_life/expected/schema_javascript.mjs +87 -85
- data/golden/game_of_life/expected/schema_ruby.rb +88 -86
- 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/lir_02_inlined.txt +15 -15
- data/golden/hierarchical_complex/expected/lir_03_cse.txt +1 -1
- data/golden/hierarchical_complex/expected/lir_04_1_loop_fusion.txt +1 -1
- data/golden/hierarchical_complex/expected/lir_04_loop_invcm.txt +1 -1
- data/golden/hierarchical_complex/expected/lir_06_const_prop.txt +1 -1
- data/golden/hierarchical_complex/expected/nast.txt +3 -3
- data/golden/hierarchical_complex/expected/schema_javascript.mjs +1 -1
- data/golden/hierarchical_complex/expected/schema_ruby.rb +2 -2
- 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/lir_02_inlined.txt +35 -35
- data/golden/interleaved_fusion/expected/lir_03_cse.txt +26 -26
- data/golden/interleaved_fusion/expected/lir_04_1_loop_fusion.txt +27 -26
- data/golden/interleaved_fusion/expected/lir_04_loop_invcm.txt +26 -26
- data/golden/interleaved_fusion/expected/lir_06_const_prop.txt +26 -26
- data/golden/interleaved_fusion/expected/nast.txt +2 -2
- data/golden/interleaved_fusion/expected/schema_javascript.mjs +23 -23
- data/golden/interleaved_fusion/expected/schema_ruby.rb +29 -29
- data/golden/let_inline/expected/nast.txt +4 -4
- data/golden/let_inline/expected/schema_ruby.rb +1 -1
- data/golden/loop_fusion/expected/lir_02_inlined.txt +17 -17
- data/golden/loop_fusion/expected/lir_03_cse.txt +14 -14
- data/golden/loop_fusion/expected/lir_04_1_loop_fusion.txt +14 -14
- data/golden/loop_fusion/expected/lir_04_loop_invcm.txt +14 -14
- data/golden/loop_fusion/expected/lir_06_const_prop.txt +14 -14
- data/golden/loop_fusion/expected/nast.txt +1 -1
- data/golden/loop_fusion/expected/schema_javascript.mjs +12 -12
- data/golden/loop_fusion/expected/schema_ruby.rb +16 -16
- 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/lir_02_inlined.txt +5 -5
- data/golden/mixed_dimensions/expected/lir_03_cse.txt +5 -5
- data/golden/mixed_dimensions/expected/lir_04_1_loop_fusion.txt +5 -5
- data/golden/mixed_dimensions/expected/lir_04_loop_invcm.txt +5 -5
- data/golden/mixed_dimensions/expected/lir_06_const_prop.txt +5 -5
- data/golden/mixed_dimensions/expected/nast.txt +2 -2
- data/golden/mixed_dimensions/expected/schema_javascript.mjs +3 -3
- data/golden/mixed_dimensions/expected/schema_ruby.rb +6 -6
- data/golden/multirank_hoisting/expected/lir_02_inlined.txt +48 -48
- data/golden/multirank_hoisting/expected/lir_03_cse.txt +35 -35
- data/golden/multirank_hoisting/expected/lir_04_1_loop_fusion.txt +35 -35
- data/golden/multirank_hoisting/expected/lir_04_loop_invcm.txt +35 -35
- data/golden/multirank_hoisting/expected/lir_06_const_prop.txt +35 -35
- data/golden/multirank_hoisting/expected/nast.txt +7 -7
- data/golden/multirank_hoisting/expected/schema_javascript.mjs +34 -34
- data/golden/multirank_hoisting/expected/schema_ruby.rb +36 -36
- data/golden/nested_hash/expected/nast.txt +1 -1
- data/golden/nested_hash/expected/schema_ruby.rb +1 -1
- data/golden/reduction_broadcast/expected/lir_02_inlined.txt +30 -30
- data/golden/reduction_broadcast/expected/lir_03_cse.txt +22 -22
- data/golden/reduction_broadcast/expected/lir_04_1_loop_fusion.txt +22 -22
- data/golden/reduction_broadcast/expected/lir_04_loop_invcm.txt +22 -22
- data/golden/reduction_broadcast/expected/lir_06_const_prop.txt +22 -22
- data/golden/reduction_broadcast/expected/nast.txt +3 -3
- data/golden/reduction_broadcast/expected/schema_javascript.mjs +18 -18
- data/golden/reduction_broadcast/expected/schema_ruby.rb +23 -23
- 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/lir_02_inlined.txt +25 -25
- data/golden/streaming_basics/expected/lir_03_cse.txt +13 -13
- data/golden/streaming_basics/expected/lir_04_1_loop_fusion.txt +13 -13
- data/golden/streaming_basics/expected/lir_04_loop_invcm.txt +13 -13
- data/golden/streaming_basics/expected/lir_06_const_prop.txt +13 -13
- data/golden/streaming_basics/expected/nast.txt +8 -8
- data/golden/streaming_basics/expected/schema_javascript.mjs +13 -13
- data/golden/streaming_basics/expected/schema_ruby.rb +14 -14
- 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 +17 -17
- data/golden/tuples_and_arrays/expected/lir_03_cse.txt +13 -13
- data/golden/tuples_and_arrays/expected/lir_04_1_loop_fusion.txt +13 -13
- data/golden/tuples_and_arrays/expected/lir_04_loop_invcm.txt +13 -13
- data/golden/tuples_and_arrays/expected/lir_06_const_prop.txt +13 -13
- data/golden/tuples_and_arrays/expected/nast.txt +3 -3
- data/golden/tuples_and_arrays/expected/schema_javascript.mjs +13 -13
- data/golden/tuples_and_arrays/expected/schema_ruby.rb +14 -14
- 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 -2400
- data/golden/us_tax_2024/expected/lir_06_const_prop.txt +587 -2400
- 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/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/lir/inline_declarations_pass.rb +118 -74
- 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/types/inference.rb +29 -22
- data/lib/kumi/core/types/normalizer.rb +29 -45
- data/lib/kumi/core/types/validator.rb +16 -27
- data/lib/kumi/core/types/value_objects.rb +116 -0
- data/lib/kumi/core/types.rb +45 -37
- data/lib/kumi/registry_v2/loader.rb +90 -0
- data/lib/kumi/registry_v2.rb +18 -1
- data/lib/kumi/version.rb +1 -1
- metadata +21 -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: b422f7930abf2d8300bcc0a6f565a4adf1505cb722f1d51abf42e776617eb255
|
4
|
+
data.tar.gz: b9920b8399e8521eb7517427a36118b0ccbdd9fb1d92644db822d9dbc755b0b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d541c8a5839a7f8e8f5cd2c4e9e8e1418e474bca0d81152f4e0043a09e059ab4839bda084aa32c141938dfb3971815071219daa2e3d5733590ba8e2d84f830ba
|
7
|
+
data.tar.gz: 72f061aa65ec67d5f0d99812d5429225f5a623e0a5f49fdad27260fc6335629b85ae69dada088f05aef24b00a22c912194c8075c9d7373b43fbf433954f417ca
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,18 @@
|
|
1
1
|
## [Unreleased]
|
2
|
+
|
3
|
+
## [0.0.26] – 2025-10-17
|
4
|
+
### Added
|
5
|
+
- UNSAT detection via constraint propagation through operations
|
6
|
+
- Documentation for UNSAT detection in `docs/UNSAT_DETECTION.md`
|
7
|
+
|
8
|
+
### Changed
|
9
|
+
- Moved `UnsatDetector` to work over SNAST for full resolution context (axes/types)
|
10
|
+
- Refactored Typing system, added proper typing metadata on data/functions
|
11
|
+
|
12
|
+
## [0.0.25] – 2025-10-17
|
13
|
+
### Fixed
|
14
|
+
- Fix inlining bug caused by previous fix
|
15
|
+
|
2
16
|
## [0.0.24] – 2025-10-16
|
3
17
|
### Fixed
|
4
18
|
- Bug when inlining of declarations with multiple axis reductions.
|
data/README.md
CHANGED
@@ -16,94 +16,93 @@
|
|
16
16
|
|
17
17
|
**Declarative calculation DSL for Ruby.** Write business rules once, run them anywhere.
|
18
18
|
|
19
|
-
Kumi compiles high-level schemas into standalone Ruby and JavaScript with no runtime dependencies.
|
19
|
+
Kumi compiles high-level schemas into standalone Ruby and JavaScript with no runtime dependencies. Includes static analysis to catch impossible constraints before runtime.
|
20
20
|
|
21
21
|
**Built for:** finance, tax, pricing, insurance, payroll, analytics—domains where correctness and transparency matter.
|
22
22
|
|
23
23
|
---
|
24
24
|
|
25
|
-
## Example:
|
25
|
+
## Example: US Tax Calculator (2024)
|
26
26
|
|
27
|
+
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
28
|
|
28
29
|
<details>
|
29
30
|
<summary><strong>Schema</strong></summary>
|
30
31
|
|
31
32
|
```ruby
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
33
|
+
schema do
|
34
|
+
input do
|
35
|
+
float :income
|
36
|
+
float :state_rate
|
37
|
+
float :local_rate
|
38
|
+
float :retirement_contrib
|
39
|
+
string :filing_status
|
40
|
+
|
41
|
+
array :statuses do
|
42
|
+
hash :status do
|
43
|
+
string :name
|
44
|
+
float :std
|
45
|
+
float :addl_threshold
|
46
|
+
array :rates do
|
47
|
+
hash :bracket do
|
48
|
+
float :lo
|
49
|
+
float :hi # -1 = open-ended
|
50
|
+
float :rate
|
51
|
+
end
|
40
52
|
end
|
41
53
|
end
|
42
54
|
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
55
|
end
|
68
56
|
|
57
|
+
# shared
|
58
|
+
let :big_hi, 100_000_000_000.0
|
59
|
+
let :state_tax, input.income * input.state_rate
|
60
|
+
let :local_tax, input.income * input.local_rate
|
61
|
+
|
62
|
+
# FICA constants
|
63
|
+
let :ss_wage_base, 168_600.0
|
64
|
+
let :ss_rate, 0.062
|
65
|
+
let :med_base_rate, 0.0145
|
66
|
+
let :addl_med_rate, 0.009
|
67
|
+
|
68
|
+
# per-status federal
|
69
|
+
let :taxable, fn(:max, [input.income - input.statuses.status.std, 0])
|
70
|
+
let :lo, input.statuses.status.rates.bracket.lo
|
71
|
+
let :hi, input.statuses.status.rates.bracket.hi
|
72
|
+
let :rate, input.statuses.status.rates.bracket.rate
|
73
|
+
let :hi_eff, select(hi == -1, big_hi, hi)
|
74
|
+
let :amt, fn(:clamp, taxable - lo, 0, hi_eff - lo)
|
75
|
+
let :fed_tax, fn(:sum, amt * rate)
|
76
|
+
let :in_br, (taxable >= lo) & (taxable < hi_eff)
|
77
|
+
let :fed_marg, fn(:sum_if, rate, in_br)
|
78
|
+
let :fed_eff, fed_tax / fn(:max, [input.income, 1.0])
|
79
|
+
|
80
|
+
# per-status FICA
|
81
|
+
let :ss_tax, fn(:min, [input.income, ss_wage_base]) * ss_rate
|
82
|
+
let :med_tax, input.income * med_base_rate
|
83
|
+
let :addl_med_tax, fn(:max, [input.income - input.statuses.status.addl_threshold, 0]) * addl_med_rate
|
84
|
+
let :fica_tax, ss_tax + med_tax + addl_med_tax
|
85
|
+
let :fica_eff, fica_tax / fn(:max, [input.income, 1.0])
|
86
|
+
|
87
|
+
# totals per status
|
88
|
+
let :total_tax, fed_tax + fica_tax + state_tax + local_tax
|
89
|
+
let :total_eff, total_tax / fn(:max, [input.income, 1.0])
|
90
|
+
let :after_tax, input.income - total_tax
|
91
|
+
let :take_home, after_tax - input.retirement_contrib
|
92
|
+
|
93
|
+
# array of result objects, one per status
|
94
|
+
value :summary, {
|
95
|
+
filing_status: input.statuses.status.name,
|
96
|
+
federal: { marginal: fed_marg, effective: fed_eff, tax: fed_tax },
|
97
|
+
fica: { effective: fica_eff, tax: fica_tax },
|
98
|
+
state: { marginal: input.state_rate, effective: input.state_rate, tax: state_tax },
|
99
|
+
local: { marginal: input.local_rate, effective: input.local_rate, tax: local_tax },
|
100
|
+
total: { effective: total_eff, tax: total_tax },
|
101
|
+
after_tax: after_tax,
|
102
|
+
retirement_contrib: input.retirement_contrib,
|
103
|
+
take_home: take_home
|
104
|
+
}
|
69
105
|
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
106
|
```
|
108
107
|
|
109
108
|
</details>
|
@@ -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: "[]"
|
@@ -2,6 +2,8 @@ functions:
|
|
2
2
|
- id: __select__
|
3
3
|
kind: elementwise
|
4
4
|
params: [{ name: condition_mask }, { name: value_when_true }, { name: value_when_false }]
|
5
|
-
dtype:
|
5
|
+
dtype:
|
6
|
+
rule: same_as
|
7
|
+
param: value_when_true
|
6
8
|
aliases: ["select", "if"]
|
7
9
|
folding_class_method: select
|
@@ -1,8 +1,10 @@
|
|
1
1
|
functions:
|
2
2
|
- id: roll
|
3
3
|
kind: elementwise
|
4
|
-
params: [{ name: source }, { name: offset }]
|
5
|
-
dtype:
|
4
|
+
params: [{ name: source }, { name: offset }]
|
5
|
+
dtype:
|
6
|
+
rule: same_as
|
7
|
+
param: source
|
6
8
|
options:
|
7
9
|
policy: wrap # wrap|clamp
|
8
10
|
axis_offset: 0
|
@@ -10,12 +12,19 @@ functions:
|
|
10
12
|
- id: shift
|
11
13
|
kind: elementwise
|
12
14
|
params: [{ name: source }, { name: offset }]
|
13
|
-
dtype:
|
15
|
+
dtype:
|
16
|
+
rule: same_as
|
17
|
+
param: source
|
14
18
|
options:
|
15
19
|
policy: zero # zero|clamp
|
16
20
|
axis_offset: 0
|
21
|
+
constraint_semantics:
|
22
|
+
domain_effect: NONE
|
23
|
+
pure_combiner: false
|
17
24
|
|
18
25
|
- id: index
|
19
26
|
kind: elementwise
|
20
|
-
params: [{name: index_name, dtype: string }]
|
21
|
-
dtype:
|
27
|
+
params: [{ name: index_name, dtype: string }]
|
28
|
+
dtype:
|
29
|
+
rule: scalar
|
30
|
+
kind: integer
|
@@ -2,18 +2,23 @@ functions:
|
|
2
2
|
- id: core.concat
|
3
3
|
kind: elementwise
|
4
4
|
params: [{ name: left_string }, { name: right_string }]
|
5
|
-
dtype:
|
5
|
+
dtype:
|
6
|
+
rule: scalar
|
7
|
+
kind: string
|
6
8
|
aliases: ["concat"]
|
7
9
|
|
8
10
|
- id: core.upcase
|
9
11
|
kind: elementwise
|
10
12
|
params: [{ name: string }]
|
11
|
-
dtype:
|
13
|
+
dtype:
|
14
|
+
rule: scalar
|
15
|
+
kind: string
|
12
16
|
aliases: ["upcase"]
|
13
17
|
|
14
18
|
- id: core.downcase
|
15
19
|
kind: elementwise
|
16
20
|
params: [{ name: string }]
|
17
|
-
dtype:
|
21
|
+
dtype:
|
22
|
+
rule: scalar
|
23
|
+
kind: string
|
18
24
|
aliases: ["downcase"]
|
19
|
-
|