Skip to content

Budget Allocation Functions

Budget allocation functions distribute a fixed cumulative emission budget among countries in a given allocation year.

Overview

All budget allocation approaches return a BudgetAllocationResult containing:

  • approach: Name of the allocation approach used
  • parameters: Dictionary of parameters used in the calculation
  • relative_shares_cumulative_emission: DataFrame of budget shares (sum to 1.0)

Per Capita Budgets

equal_per_capita_budget

fair_shares.library.allocations.budgets.per_capita.equal_per_capita_budget

Python
equal_per_capita_budget(
    population_ts: TimeseriesDataFrame,
    allocation_year: int,
    emission_category: str,
    preserve_allocation_year_shares: bool = False,
    group_level: str = "iso3c",
    unit_level: str = "unit",
    ur: PlainRegistry = get_default_unit_registry(),
) -> BudgetAllocationResult

Equal per capita budget allocation for cumulative emissions.

This function generates cumulative shares for the allocation year based on equal per capita principles.

Mathematical Foundation

Two allocation modes are supported:

Mode 1: Dynamic shares (preserve_allocation_year_shares=False, default)

Population shares are calculated using cumulative population from allocation_year onwards. This accounts for changes in relative population shares over time:

\[ A(g) = \frac{\sum_{t \geq t_a} P(g, t)}{\sum_{g} \sum_{t \geq t_a} P(g, t)} \]

Where:

  • \(A(g)\): Budget share allocated to country \(g\)
  • \(P(g, t)\): Population of country \(g\) in year \(t\)
  • \(t_a\): Allocation year
  • \(\sum_{t \geq t_a} P(g, t)\): Cumulative population of country \(g\) from allocation year onwards
  • \(\sum_{g} \sum_{t \geq t_a} P(g, t)\): Total cumulative population across all countries from allocation year onwards

Mode 2: Preserved shares (preserve_allocation_year_shares=True)

Population shares calculated at the allocation year are preserved. This means the relative allocation between groups remains constant:

\[ A(g) = \frac{P(g, t_a)}{\sum_{g} P(g, t_a)} \]

Where:

  • \(A(g)\): Budget share allocated to country \(g\)
  • \(P(g, t_a)\): Population of country \(g\) at allocation year \(t_a\)
  • \(\sum_{g} P(g, t_a)\): Total world population at allocation year

Parameters:

Name Type Description Default
population_ts TimeseriesDataFrame

Timeseries of population for each group of interest

required
allocation_year int

Year from which to start calculating allocations and budgets. See docs/science/parameter-effects.md#allocation_year for how this affects country shares

required
emission_category str

Emission category to include in the output

required
preserve_allocation_year_shares bool

If False (default), shares are calculated using cumulative population from allocation_year onwards. If True, shares calculated at allocation_year are preserved

False
group_level str

Level in the index which specifies group information

'iso3c'
unit_level str

Level in the index which specifies the unit of each timeseries

'unit'
ur PlainRegistry

The unit registry to use for calculations

get_default_unit_registry()

Returns:

Type Description
BudgetAllocationResult

Container with relative shares for cumulative emissions budget allocation. The TimeseriesDataFrame contains only the allocation_year column with population shares that sum to 1 across groups for the specified emission category.

Notes

Theoretical grounding:

See docs/science/allocations.md#equal-per-capita for detailed mathematical formulation, limitations, and when to use this approach.

For translating the egalitarian tradition (which grounds the equal per capita principle) into code, see docs/science/principle-to-code.md#egalitarianism for implementation guidance.

Examples:

Calculate equal per capita budget allocation for 2020:

Python Console Session
>>> from fair_shares.library.utils import create_example_data
>>> data = create_example_data()
>>> result = equal_per_capita_budget(
...     population_ts=data["population"],
...     allocation_year=2020,
...     emission_category="co2-ffi",
... )
Converting units...
>>> result.approach
'equal-per-capita-budget'
>>> # Shares are proportional to population
>>> shares = result.relative_shares_cumulative_emission
>>> bool(abs(shares["2020"].sum() - 1.0) < 1e-10)  # Should sum to 1.0
True

