Skip to content

Commit

Permalink
As of date parameters (#1212)
Browse files Browse the repository at this point in the history
benjello authored Aug 3, 2024
2 parents 8e28b0d + bc4ac9e commit 8c6bc57
Showing 10 changed files with 538 additions and 2 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# Changelog

### 41.4.7 [#1212](https://github.com/openfisca/openfisca-core/pull/1212)
## 41.5.0 [#1212](https://github.com/openfisca/openfisca-core/pull/1212)

#### New features

- Introduce `VectorialAsofDateParameterNodeAtInstant`
- It is a parameter node of the legislation at a given instant which has been vectorized along some date.
- Vectorized parameters allow requests such as parameters.housing_benefit[date], where date is a `numpy.datetime64` vector

### 41.4.7 [#1211](https://github.com/openfisca/openfisca-core/pull/1211)

#### Technical changes

2 changes: 2 additions & 0 deletions openfisca_core/parameters/__init__.py
Original file line number Diff line number Diff line change
@@ -41,6 +41,7 @@
from .parameter_scale_bracket import ParameterScaleBracket
from .parameter_scale_bracket import ParameterScaleBracket as Bracket
from .values_history import ValuesHistory
from .vectorial_asof_date_parameter_node_at_instant import VectorialAsofDateParameterNodeAtInstant
from .vectorial_parameter_node_at_instant import VectorialParameterNodeAtInstant

__all__ = [
@@ -63,5 +64,6 @@
"ParameterScaleBracket",
"Bracket",
"ValuesHistory",
"VectorialAsofDateParameterNodeAtInstant",
"VectorialParameterNodeAtInstant",
]
4 changes: 4 additions & 0 deletions openfisca_core/parameters/parameter_node_at_instant.py
Original file line number Diff line number Diff line change
@@ -41,6 +41,10 @@ def __getattr__(self, key):
def __getitem__(self, key):
# If fancy indexing is used, cast to a vectorial node
if isinstance(key, numpy.ndarray):
# If fancy indexing is used wit a datetime64, cast to a vectorial node supporting datetime64
if numpy.issubdtype(key.dtype, numpy.datetime64):
return parameters.VectorialAsofDateParameterNodeAtInstant.build_from_node(self)[key]

return parameters.VectorialParameterNodeAtInstant.build_from_node(self)[key]
return self._children[key]

Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import numpy

from openfisca_core.parameters.parameter_node_at_instant import ParameterNodeAtInstant
from openfisca_core.parameters.vectorial_parameter_node_at_instant import VectorialParameterNodeAtInstant


class VectorialAsofDateParameterNodeAtInstant(VectorialParameterNodeAtInstant):
"""
Parameter node of the legislation at a given instant which has been vectorized along some date.
Vectorized parameters allow requests such as parameters.housing_benefit[date], where date is a np.datetime64 type vector
"""

@staticmethod
def build_from_node(node):
VectorialParameterNodeAtInstant.check_node_vectorisable(node)
subnodes_name = node._children.keys()
# Recursively vectorize the children of the node
vectorial_subnodes = tuple([
VectorialAsofDateParameterNodeAtInstant.build_from_node(node[subnode_name]).vector
if isinstance(node[subnode_name], ParameterNodeAtInstant)
else node[subnode_name]
for subnode_name in subnodes_name
])
# A vectorial node is a wrapper around a numpy recarray
# We first build the recarray
recarray = numpy.array(
[vectorial_subnodes],
dtype=[
(subnode_name, subnode.dtype if isinstance(subnode, numpy.recarray) else 'float')
for (subnode_name, subnode) in zip(subnodes_name, vectorial_subnodes)
]
)
return VectorialAsofDateParameterNodeAtInstant(node._name, recarray.view(numpy.recarray), node._instant_str)

def __getitem__(self, key):
# If the key is a string, just get the subnode
if isinstance(key, str):
key = numpy.array([key], dtype='datetime64[D]')
return self.__getattr__(key)
# If the key is a vector, e.g. ['1990-11-25', '1983-04-17', '1969-09-09']
elif isinstance(key, numpy.ndarray):
assert numpy.issubdtype(key.dtype, numpy.datetime64)
names = list(self.dtype.names) # Get all the names of the subnodes, e.g. ['before_X', 'after_X', 'after_Y']
values = numpy.asarray([value for value in self.vector[0]])
names = [
name
for name in names
if not name.startswith("before")
]
names = [
numpy.datetime64(
"-".join(name[len("after_"):].split("_"))
)
for name in names
]
conditions = sum([
name <= key
for name in names
])
result = values[conditions]

# If the result is not a leaf, wrap the result in a vectorial node.
if numpy.issubdtype(result.dtype, numpy.record) or numpy.issubdtype(result.dtype, numpy.void):
return VectorialAsofDateParameterNodeAtInstant(self._name, result.view(numpy.recarray), self._instant_str)

return result
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -66,7 +66,7 @@

setup(
name="OpenFisca-Core",
version="41.4.7",
version="41.5.0",
author="OpenFisca Team",
author_email="[email protected]",
classifiers=[
Empty file.
121 changes: 121 additions & 0 deletions tests/core/parameters_date_indexing/full_rate_age.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
description: Full rate age
full_rate_age_by_birthdate:
description: Full rate age by birthdate
before_1951_07_01:
description: Born before 01/07/1951
year:
description: Year
values:
1983-04-01:
value: 65.0
month:
description: Month
values:
1983-04-01:
value: 0.0
after_1951_07_01:
description: Born after 01/07/1951
year:
description: Year
values:
2011-07-01:
value: 65.0
1983-04-01:
value: null
month:
description: Month
values:
2011-07-01:
value: 4.0
1983-04-01:
value: null
after_1952_01_01:
description: Born after 01/01/1952
year:
description: Year
values:
2011-07-01:
value: 65.0
1983-04-01:
value: null
month:
description: Month
values:
2012-01-01:
value: 9.0
2011-07-01:
value: 8.0
1983-04-01:
value: null
after_1953_01_01:
description: Born after 01/01/1953
year:
description: Year
values:
2011-07-01:
value: 66.0
1983-04-01:
value: null
month:
description: Month
values:
2012-01-01:
value: 2.0
2011-07-01:
value: 0.0
1983-04-01:
value: null
after_1954_01_01:
description: Born after 01/01/1954
year:
description: Year
values:
2011-07-01:
value: 66.0
1983-04-01:
value: null
month:
description: Month
values:
2012-01-01:
value: 7.0
2011-07-01:
value: 4.0
1983-04-01:
value: null
after_1955_01_01:
description: Born after 01/01/1955
year:
description: Year
values:
2012-01-01:
value: 67.0
2011-07-01:
value: 66.0
1983-04-01:
value: null
month:
description: Month
values:
2012-01-01:
value: 0.0
2011-07-01:
value: 8.0
1983-04-01:
value: null
after_1956_01_01:
description: Born after 01/01/1956
year:
description: Year
values:
2011-07-01:
value: 67.0
1983-04-01:
value: null
month:
description: Month
values:
2011-07-01:
value: 0.0
1983-04-01:
value: null
162 changes: 162 additions & 0 deletions tests/core/parameters_date_indexing/full_rate_required_duration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
description: Required contribution duration for full rate
contribution_quarters_required_by_birthdate:
description: Contribution quarters required by birthdate
before_1934_01_01:
description: before 1934
values:
1983-01-01:
value: 150.0
after_1934_01_01:
description: '1934-01-01'
values:
1994-01-01:
value: 151.0
1983-01-01:
value: null
after_1935_01_01:
description: '1935-01-01'
values:
1994-01-01:
value: 152.0
1983-01-01:
value: null
after_1936_01_01:
description: '1936-01-01'
values:
1994-01-01:
value: 153.0
1983-01-01:
value: null
after_1937_01_01:
description: '1937-01-01'
values:
1994-01-01:
value: 154.0
1983-01-01:
value: null
after_1938_01_01:
description: '1938-01-01'
values:
1994-01-01:
value: 155.0
1983-01-01:
value: null
after_1939_01_01:
description: '1939-01-01'
values:
1994-01-01:
value: 156.0
1983-01-01:
value: null
after_1940_01_01:
description: '1940-01-01'
values:
1994-01-01:
value: 157.0
1983-01-01:
value: null
after_1941_01_01:
description: '1941-01-01'
values:
1994-01-01:
value: 158.0
1983-01-01:
value: null
after_1942_01_01:
description: '1942-01-01'
values:
1994-01-01:
value: 159.0
1983-01-01:
value: null
after_1943_01_01:
description: '1943-01-01'
values:
1994-01-01:
value: 160.0
1983-01-01:
value: null
after_1949_01_01:
description: '1949-01-01'
values:
2009-01-01:
value: 161.0
1983-01-01:
value: null
after_1950_01_01:
description: '1950-01-01'
values:
2009-01-01:
value: 162.0
1983-01-01:
value: null
after_1951_01_01:
description: '1951-01-01'
values:
2009-01-01:
value: 163.0
1983-01-01:
value: null
after_1952_01_01:
description: '1952-01-01'
values:
2009-01-01:
value: 164.0
1983-01-01:
value: null
after_1953_01_01:
description: '1953-01-01'
values:
2012-01-01:
value: 165.0
1983-01-01:
value: null
after_1955_01_01:
description: '1955-01-01'
values:
2013-01-01:
value: 166.0
1983-01-01:
value: null
after_1958_01_01:
description: '1958-01-01'
values:
2015-01-01:
value: 167.0
1983-01-01:
value: null
after_1961_01_01:
description: '1961-01-01'
values:
2015-01-01:
value: 168.0
1983-01-01:
value: null
after_1964_01_01:
description: '1964-01-01'
values:
2015-01-01:
value: 169.0
1983-01-01:
value: null
after_1967_01_01:
description: '1967-01-01'
values:
2015-01-01:
value: 170.0
1983-01-01:
value: null
after_1970_01_01:
description: '1970-01-01'
values:
2015-01-01:
value: 171.0
1983-01-01:
value: null
after_1973_01_01:
description: '1973-01-01'
values:
2015-01-01:
value: 172.0
1983-01-01:
value: null
38 changes: 38 additions & 0 deletions tests/core/parameters_date_indexing/test_date_indexing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import numpy
import os


from openfisca_core.tools import assert_near
from openfisca_core.parameters import ParameterNode
from openfisca_core.model_api import * # noqa

LOCAL_DIR = os.path.dirname(os.path.abspath(__file__))

parameters = ParameterNode(directory_path=LOCAL_DIR)


def get_message(error):
return error.args[0]


def test_on_leaf():
parameter_at_instant = parameters.full_rate_required_duration('1995-01-01')
birthdate = numpy.array(['1930-01-01', '1935-01-01', '1940-01-01', '1945-01-01'], dtype='datetime64[D]')
assert_near(parameter_at_instant.contribution_quarters_required_by_birthdate[birthdate], [150, 152, 157, 160])


def test_on_node():
birthdate = numpy.array(['1950-01-01', '1953-01-01', '1956-01-01', '1959-01-01'], dtype='datetime64[D]')
parameter_at_instant = parameters.full_rate_age('2012-03-01')
node = parameter_at_instant.full_rate_age_by_birthdate[birthdate]
assert_near(node.year, [65, 66, 67, 67])
assert_near(node.month, [0, 2, 0, 0])


# def test_inhomogenous():
# birthdate = numpy.array(['1930-01-01', '1935-01-01', '1940-01-01', '1945-01-01'], dtype = 'datetime64[D]')
# parameter_at_instant = parameters..full_rate_age('2011-01-01')
# parameter_at_instant.full_rate_age_by_birthdate[birthdate]
# with pytest.raises(ValueError) as error:
# parameter_at_instant.full_rate_age_by_birthdate[birthdate]
# assert "Cannot use fancy indexing on parameter node '.full_rate_age.full_rate_age_by_birthdate'" in get_message(error.value)
135 changes: 135 additions & 0 deletions tests/core/parameters_fancy_indexing/coefficient_de_minoration.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
description: Coefficient de minoration ARRCO
coefficient_minoration_en_fonction_distance_age_annulation_decote_en_annee:
description: Coefficient de minoration à l'Arrco en fonction de la distance à l'âge d'annulation de la décote (en année)
'-10':
description: '-10'
values:
1965-01-01:
value: 0.43
1957-05-15:
value: null
'-9':
description: '-9'
values:
1965-01-01:
value: 0.5
1957-05-15:
value: null
'-8':
description: '-8'
values:
1965-01-01:
value: 0.57
1957-05-15:
value: null
'-7':
description: '-7'
values:
1965-01-01:
value: 0.64
1957-05-15:
value: null
'-6':
description: '-6'
values:
1965-01-01:
value: 0.71
1957-05-15:
value: null
'-5':
description: '-5'
values:
1965-01-01:
value: 0.78
1957-05-15:
value: 0.75
'-4':
description: '-4'
values:
1965-01-01:
value: 0.83
1957-05-15:
value: 0.8
'-3':
description: '-3'
values:
1965-01-01:
value: 0.88
1957-05-15:
value: 0.85
'-2':
description: '-2'
values:
1965-01-01:
value: 0.92
1957-05-15:
value: 0.9
'-1':
description: '-1'
values:
1965-01-01:
value: 0.96
1957-05-15:
value: 0.95
'0':
description: '0'
values:
1965-01-01:
value: 1.0
1957-05-15:
value: 1.05
'1':
description: '1'
values:
1965-01-01:
value: null
1957-05-15:
value: 1.1
'2':
description: '2'
values:
1965-01-01:
value: null
1957-05-15:
value: 1.15
'3':
description: '3'
values:
1965-01-01:
value: null
1957-05-15:
value: 1.2
'4':
description: '4'
values:
1965-01-01:
value: null
1957-05-15:
value: 1.25
metadata:
order:
- '-10'
- '-9'
- '-8'
- '-7'
- '-6'
- '-5'
- '-4'
- '-3'
- '-2'
- '-1'
- '0'
- '1'
- '2'
- '3'
- '4'
metadata:
order:
- coefficient_minoration_en_fonction_distance_age_annulation_decote_en_annee
reference:
1965-01-01: Article 18 de l'annexe A de l'Accord national interprofessionnel de retraite complémentaire du 8 décembre 1961
1957-05-15: Accord du 15/05/1957 pour la création de l'UNIRS
description_en: Penalty for early retirement ARRCO
documentation: |
Note: Le coefficient d'abattement (ou de majoration avant 1965) constitue une multiplication des droits de pension à l'arrco par le coefficient en question. Par exemple, un individu partant en retraite à 60 ans en 1960 touchait 75% de sa pension. A partir de 1983, une double condition d'âge et de durée d'assurance est instaurée: un individu ayant validé une durée égale à la durée d'assurance cible(voir onglet Trim_tx_plein_RG) partira sans abbattement, même s'il n'a pas atteint l'âge d'annulation de la décôte dans le régime général (voir onglet Age_ann_dec_RG).
Note : le coefficient de minoration est linéaire en nombre de trimestres, e.g. il est de 0,43 à AAD - 10 ans, de 0,4475 à AAD - 9 ans et 3 trimestres, de 0,465 à AAD - 9 ans et 2 trimestres, etc.

0 comments on commit 8c6bc57

Please sign in to comment.