]>
git.scottworley.com Git - inverse-tax/blob - tax.js
3 function parse_table(as_text
) {
4 function parse_line(line
) {
5 return line
.trim().split(' ').filter(x
=> x
!== '').map(x
=> parseFloat(x
));
7 return as_text
.trim().split('\n').map(parse_line
);
10 function tax_table_from_table(table
) {
11 return table
.map(([start
, rate
], i
, table
) =>
12 [start
, i
< table
.length
- 1 ? table
[i
+1][0] : Infinity
, rate
/ 100.0]);
15 function parse_tax_table(as_text
) {
16 return tax_table_from_table(parse_table(as_text
));
20 return nums
.reduce((total
, num
) => total
+ num
, 0);
23 function tax(table
, income
) {
24 return sum(table
.map(([start
, end
, rate
]) =>
25 Math
.max(0, Math
.min(income
, end
) - start
) * rate
));
28 function apply_deductible(table
, deductible
) {
29 return table
.map(([start
, end
, rate
]) => [start
+ deductible
, end
+ deductible
, rate
]);
32 function merge_tax_tables(t1
, t2
) {
33 if (t1
.length
== 0) return t2
;
34 if (t2
.length
== 0) return t1
;
35 const [start1
, end1
, rate1
] = t1
[0];
36 const [start2
, end2
, rate2
] = t2
[0];
37 if (start1
== start2
) {
39 return [[start1
, end1
, rate1
+ rate2
]].concat(merge_tax_tables(t1
.slice(1), t2
.slice(1)));
42 return [[start1
, end1
, rate1
+ rate2
]].concat(merge_tax_tables(t1
.slice(1), [[end1
, end2
, rate2
]].concat(t2
.slice(1))));
44 return merge_tax_tables(t2
, t1
);
46 if (start1
< start2
) {
48 return [t1
[0]].concat(merge_tax_tables(t1
.slice(1), t2
));
50 return [[start1
, start2
, rate1
]].concat(merge_tax_tables([[start2
, end1
, rate1
]].concat(t1
.slice(1)), t2
));
52 return merge_tax_tables(t2
, t1
);
55 function invert(table
) {
56 if (table
.length
== 0) return x
=> x
;
59 // net = m * gross + b
61 // net - b = m * gross
62 // (net - b) / m = gross
63 // and the calculate the inverse's bounds
65 const ms
= table
.map(([start
, end
, rate
]) => 1 - rate
);
66 const full_brackets
= [[0]].concat(table
.map(([start
, end
, rate
]) => (end
- start
) * rate
)).slice(0, table
.length
);
67 function sum_lower_brackets(remaining_brackets
, acc
= 0) {
68 if (remaining_brackets
.length
== 0) return [];
69 return [acc
+ remaining_brackets
[0]].concat(sum_lower_brackets(remaining_brackets
.slice(1), acc
+ remaining_brackets
[0]));
71 const bs
= sum_lower_brackets(full_brackets
).map((lower_brackets
, i
) => {
72 const [start
, end
, rate
] = table
[i
];
74 // net = gross - lower_brackets - rate * (gross - start)
75 // net = gross - lower_brackets - rate * gross + rate * start
76 // net = gross - rate * gross - lower_brackets + rate * start
77 // net = (1 - rate) * gross - lower_brackets + rate * start
78 // net = m * gross - lower_brackets + rate * start
79 // \_____________________________/ - here is b
80 return rate
* start
- lower_brackets
;
82 const inverse_table
= table
.map(([start
, end
, rate
], i
) => {
85 return [(start
- b
) / m
, (end
- b
) / m
, m
, b
];
87 return function(net
) {
88 for (const [start
, end
, m
, b
] of inverse_table
) {
89 if (start
< net
&& net
< end
) {