Using preserve_allocation_year_shares to fix shares at allocation year:

Python Console Session
>>> result_preserved = equal_per_capita_budget(
...     population_ts=data["population"],
...     allocation_year=2020,
...     emission_category="co2-ffi",
...     preserve_allocation_year_shares=True,
... )
Converting units...
>>> # Shares are based only on 2020 population, not cumulative from 2020 onwards
>>> result_preserved.parameters["preserve_allocation_year_shares"]
True

per_capita_adjusted_budget

fair_shares.library.allocations.budgets.per_capita.per_capita_adjusted_budget

Python
per_capita_adjusted_budget(
    population_ts: TimeseriesDataFrame,
    allocation_year: int,
    emission_category: str,
    country_actual_emissions_ts: (
        TimeseriesDataFrame | None
    ) = None,
    gdp_ts: TimeseriesDataFrame | None = None,
    pre_allocation_responsibility_weight: float = 0.0,
    capability_weight: float = 0.0,
    pre_allocation_responsibility_year: int = 1990,
    pre_allocation_responsibility_per_capita: bool = True,
    pre_allocation_responsibility_exponent: float = 1.0,
    pre_allocation_responsibility_functional_form: str = "asinh",
    capability_per_capita: bool = True,
    capability_exponent: float = 1.0,
    capability_functional_form: str = "asinh",
    max_deviation_sigma: float | None = 2.0,
    preserve_allocation_year_shares: bool = False,
    historical_discount_rate: float = 0.0,
    group_level: str = "iso3c",
    unit_level: str = "unit",
    ur: PlainRegistry = get_default_unit_registry(),
) -> BudgetAllocationResult

Per capita budget allocation with pre-allocation responsibility and capability adjustments.

This function generates cumulative shares for the allocation year based on adjusted per capita principles, incorporating pre-allocation responsibility and economic capability adjustments (but without Gini correction).

Mathematical Foundation

The per capita adjusted budget allocation adjusts for pre-allocation responsibility and economic capability using the following approach.

Core Allocation Formula

For budget allocation with dynamic shares (default mode):

\[ A(g) = \frac{\sum_{t \geq t_a} R(g) \times C(g, t) \times P(g, t)}{\sum_g \sum_{t \geq t_a} R(g) \times C(g, t) \times P(g, t)} \]

Where:

  • \(A(g)\): Budget share allocated to country \(g\)
  • \(R(g)\): Responsibility adjustment factor for country \(g\) (constant over time, equals 1.0 if not used)
  • \(C(g, t)\): Capability adjustment factor for country \(g\) in year \(t\) (equals 1.0 if not used)
  • \(P(g, t)\): Population of country \(g\) in year \(t\)
  • \(t_a\): Allocation year

Responsibility Adjustment

Historical emissions reduce future allocation rights.

For per capita responsibility (:code:pre_allocation_responsibility_per_capita=True, default):

\[ R(g) = \left(\frac{\sum_{t=t_h}^{t_a-1} E(g, t)}{\sum_{t=t_h}^{t_a-1} P(g, t)}\right)^{-w_r \times e_r} \]

Where:

  • \(R(g)\): Responsibility adjustment factor (inverse - higher emissions = lower allocation)
  • \(E(g, t)\): Emissions of country \(g\) in year \(t\)
  • \(t_h\): Historical responsibility start year
  • \(t_a\): Allocation year
  • \(w_r\): Normalized responsibility weight
  • \(e_r\): Responsibility exponent

For absolute responsibility (:code:pre_allocation_responsibility_per_capita=False):

\[ R(g) = \left(\sum_{t=t_h}^{t_a-1} E(g, t)\right)^{-w_r \times e_r} \]

Capability Adjustment

Economic capacity reduces allocation rights for wealthier countries.

For per capita capability (:code:capability_per_capita=True, default):

