Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/salesforce/ai-economist/llms.txt

Use this file to discover all available pages before exploring further.

The redistribution.py module contains two components that handle fiscal policy in Foundation simulations: WealthRedistribution for simple equal redistribution, and PeriodicBracketTax for a full-featured bracket tax system with multiple policy models. The file also defines a related helper component SimpleLabor (in simple_labor.py) covered at the end of this page.
Both redistribution components should always be placed last in the component order so they operate on finalized agent inventories for each timestep.

WealthRedistribution

Class name: WealthRedistribution — registry name "WealthRedistribution". A passive component that redistributes the total coin endowment of all mobile agents as evenly as possible at every timestep. It adds no actions and no observations.

How it works

On each component_step():
  1. Sums the inventory and escrow coin across all agents: tc = sum(inventory_coin + escrow_coin).
  2. Computes the equal target share: target = tc / n_agents.
  3. Sets each agent’s inventory coin to target - agent_escrow_coin.
Required world entities: Coin.

PeriodicBracketTax

Class name: PeriodicBracketTax — registry name "PeriodicBracketTax", component type "PeriodicTax". Periodically collects income taxes from agents using a configurable marginal bracket schedule and redistributes the total tax revenue as an equal lump-sum payment to all agents. Supports four tax policy models including a learned planner, US federal rates, the Saez optimal formula, and user-supplied fixed rates. Required world entities: Coin. Applies to both BasicMobileAgent and BasicPlanner.

Constructor parameters

disable_taxes
boolean
default:"false"
When True, forces all tax rates to 0 while preserving the full observation space. Useful for controlled no-tax baseline comparisons.
tax_model
string
default:"model_wrapper"
Which policy determines tax rates each period.
ValueDescription
"model_wrapper"Tax rates set by the planner agent’s actions
"saez"Rates computed from the Saez (2001) optimal taxation formula
"us-federal-single-filer-2018-scaled"Scaled US federal 2018 single-filer rates
"fixed-bracket-rates"Rates supplied in fixed_bracket_rates
period
int
default:"100"
Length of one tax period in environment timesteps. Taxes are updated at the start and collected at the end of each period. Must be > 0.
rate_min
float
default:"0.0"
Minimum allowable marginal tax rate for any bracket. Must be >= 0.
rate_max
float
default:"1.0"
Maximum allowable marginal tax rate for any bracket. Must be <= 1.
rate_disc
float
default:"0.05"
Step size between discrete rate options available to the planner. Only applies when tax_model == "model_wrapper". Must be > 0 and < 1. A value of 0.05 gives rate choices [0.0, 0.05, 0.10, ..., 1.0].
n_brackets
int
default:"5"
Number of tax brackets. Must be >= 2. Ignored when bracket_spacing == "us-federal" (which always uses 7 brackets).
top_bracket_cutoff
float
default:"100"
Income level (in coin) at the left edge of the top bracket. Must be >= 10. Ignored for "us-federal" bracket spacing.
usd_scaling
float
default:"1000.0"
Divisor applied to US federal bracket cutoffs when bracket_spacing == "us-federal". Must be > 0.
bracket_spacing
string
default:"us-federal"
How bracket cutoff incomes are spaced.
ValueDescription
"us-federal"Uses scaled 2018 US federal cutoffs (7 brackets, ignores n_brackets and top_bracket_cutoff)
"linear"Linearly spaced from 0 to top_bracket_cutoff
"log"Logarithmically spaced from 0 to top_bracket_cutoff
fixed_bracket_rates
list
Required when tax_model == "fixed-bracket-rates". A list of fixed marginal rates, one per bracket. All values must be in [0, 1] and the list length must equal the number of brackets.
pareto_weight_type
string
default:"inverse_income"
Pareto welfare weights used in the Saez formula. Only applies when tax_model == "saez".
ValueWeight
"inverse_income"1 / max(1, income)
"uniform"1 for all agents
saez_fixed_elas
float
If provided, uses this fixed elasticity value in the Saez formula instead of estimating it empirically via OLS regression. Must be >= 0. Only applies when tax_model == "saez".
tax_annealing_schedule
list
A two-element list [warmup_steps, slope] defining a tax annealing schedule. During warmup, the maximum tax rate is gradually increased from 0 to rate_max. Default is no annealing.

Tax period cycle

Each timestep component_step() advances a cycle counter:
  • First day of a new period (tax_cycle_pos == 1): New tax rates are computed and applied according to the chosen tax_model.
  • Last day of the period (tax_cycle_pos >= period): enact_taxes() is called, which:
    1. Computes each agent’s income for the period as current_total_endowment - last_period_endowment.
    2. Applies the bracket schedule to compute taxes owed.
    3. Deducts taxes from each agent’s inventory coin (never from escrow).
    4. Distributes an equal lump-sum net_tax_revenue / n_agents to every agent.

Tax bracket configuration

Brackets are defined by bracket_cutoffs (left edges) and bracket_edges (left + right edges, where the top bracket extends to infinity). The US federal 2018 brackets (before usd_scaling) use cutoffs at: $0, $9,700, $39,475, $84,200, $160,725, $204,100, $510,300 with rates 10%, 12%, 22%, 24%, 32%, 35%, 37%.

