iza-institute-of-labor-economics / gettsim

The GErman Taxes and Transfers SIMulator
https://gettsim.readthedocs.io/
GNU Affero General Public License v3.0
54 stars 32 forks source link

Vertrauensschutz in Rente für Arbeitslose #645

Closed TeBackh closed 10 months ago

TeBackh commented 1 year ago

Special age thresholds for people with legitimate expectations during the phase-in of tightened eligibility requirements. Lots of additional improvements that popped up along the way.

codecov[bot] commented 1 year ago

Codecov Report

All modified and coverable lines are covered by tests :white_check_mark:

Comparison is base (922aae7) 91.02% compared to head (f6986bb) 91.31%.

Additional details and impacted files ```diff @@ Coverage Diff @@ ## main #645 +/- ## ========================================== + Coverage 91.02% 91.31% +0.29% ========================================== Files 48 48 Lines 3143 3225 +82 ========================================== + Hits 2861 2945 +84 + Misses 282 280 -2 ```

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

MImmesberger commented 10 months ago

When working on the Vertrauensschutz, I noticed that some rules regarding the statutory retirement ages of Arbeitslose are not implemented yet.

Currently, we mostly use piecewise linear functions. Now I have a reform where a piecewise linear function would have more than 40 segments, so it is both cumbersome to write and difficult to understand in the end. Currently I use the implementation below. But this has the downside that we need a new policy function even though only parameters changed. Any advice? I am leaning towards the piecewise linear function.

  1992-01-01:
    reference: Rentenreformgesetz 1992. BGBl. I S. 2261 1989 § 41
    note: Increase of full retirement age from 60 to 65 for birth cohort 1941-1952.
    [.....]
    1951:
      0: 64.083333
      2: 64.166667
      4: 64.25
      6: 64.333333
      8: 64.416667
      10: 64.5
    1952:
      0: 64.583333
      2: 64.666667
      4: 64.75
      6: 64.833333
      8: 64.916667
      10: 65
    1953:
      scalar: 65
  1997-01-01:
    reference: Wachstums- und Beschäftigungsförderungsgesetz 1996. BGBl. I S. 1461 1996
    note: Increase of full retirement age from 60 to 65 for birth cohort 1937-1941.
    0:
      lower_threshold: -inf
      upper_threshold: 1936.916666666
      rate_linear: 0
      intercept_at_lower_threshold: 60
    1:
      upper_threshold: 1941.916666666
      rate_linear: 1
    2:
      upper_threshold: inf
      rate_linear: 0
hmgaudecker commented 10 months ago

I don't quite follow. Why do we need a new policy function? In general, writing out the parameters is much better IMHO, even if it becomes lengthy. piecewise_linear is really made for individual-level stuff like the tax code, not for converting aggregate parameters. Of course it can be used for that purpose, too -- but it typically becomes very hard to read.

If the answer to Why do we need a new policy function? is Because of the second part for the 1937-1941 cohorts, better convert that to direct parameters, too.

MImmesberger commented 10 months ago

If the answer to Why do we need a new policy function? is Because of the second part for the 1937-1941 cohorts, better convert that to direct parameters, too.

Yes, exactly!

MImmesberger commented 10 months ago

In the last commit I rewrote the functions and parameter inputs for the Rente wg. Arbeitslosigkeit and implemented the Vertrauensschutz rules for 1997 and 2006.

When working on it, I noticed that the former implementation was not quite correct because increases in statutory retirement ages after the abolishment of the Rente wg. Arbeitslosigkeit were also applied there. I guess this is an artifact of an older version of GETTSIM.

This is why tests are currently failing. For example, in test_data/renten_alter/2010/hh_id_769.yaml a retirement age of 67 for the Rente wg. Arbeitslosigkeit is the expected output. AFAIK, the full retirement age was 65 when the Rente wg. Arbeitslosigkeit was abolished.

Long story short: We probably have to update the test data.

Edit: The Rente für Frauen also needs a major overhaul. Same problems as with Rente wg. Arbeitslosigkeit and also some Vertrauensschutz rules. But implementation should be very similar to this one here.

MImmesberger commented 10 months ago

ToDo:

MImmesberger commented 10 months ago

In case you are confused by the recent changes: Apparently they first accelerated the FRA increase (in July 1996) while the ERA increased as before (in 1992). Then a few months later (September 1996), they abolished the increase in the ERA but kept the acceleration in the FRA from July 1996.

MImmesberger commented 10 months ago

I added some tests for the Rente wg. Arbeitslosigkeit. Those tests are made up using the texts of the relevant laws.

I have one problem that I'm not able to solve: Some tests fail because of a pandas error: ValueError: If using all scalar values, you must pass an index.

All of the failed tests seem to address functions that just return a parameter from the params dictionary, i.e.

def func(params):
  return params["some_param"]

Other than that, the PR is ready to be reviewed.

hmgaudecker commented 10 months ago

Thanks!!!

I have one problem that I'm not able to solve: Some tests fail because of a pandas error: ValueError: If using all scalar values, you must pass an index.

All of the failed tests seem to address functions that just return a parameter from the params dictionary, i.e.

def func(params):
  return params["some_param"]

So the problem is that for whatever reason, this implies that instead of something like this:

{'entgeltp_update': array([31.0625])}

the following arrives in line 738 of interface.py:

{'ges_rente_arbeitsl_vorzeitig': array(60.)}

I don't quite see why that happens as the outputs of functions look the same (just a scalar). @lars-reimann, would you mind having a quick look?

In any case, we'll just need some workaround and truly fix it when looking seriously at the interface.

lars-reimann commented 10 months ago

Hmm, the tests fail for functions that only depend on ges_rente_params:

@dates_active(end="1991-12-31", change_name="ges_rente_arbeitsl_vorzeitig")
def _ges_rente_arbeitsl_vorzeitig_ohne_staffelung(
    ges_rente_params: dict
):
   ...

Adding any other dependency resolves the issue:

@dates_active(end="1991-12-31", change_name="ges_rente_arbeitsl_vorzeitig")
def _ges_rente_arbeitsl_vorzeitig_ohne_staffelung(
        ges_rente_params: dict,
        geburtsjahr: int,
):
   ...

I didn't figure out why that happens yet, though.

hmgaudecker commented 10 months ago

Ahh, sure, the params are partialed in beforehand, so something weird must be happening when doing the calculations via the DAG.

Just add a fake dependency, corresponding # noqa: XXX statements, and an issue so as not to forget about it when re-doing the interface.

MImmesberger commented 10 months ago

Ah, thanks @lars-reimann @hmgaudecker. It worked!

hmgaudecker commented 10 months ago

I added some tests for the Rente wg. Arbeitslosigkeit.

Cool. Only thing is that for new tests, can you please call the file for what is being tested instead of test_hh_id_[x].yaml? That was a leftover of the bulk conversion of csv-formatted tests to individuals / households.

E.g., I am just looking at the 2007 change. So there could be tests (making up the year here):

MImmesberger commented 10 months ago

Thank you for the comments! Will keep those in mind for future PRs. I implemented the changes or replied to your concerns.