\[ C(g, t) = \left(\frac{\text{GDP}(g, t)}{P(g, t)}\right)^{-w_c \times e_c} \]

Where:

  • \(C(g, t)\): Capability adjustment factor (inverse - higher GDP per capita = lower allocation)
  • \(\text{GDP}(g, t)\): Gross domestic product of country \(g\) in year \(t\)
  • \(w_c\): Normalized capability weight
  • \(e_c\): Capability exponent

For absolute capability (:code:capability_per_capita=False):

\[ C(g, t) = \text{GDP}(g, t)^{-w_c \times e_c} \]

Two allocation modes are supported based on :code:preserve_allocation_year_shares:

  • False (default): Uses cumulative adjusted population from allocation_year onwards
  • True: Uses adjusted population at allocation_year only

Parameters:

Name Type Description Default
population_ts TimeseriesDataFrame

Timeseries of population for each group of interest

required
allocation_year int

Year from which to start calculating allocations and budgets. See docs/science/parameter-effects.md#allocation_year for how this affects country shares

required
emission_category str

Emission category to include in the output

required
country_actual_emissions_ts TimeseriesDataFrame | None

Historical emissions data (required if pre_allocation_responsibility_weight > 0)

None
gdp_ts TimeseriesDataFrame | None

GDP data (required if capability_weight > 0)

None
pre_allocation_responsibility_weight float

Weight for historical responsibility adjustment (0.0 to 1.0). See docs/science/parameter-effects.md#pre_allocation_responsibility_weight for real allocation examples showing how this affects country shares

0.0
capability_weight float

Weight for economic capability adjustment (0.0 to 1.0). See docs/science/parameter-effects.md#capability_weight for real allocation examples showing how this affects country shares

0.0
pre_allocation_responsibility_year int

Start year for calculating historical responsibility (default: 1990)

1990
pre_allocation_responsibility_per_capita bool

If True, use per capita emissions; if False, use absolute emissions

True
pre_allocation_responsibility_exponent float

Exponent for the responsibility adjustment function

1.0
pre_allocation_responsibility_functional_form str

Functional form for responsibility: "asinh" or "power"

'asinh'
capability_exponent float

Exponent for the capability adjustment function

1.0
capability_functional_form str

Functional form for capability: "asinh" or "power"

'asinh'
max_deviation_sigma float | None

Maximum allowed deviation from equal per capita in standard deviations. Constrains allocations to remain within a statistically reasonable range of the equal per capita baseline, preventing extreme adjustments. If None, no constraint is applied

2.0
preserve_allocation_year_shares bool

If False (default), shares are calculated using cumulative adjusted population from allocation_year onwards. If True, shares calculated at allocation_year are preserved

False
historical_discount_rate float

Discount rate for historical emissions (0.0 to <1.0). When > 0, earlier emissions are weighted less via (1 - rate)^(reference_year - t). Implements natural CO2 removal rationale (Dekker Eq. 5). Default: 0.0 (no discounting).

0.0
group_level str

Level in the index which specifies group information

'iso3c'
unit_level str

Level in the index which specifies the unit of each timeseries

'unit'
ur PlainRegistry

The unit registry to use for calculations

get_default_unit_registry()

Returns:

Type Description
BudgetAllocationResult

Container with relative shares for cumulative emissions budget allocation. The TimeseriesDataFrame contains only the allocation_year column with adjusted population shares that sum to 1 across groups for the specified emission category.

Notes

Theoretical grounding:

See docs/science/allocations.md#per-capita-adjusted for detailed mathematical formulation, parameter considerations, and CBDR-RC alignment.

For translating equity principles into code, see:

  • docs/science/principle-to-code.md#historical-responsibility-polluter-pays for responsibility weight implementation
  • docs/science/principle-to-code.md#capability-ability-to-pay for capability weight implementation
  • docs/science/principle-to-code.md#cbdr-rc for combining both principles

Examples:

