Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 207 additions & 0 deletions IMPLEMENTATION_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
# Implementation Summary: Partial Parameter Definition Feature

## Overview
This implementation adds support for defining models without specifying all parameters upfront, allowing parameters to be provided later through subsequent `@parameters` calls or function arguments.

## Files Modified

### Core Implementation
1. **src/structures.jl** (Modified)
- Added `undefined_parameters::Vector{Symbol}` field to `ℳ` struct
- Tracks parameters that have not been defined yet

2. **src/macros.jl** (Modified)
- In `@model` macro: Initialize `undefined_parameters` field with empty vector
- In `@parameters` macro:
- Removed assertion that required all parameters to be defined
- Added check for undefined parameters with informative `@info` message
- Store undefined parameters in model structure
- Skip NSSS calculation when parameters are undefined

3. **src/MacroModelling.jl** (Modified)
- `get_NSSS_and_parameters`: Check for undefined parameters at entry, return Inf error if any missing
- `write_parameters_input!` (Dict version): Clear newly defined parameters from undefined_parameters list
- `write_parameters_input!` (Vector version): Clear all from undefined_parameters when full vector provided

4. **src/get_functions.jl** (Modified)
- Added `check_parameters_defined` helper function (currently unused but available)

### Testing
5. **test/test_partial_parameters.jl** (Added)
- Comprehensive test suite covering:
- Partial parameter definition
- Tracking undefined parameters
- Completing definition later
- Providing parameters via function arguments
- Clearing undefined_parameters list

### Documentation
6. **docs/partial_parameters.md** (Added)
- Complete user-facing documentation
- Usage examples
- Common patterns (loading from files)
- Notes on behavior

7. **examples/partial_parameters_example.jl** (Added)
- Working example demonstrating the feature
- Two approaches: incremental definition and function arguments

8. **examples/README.md** (Added)
- Instructions for running examples

## Key Design Decisions

### 1. Non-Breaking Changes
- All existing code continues to work unchanged
- Default behavior is identical when all parameters are defined
- No changes to public API signatures

### 2. Tracking Undefined Parameters
- Simple Vector{Symbol} to track missing parameters
- Automatically updated when parameters are provided
- Can be inspected by users via `model.undefined_parameters`

### 3. Error Handling
- Graceful degradation: functions return appropriate fallback values
- Clear error messages indicating which parameters are missing
- Using `@info` for setup messages, `@error` for computation attempts

### 4. NSSS Calculation
- Delayed until all parameters are defined
- Prevents unnecessary computation with incomplete parameter sets
- Returns Inf error when parameters are missing

### 5. Parameter Provision Methods
Both methods supported:
- Multiple `@parameters` calls (incremental definition)
- Function arguments (Dict, Vector, Pairs) - updates model state

## Behavior Flow

```
@model creation
Initialize undefined_parameters = []
@parameters (partial)
Check which params are undefined
Store in model.undefined_parameters
Show info message if any undefined
Skip NSSS calculation
Computation attempts (get_irf, get_steady_state, etc.)
Call get_NSSS_and_parameters
Check undefined_parameters
If empty: proceed normally
If not: return Inf error with message
@parameters (complete) OR function call with parameters
Update parameter values
Clear from undefined_parameters
Mark NSSS as outdated
Next computation recalculates NSSS
```

## Testing Strategy

The test suite validates:
1. ✅ Model creation with partial parameters
2. ✅ Tracking of undefined parameters
3. ✅ Informative messages when parameters missing
4. ✅ Graceful handling of computation attempts
5. ✅ Completing parameter definition later
6. ✅ Providing parameters via Dict
7. ✅ Clearing undefined_parameters list
8. ✅ Successful computations after all params defined

## Future Enhancements (Not in Scope)

Potential future improvements:
- Allow specifying default values for parameters
- Support for parameter ranges/distributions
- Validation of parameter dependencies
- Parameter groups/categories

## Compatibility

- ✅ Julia 1.6+ (no special requirements)
- ✅ All existing tests pass
- ✅ No breaking changes
- ✅ Backward compatible

## Usage Examples

### Basic Usage
```julia
@model RBC begin
# equations...
end

@parameters RBC begin
α = 0.5
# β and δ undefined
end

# Later...
@parameters RBC begin
α = 0.5
β = 0.95
δ = 0.02
end
```

### Function Argument Usage
```julia
@parameters RBC begin
α = 0.5
end

params = Dict(:β => 0.95, :δ => 0.02, :α => 0.5)
get_irf(RBC, parameters = params)
```

### Loading from File
```julia
@parameters RBC begin
# minimal setup
end

# Load from CSV, JSON, etc.
params = load_parameters_from_file("params.csv")
get_irf(RBC, parameters = params)
```

## Impact Assessment

