I really enjoy OpenFisca, but I recently encountered an issue.
Here is what I did:
I tried to model this variable:
Abatement rate means the rate at which a rate of benefit (for example, specified in Schedule 4) must, under the appropriate income test, be reduced on account of income.
Income Test 1 means that the applicable rate of benefit must be reduced—
(a) by 30 cents for every $1 of the total income of the beneficiary and the beneficiary’s spouse or partner that is more than $160 a week but not more than $250 a week; and
(b) by 70 cents for every $1 of that income that is more than $250 a week
Here is what I expected to happen:
Because the calculation if income is specific (and different) to each social benefit, it does not refer to a specific variable to a range of possible variables, from which we need to use the one that corresponds to the benefit we're calculating.
That breaks a fundamental (implicit?) assumption in OpenFisca: the law does not contain abstract formulations. In software terms, we're not supposed to define variables whose application result in the creation of another variable, because, supposedly, the law doesn't. A good practice has emerged that can be resumed as: Model as a rule-maker, not as a developer.
However, in the text above, income is unknowable as along as benefit is unknowable, and benefit is only knowable at run time. Therefore, I expected to be able to do something like this:
class abatement_rate(variables.Variable):
...
def formula_2018_11_26(people, period, params, *args, **kwargs):
income = kwargs["income"]
...
Or:
class abatement_rate(variables.MetaVariable):
income = lambda variable: variable.income
def formula_2018_11_26(cls, people, period, params):
income = people(cls.income, period)
...
Etc.
Here is what actually happened:
We can't. For now, I had to do this:
@dataclasses.dataclass(frozen=True)
class AbatementRate:
"""Abatement rate applicable to income-tested benefits.
Income test means that the applicable rate of a benefit must be reduced by
a certain amount for each unit of income defined by the policy-maker, above
a certain floor but below a certain ceiling.
Abatement rate is the application of an income test to a specific benefit,
taking into account that benefit's own definition of total income; that is,
"the rate at which a rate of benefit [...] must, under the appropriate
income test, be reduced on account of income."
"""
#: Applicable rate of benefit to be reduced.
applicable_rate: Vector
#: Total income of the beneficiary and the beneficiary’s spouse or partner.
total_income: Vector
def __call__(self, income_test: Callable[[Vector], Vector]) -> Vector:
"""Apply an income test to a benefit's applicable rate."""
# numpy.floor is required for income tests as i.e. "35c for every $1".
floor = numpy.floor(self.total_income)
# The abatement rate regardless of benefit rate.
abatement_rate = income_test(floor)
# The abatement rate capped at the applicable benefit rate.
return numpy.minimum(abatement_rate, self.applicable_rate)
Here is data (or links to it) that can help you reproduce this issue:
While we should not create code abstracttions that do not exist in the law, it seems logical that we were able to model the abstractions that do exist, which today we can't (the current implementation won't be registered as a Variable).
Hi there!
I really enjoy OpenFisca, but I recently encountered an issue.
Here is what I did:
I tried to model this variable:
Abatement rate means the rate at which a rate of benefit (for example, specified in Schedule 4) must, under the appropriate income test, be reduced on account of income.
Income Test 1 means that the applicable rate of benefit must be reduced— (a) by 30 cents for every $1 of the total income of the beneficiary and the beneficiary’s spouse or partner that is more than $160 a week but not more than $250 a week; and (b) by 70 cents for every $1 of that income that is more than $250 a week
Here is what I expected to happen:
Because the calculation if income is specific (and different) to each social benefit, it does not refer to a specific variable to a range of possible variables, from which we need to use the one that corresponds to the benefit we're calculating.
That breaks a fundamental (implicit?) assumption in OpenFisca: the law does not contain abstract formulations. In software terms, we're not supposed to define variables whose application result in the creation of another variable, because, supposedly, the law doesn't. A good practice has emerged that can be resumed as: Model as a rule-maker, not as a developer.
However, in the text above, income is unknowable as along as benefit is unknowable, and benefit is only knowable at run time. Therefore, I expected to be able to do something like this:
Or:
Etc.
Here is what actually happened:
We can't. For now, I had to do this:
Here is data (or links to it) that can help you reproduce this issue:
https://www.legislation.govt.nz/act/public/2018/0032/latest/whole.html#whole https://github.com/digitalaotearoa/openfisca-aotearoa/pull/59 https://github.com/openfisca/openfisca-core/blob/f7d979d461e38278c99874f9cf4e4f8beecb20bf/openfisca_core/simulations/simulation.py#L309-L328
Context
I identify more as a:
Discussion
While we should not create code abstracttions that do not exist in the law, it seems logical that we were able to model the abstractions that do exist, which today we can't (the current implementation won't be registered as a Variable).