Calculate allocation with both responsibility and capability adjustments:

Python Console Session
>>> from fair_shares.library.utils import create_example_data
>>> data = create_example_data()
>>> result = per_capita_adjusted_budget(
...     population_ts=data["population"],
...     allocation_year=2030,
...     emission_category="co2-ffi",
...     country_actual_emissions_ts=data["emissions"],
...     gdp_ts=data["gdp"],
...     pre_allocation_responsibility_weight=0.5,
...     capability_weight=0.5,
...     pre_allocation_responsibility_year=2020,
... )
Converting units...
>>> result.approach
'per-capita-adjusted-budget'
>>> # Shares sum to 1.0
>>> shares = result.relative_shares_cumulative_emission
>>> bool(abs(shares["2030"].sum() - 1.0) < 1e-10)
True
>>> # Parameters include normalized weights
>>> result.parameters["pre_allocation_responsibility_weight"]
0.5...
>>> result.parameters["capability_weight"]
0.5...

Using only responsibility adjustment (no capability):

Python Console Session
>>> result_resp_only = per_capita_adjusted_budget(
...     population_ts=data["population"],
...     allocation_year=2030,
...     emission_category="co2-ffi",
...     country_actual_emissions_ts=data["emissions"],
...     pre_allocation_responsibility_weight=1.0,
...     capability_weight=0.0,
...     pre_allocation_responsibility_year=2020,
... )
Converting units...
>>> # Countries with higher historical emissions get lower allocations
>>> result_resp_only.approach
'per-capita-adjusted-budget'
>>> result_resp_only.parameters["pre_allocation_responsibility_weight"]
1.0...
>>> result_resp_only.parameters["capability_weight"]
0.0...

per_capita_adjusted_gini_budget

fair_shares.library.allocations.budgets.per_capita.per_capita_adjusted_gini_budget

Python
per_capita_adjusted_gini_budget(
    population_ts: TimeseriesDataFrame,
    gdp_ts: TimeseriesDataFrame,
    gini_s: DataFrame,
    allocation_year: int,
    emission_category: str,
    country_actual_emissions_ts: (
        TimeseriesDataFrame | None
    ) = None,
    pre_allocation_responsibility_weight: float = 0.0,
    capability_weight: float = 1.0,
    pre_allocation_responsibility_year: int = 1990,
    pre_allocation_responsibility_per_capita: bool = True,
    pre_allocation_responsibility_exponent: float = 1.0,
    pre_allocation_responsibility_functional_form: str = "asinh",
    capability_per_capita: bool = True,
    capability_exponent: float = 1.0,
    capability_functional_form: str = "asinh",
    income_floor: float = 0.0,
    max_gini_adjustment: float = 0.8,
    max_deviation_sigma: float | None = 2.0,
    preserve_allocation_year_shares: bool = False,
    historical_discount_rate: float = 0.0,
    group_level: str = "iso3c",
    unit_level: str = "unit",
    ur: PlainRegistry = get_default_unit_registry(),
) -> BudgetAllocationResult

Per capita budget allocation with pre-allocation responsibility, capability, and Gini adjustments.

This function generates cumulative shares for the allocation year based on adjusted per capita principles, incorporating pre-allocation responsibility, Gini-corrected GDP capability adjustments, and inequality considerations.

Mathematical Foundation

The Gini-adjusted budget allocation extends the per capita adjusted approach by incorporating income inequality within countries.

Core Allocation Formula

For budget allocation with dynamic shares (default mode):

\[ A(g) = \frac{\sum_{t \geq t_a} R(g) \times C_{\text{Gini}}(g, t) \times P(g, t)}{\sum_g \sum_{t \geq t_a} R(g) \times C_{\text{Gini}}(g, t) \times P(g, t)} \]

Where:

  • \(A(g)\): Budget share allocated to country \(g\)
  • \(R(g)\): Responsibility adjustment factor (equals 1.0 if not used)
  • \(C_{\text{Gini}}(g, t)\): Gini-adjusted capability factor (equals 1.0 if not used)
  • \(P(g, t)\): Population of country \(g\) in year \(t\)
  • \(t_a\): Allocation year