Planner actions (model_wrapper mode)

When tax_model == "model_wrapper" and taxes are not disabled, the BasicPlanner receives one action sub-space per bracket:
Action nameSizeDescription
TaxIndexBracket_{cutoff:03d}n_disc_ratesSelects the marginal rate index for this bracket
These actions are only unmasked on the first timestep of each new tax period (tax_cycle_pos == 1). On all other timesteps the planner is forced to take a no-op.

Saez tax policy

When tax_model == "saez", the component adapts Saez’s theoretical optimal income tax formula to the discrete bracket setting:
  1. Maintains a rolling buffer of (income, marginal_rate) pairs sampled across agent-periods.
  2. Estimates income elasticity via OLS regression on log(income) vs. log(1 - marginal_rate).
  3. Computes binned welfare weights g(z) and inverse Pareto parameters A(z).
  4. Derives marginal rates via tau(z) = (1 - g(z)) / (1 - g(z) + A(z) * elasticity).
  5. Maps the resulting schedule onto the configured tax brackets.
Until the buffer has at least 500 samples, random rates are used. Once sufficient data is available, rates update at the start of each new period.

FixedBracketTax / US federal rates

  • "fixed-bracket-rates": Rates provided via fixed_bracket_rates are applied unchanged each period, capped by rate_max.
  • "us-federal-single-filer-2018-scaled": The statutory 2018 rates [10%, 12%, 22%, 24%, 32%, 35%, 37%] are applied, scaled by usd_scaling on bracket cutoffs, and capped by rate_max.

Observations

Agent observations

is_tax_day
float
1.0 if taxes will be collected this timestep, 0.0 otherwise.
is_first_day
float
1.0 if this is the first day of a new tax period, 0.0 otherwise.
tax_phase
float
Fractional position within the current tax period (tax_cycle_pos / period).
last_incomes
ndarray
Sorted array of all agents’ incomes from the previous tax period (normalized by period).
curr_rates
ndarray
Current marginal tax rates for each bracket.
marginal_rate
float
The marginal rate that would apply to this agent’s current income-to-date.

Planner observations (keyed "p{agent_idx}" per agent)

last_income
float
Agent’s normalized income from the last tax period.
last_marginal_rate
float
Marginal rate that was applied to this agent in the last period.
curr_marginal_rate
float
Marginal rate that would apply to this agent’s current income-to-date.

Metrics

avg_bracket_rate/{cutoff}
float
Average marginal rate used for this bracket over the episode.
bracket_occupancy/{cutoff}
float
Fraction of observed agent-periods that fell within this bracket.
avg_effective_tax_rate
float
Mean effective (not marginal) tax rate across all agent-periods. Not reported when disable_taxes=True.
total_collected_taxes
float
Total coin collected as taxes over the episode.
avg_tax_rate/poorest
float
Episode-average effective tax rate paid by the agent with the lowest total coin endowment.
avg_tax_rate/richest
float
Episode-average effective tax rate paid by the agent with the highest total coin endowment.
saez/estimated_elasticity
float
Running estimate of income elasticity. Only present when tax_model == "saez".

Dense log

get_dense_log() returns a list with one entry per timestep. Entries are empty except on tax days. Tax-day entries include:
schedule
ndarray
Array of marginal tax rates applied this period.
cutoffs
ndarray
Array of bracket left-edge cutoff incomes.
{agent_idx}
object
Per-agent tax data with fields: income, tax_paid, marginal_rate, effective_rate, lump_sum.

SimpleLabor

Class name: SimpleLabor — registry name "SimpleLabor" (defined in simple_labor.py). SimpleLabor is a companion component intended for use with PeriodicBracketTax in the one-step-economy scenario. It simplifies labor to a 1-D choice: agents select how many hours to work (0–100) and earn income equal to hours * skill, where skill is pre-assigned from a sorted Pareto distribution.

Key parameters

mask_first_step
boolean
default:"true"
When True, all non-zero labor actions are masked on the environment’s first step. This allows the planner to set tax rates before agents choose their labor supply.
payment_max_skill_multiplier
float
default:"3"
Upper bound on sampled skill values. Skills are drawn from a Pareto distribution and clipped to this maximum.
pareto_param
float
default:"4.0"
Shape parameter of the Pareto distribution used to sample agent skills.

Action space

100 discrete actions — action k means working k hours. Action 0 is no-op (0 hours). Income earned = k * agent.state["skill"].

Agent state fields

skill
float
Wage rate assigned to the agent. Determined by rank-ordering Pareto samples so each agent consistently occupies a skill rank across episodes.
production
float
Cumulative coin earned by this agent through labor this episode.

Example usage

env_config = {
    "components": [
        {
            "SimpleLabor": {
                "mask_first_step": True,
                "payment_max_skill_multiplier": 3,
            }
        },
        {
            "PeriodicBracketTax": {
                "tax_model": "model_wrapper",
                "period": 100,
                "bracket_spacing": "us-federal",
                "usd_scaling": 1000.0,
                "rate_disc": 0.05,
            }
        },
    ]
}