### Minimal Changes
- Only 5 core files modified
- ~150 lines of code added/modified
- No complex refactoring required

### Risk Assessment
- **Low Risk**: Changes are additive, not replacements
- **Isolated**: New field and checks don't affect existing logic
- **Tested**: Comprehensive test coverage
- **Documented**: Clear documentation and examples

## Conclusion

This implementation successfully addresses the issue requirements:
✅ Allow partial parameter definition
✅ Support incremental parameter addition
✅ Enable parameter provision via function calls
✅ Provide informative messages
✅ Delay NSSS calculation appropriately
✅ Track and report missing parameters
✅ Maintain backward compatibility
119 changes: 119 additions & 0 deletions docs/partial_parameters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Partial Parameter Definition

Starting from this version, MacroModelling.jl allows you to define a model without specifying all parameters upfront. This is useful when:
- You want to load parameters from a file later
- You're working with large models and want to define parameters incrementally
- You want to experiment with different parameter values via function arguments

## Usage

### Basic Example

```julia
using MacroModelling

# Define your model
@model RBC begin
1 / c[0] = (β / c[1]) * (α * exp(z[1]) * k[0]^(α - 1) + (1 - δ))
c[0] + k[0] = (1 - δ) * k[-1] + q[0]
q[0] = exp(z[0]) * k[-1]^α
z[0] = ρ * z[-1] + std_z * eps_z[x]
end

# Define only some parameters initially
@parameters RBC begin
std_z = 0.01
ρ = 0.2
α = 0.5
# β and δ are not defined yet
end
```

When you run this, you'll see an informative message:
```
[ Info: Model set up with undefined parameters: [:β, :δ]
Non-stochastic steady state and solution cannot be calculated until all parameters are defined.
```

### Checking Undefined Parameters

You can check which parameters are still undefined:

```julia
RBC.undefined_parameters # Returns [:β, :δ]
```

### Completing Parameter Definition

You can define the remaining parameters later by calling `@parameters` again:

```julia
@parameters RBC begin
std_z = 0.01
ρ = 0.2
α = 0.5
β = 0.95 # Now defined
δ = 0.02 # Now defined
end
```

After this, `RBC.undefined_parameters` will be empty, and you can compute steady states and IRFs.

### Providing Parameters via Function Arguments

Alternatively, you can provide all parameters when calling functions:

```julia
# Model still has undefined parameters
@parameters RBC begin
std_z = 0.01
ρ = 0.2
end

# Provide all parameters including the undefined ones
params = Dict(:α => 0.5, :β => 0.95, :δ => 0.02, :std_z => 0.01, :ρ => 0.2)

# This will work and update the undefined_parameters list
get_irf(RBC, parameters = params, periods = 40)
```

## Behavior with Undefined Parameters

When you try to compute outputs (IRFs, steady states, etc.) with undefined parameters:

1. **Functions that compute NSSS**: These will log an error message indicating which parameters are missing and return appropriate fallback values
2. **The `undefined_parameters` field**: Automatically tracked and updated when:
- Parameters are defined via `@parameters`
- Parameters are provided via function arguments (Dict or Vector)

## Loading Parameters from Files

A common use case is loading parameters from external sources:

```julia
using MacroModelling, CSV, DataFrames

# Define model
@model MyModel begin
# ... model equations ...
end

# Set up with minimal parameters
@parameters MyModel begin
# ... only essential parameters ...
end

# Load remaining parameters from file
params_df = CSV.read("model_parameters.csv", DataFrame)
params_dict = Dict(Symbol(row.parameter) => row.value for row in eachrow(params_df))

# Provide parameters via function call
get_irf(MyModel, parameters = params_dict)
```

## Notes

- The model structure is still fully validated when created with `@model`
- Only parameter values can be left undefined, not the model equations
- When all parameters are eventually defined, the model behaves exactly as if all parameters were defined from the start
- The non-stochastic steady state and solution will be computed once all parameters are provided
36 changes: 36 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# MacroModelling.jl Examples

This directory contains example scripts demonstrating various features of MacroModelling.jl.

## Running the Examples

To run an example, navigate to the package directory and execute:

```bash
julia --project=. examples/partial_parameters_example.jl
```

## Available Examples

### partial_parameters_example.jl

Demonstrates the new partial parameter definition feature, which allows you to:
- Define models without specifying all parameters upfront
- Add parameters incrementally via multiple `@parameters` calls
- Provide parameters dynamically via function arguments
- Load parameters from external sources

This is particularly useful for:
- Large models where parameter definition is cumbersome
- Scenarios where parameters come from different sources or files
- Experimentation with different parameter values

## Requirements

Make sure the MacroModelling.jl package is properly installed and activated:

```julia
using Pkg
Pkg.activate(".")
Pkg.instantiate()
```
Loading
Loading