Piecewise Linear Budget Constraints

This generates a complete two-dimensional budget constraints for some unit (person, benefit-unit, household, etc.) for some tax-benefit system. That is, a list points describing the combinations of net income that the unit would get for different values of gross income (or hours worked, wages, etc.).

See: Duncan, Alan, and Graham Stark. "A Recursive Algorithm to Generate Piecewise Linear Budget Contraints" IFS Working Paper 2000/01 May 2, 2000] https://doi.org/10.1920/wp.ifs.2000.0011.

Here is a live example of this algorithm in action.

Usage

Define a function that returns the net income for some gross value - this could be (e.g.) hours worked, wage, or gross income, and some set of data (details of a person, tax paramters, etc):

   function getnet( data::Dict, gross :: Real ) :: Real

The call to makebc then generates the budget constraint using getnet. If successful this returns a BudgetConstraint array, which is a collection of x,y points describing all the points where the budget constraint has a change of slope, where x is the gross value and y the net.

The routine is controlled by a BCSettings struct; there is a DEFAULT_SETTINGS constant version of this which I suggest you don't change, apart from perhaps the upper and lower x-bounds of the graph.

Functions and Data Structures

BudgetConstraints.annotate_bcMethod

This takes a budget constraint and produces a named tuple of METRs and Tax Credits for each one. (really just 1 minus the slope and the intercept at that point). Useful for annotating graphs and tables.

BudgetConstraints.censorFunction

Attempt to remove near duplicate points and ensure all points ordered in ascending gross income.

BudgetConstraints.makebcFunction

Make a budget constraint using function getnet to extract net incomes and settings (see above on this struct). data should hold whatever your getnet function needs (parameters, a househols, etc.) getnet should be a function of the form net=f(data, gross). See the testcase for an example.

Problems/TODO

  • the tolerance isn't used consistently (see nearlysameline);
  • I may be misunderstanding abstract types in the declarations;
  • possibly use some definition of point, line, etc. from some standard package.