Gini Adjustment Process

GDP is adjusted using an interpretation of the Greenhouse Development Rights (GDR) framework's capability metric (note: GDR was designed for burden-sharing; fair-shares adapts its capability calculation for entitlement allocation). Only income above a development threshold counts as capability. When combined with the income floor, higher inequality means more national income sits above the threshold — increasing measured capability. See :func:~fair_shares.library.utils.math.allocation.calculate_gini_adjusted_gdp for the full mathematical derivation.

Responsibility Adjustment

Identical to per capita adjusted budget (see that function for details).

For per capita responsibility (:code:pre_allocation_responsibility_per_capita=True, default):

\[ R(g) = \left(\frac{\sum_{t=t_h}^{t_a-1} E(g, t)}{\sum_{t=t_h}^{t_a-1} P(g, t)}\right)^{-w_r \times e_r} \]

Where:

  • \(E(g, t)\): Emissions of country \(g\) in year \(t\)
  • \(t_h\): Historical responsibility start year
  • \(t_a\): Allocation year
  • \(w_r\): Normalized responsibility weight
  • \(e_r\): Responsibility exponent

Capability Adjustment with Gini-Adjusted GDP

For per capita capability (:code:capability_per_capita=True, default):

\[ C_{\text{Gini}}(g, t) = \left(\frac{\text{GDP}^{\text{adj}}(g, t)}{P(g, t)}\right)^{-w_c \times e_c} \]

Where:

  • \(C_{\text{Gini}}(g, t)\): Gini-adjusted capability factor (inverse - higher adjusted GDP = lower allocation)
  • \(\text{GDP}^{\text{adj}}(g, t)\): Gini-adjusted GDP (see :func:~fair_shares.library.utils.math.allocation.calculate_gini_adjusted_gdp)
  • \(w_c\): Normalized capability weight
  • \(e_c\): Capability exponent

When combined with the income floor, higher inequality means more income above the development threshold, giving high-inequality countries smaller emission allocations than unadjusted GDP would suggest.

Two allocation modes are supported based on :code:preserve_allocation_year_shares:

  • False (default): Uses cumulative adjusted population from allocation_year onwards
  • True: Uses adjusted population at allocation_year only

Parameters:

Name Type Description Default
population_ts TimeseriesDataFrame

Timeseries of population for each group of interest

required
gdp_ts TimeseriesDataFrame

Timeseries of GDP for each group of interest (required)

required
gini_s DataFrame

DataFrame containing Gini coefficient data for each group (required)

required
allocation_year int

Year from which to start calculating allocations and budgets. See docs/science/parameter-effects.md#allocation_year for how this affects country shares

required
emission_category str

Emission category to include in the output

required
country_actual_emissions_ts TimeseriesDataFrame | None

Historical emissions data (required if pre_allocation_responsibility_weight > 0)

None
pre_allocation_responsibility_weight float

Weight for historical responsibility adjustment (0.0 to 1.0). See docs/science/parameter-effects.md#pre_allocation_responsibility_weight for real allocation examples showing how this affects country shares

0.0
capability_weight float

Weight for economic capability adjustment (0.0 to 1.0, default 1.0)

1.0
pre_allocation_responsibility_year int

Start year for calculating historical responsibility (default: 1990)

1990
pre_allocation_responsibility_per_capita bool

If True, use per capita emissions; if False, use absolute emissions

True
pre_allocation_responsibility_exponent float

Exponent for the responsibility adjustment function

1.0
pre_allocation_responsibility_functional_form str

Functional form for responsibility: "asinh" or "power"

'asinh'
capability_exponent float

Exponent for the capability adjustment function

1.0
capability_functional_form str

Functional form for capability: "asinh" or "power"

'asinh'
income_floor float

Income floor for Gini adjustment (in USD PPP per capita). Income below this threshold is excluded from capability calculations, adapted from the Greenhouse Development Rights (GDR) development threshold [Baer 2013] (GDR was designed for burden-sharing; fair-shares uses its capability metric in an entitlement allocation context). See docs/science/parameter-effects.md#income_floor for real allocation examples showing how this affects country shares

0.0
max_gini_adjustment float

Maximum allowed Gini adjustment factor

0.8
max_deviation_sigma float | None

Maximum allowed deviation from equal per capita in standard deviations. Constrains allocations to remain within a statistically reasonable range of the equal per capita baseline, preventing extreme adjustments. If None, no constraint is applied

2.0
preserve_allocation_year_shares bool

If False (default), shares are calculated using cumulative adjusted population from allocation_year onwards. If True, shares calculated at allocation_year are preserved

False
historical_discount_rate float

Discount rate for historical emissions (0.0 to <1.0). When > 0, earlier emissions are weighted less via (1 - rate)^(reference_year - t). Implements natural CO2 removal rationale (Dekker Eq. 5). Default: 0.0 (no discounting).

0.0
group_level str

Level in the index which specifies group information

'iso3c'
unit_level str

Level in the index which specifies the unit of each timeseries

'unit'
ur PlainRegistry

The unit registry to use for calculations

get_default_unit_registry()

Returns:

Type Description
BudgetAllocationResult

Container with relative shares for cumulative emissions budget allocation. The TimeseriesDataFrame contains only the allocation_year column with Gini-adjusted capability-weighted population shares that sum to 1 across groups for the specified emission category.

Notes

Theoretical grounding:

See docs/science/allocations.md#gini-adjusted for detailed mathematical formulation, intra-national equity considerations, and when to use this approach.

For translating equity principles into code, see:

  • docs/science/principle-to-code.md#subsistence-protection for income floor and Gini adjustment implementation
  • docs/science/principle-to-code.md#cbdr-rc for combining with pre-allocation responsibility and capability

Examples:

Calculate allocation with Gini-adjusted capability (no responsibility):

Python Console Session
>>> from fair_shares.library.utils import create_example_data
>>> data = create_example_data()
>>> result = per_capita_adjusted_gini_budget(
...     population_ts=data["population"],
...     gdp_ts=data["gdp"],
...     gini_s=data["gini"],
...     allocation_year=2030,
...     emission_category="co2-ffi",
...     pre_allocation_responsibility_weight=0.0,
...     capability_weight=1.0,
... )
Converting units...
>>> result.approach
'per-capita-adjusted-gini-budget'
>>> # Shares are adjusted for inequality in addition to GDP
>>> shares = result.relative_shares_cumulative_emission
>>> bool(abs(shares["2030"].sum() - 1.0) < 1e-10)  # Should sum to 1.0
True
>>> # Gini parameters are stored in result
>>> result.parameters["income_floor"]
0.0...
>>> result.parameters["max_gini_adjustment"]
0.8...

Calculate allocation with both responsibility and Gini-adjusted capability:

Python Console Session
>>> result_full = per_capita_adjusted_gini_budget(
...     population_ts=data["population"],
...     gdp_ts=data["gdp"],
...     gini_s=data["gini"],
...     allocation_year=2030,
...     emission_category="co2-ffi",
...     country_actual_emissions_ts=data["emissions"],
...     pre_allocation_responsibility_weight=0.5,
...     capability_weight=0.5,
...     pre_allocation_responsibility_year=2020,
... )
Converting units...
>>> result_full.approach
'per-capita-adjusted-gini-budget'
>>> # Both adjustments are reflected in parameters
>>> result_full.parameters["pre_allocation_responsibility_weight"]
0.5...
>>> result_full.parameters["capability_weight"]
0.5...
>>> # With income floor, high inequality means more income above threshold
>>> shares_full = result_full.relative_shares_cumulative_emission
>>> bool(abs(shares_full["2030"].sum() - 1.0) < 1e-10)
True

See Also