Skip to content

Add copy support to Scenario#3166

Closed
navneetkumaryadav207001 wants to merge 6 commits intomesa:mainfrom
navneetkumaryadav207001:scenario-parameters-fix
Closed

Add copy support to Scenario#3166
navneetkumaryadav207001 wants to merge 6 commits intomesa:mainfrom
navneetkumaryadav207001:scenario-parameters-fix

Conversation

@navneetkumaryadav207001
Copy link
Copy Markdown

@navneetkumaryadav207001 navneetkumaryadav207001 commented Jan 17, 2026

Scenario Copy Utility

Motivation

When running experiment sweeps, ablations, or parameter tuning, it is common to create multiple variants of a base scenario with small parameter changes.

Manually reconstructing scenarios is:

  • Error-prone: Forgetting to update _scenario_id or other hidden attributes can cause subtle bugs.
  • Verbose: Loops to create multiple scenario variants become messy and repetitive.

This utility introduces a simple, explicit API for cloning scenarios while preserving reproducibility guarantees.


Implementation

  • Added a copy(**updates) method to the Scenario class.
  • Behavior of copied scenario:
    • Receives a new _scenario_id
    • Does not retain the model reference
    • Shares the same RNG object by reference (explicitly documented)
    • Allows parameter overrides at creation

Examples

Without Copy

# This won't run
base = Scenario(a=1, b=2, rng=42)
scenarios2 = []
for b in [3, 4, 5]:
    params = base.to_dict() 
    scenarios2.append(Scenario(**params, b= b)) 

It has three problems

  1. TypeError: experimental.scenarios.scenario.Scenario() got multiple values for keyword argument 'b'
  2. _scenario_id of all scenerios would be same
# Solution
base = Scenario(a=1, b=2, rng=42)
scenarios2 = []
for b in [3, 4, 5]:
    params = base.to_dict()
    params.pop('_scenario_id', None) # fixes 2 
    params.update({'b': b})
    scenarios2.append(Scenario(**params)) 
  1. Too Verbose

With Copy

base = Scenario(a=1, b=2, rng=42)
scenarios1 = [base.copy(b=b) for b in [3, 4, 5]]

Additional Context

  • Dropped get_parameters as it is redundant on quaquel suggestion.
  • I am not sure why are we copying _scenerio_id from *kwargs in scenerio class initialization
self._scenario_id: int = (
            next(self._ids[self.__class__])
            if "_scenario_id" not in kwargs
            else kwargs.pop("_scenario_id")
        )

solves #3159.

@github-actions
Copy link
Copy Markdown

Performance benchmarks:

Model Size Init time [95% CI] Run time [95% CI]
BoltzmannWealth small 🔵 +0.4% [-0.4%, +1.2%] 🔵 +2.0% [+1.8%, +2.1%]
BoltzmannWealth large 🔵 +1.3% [+0.8%, +1.8%] 🔵 +3.3% [+0.5%, +6.4%]
Schelling small 🔵 +0.7% [+0.4%, +1.1%] 🔵 -0.1% [-0.2%, +0.1%]
Schelling large 🔵 +0.8% [+0.5%, +1.1%] 🔵 -1.1% [-2.9%, +0.4%]
WolfSheep small 🔵 +1.3% [+0.8%, +1.9%] 🔵 +0.5% [+0.2%, +0.8%]
WolfSheep large 🔵 +1.5% [+0.4%, +2.7%] 🔵 +1.4% [+0.5%, +2.5%]
BoidFlockers small 🔵 +0.5% [+0.1%, +0.9%] 🔵 +0.3% [+0.1%, +0.5%]
BoidFlockers large 🔵 +0.6% [+0.1%, +1.1%] 🔵 +0.4% [+0.2%, +0.6%]

@quaquel
Copy link
Copy Markdown
Member

quaquel commented Jan 18, 2026

With #3168 merged, I see even less reason for this. Because you can just subclass a scenario with default values and then create new instances from this with only the relevant parameters changed. So again, can you give me a clear practical example of why this would be needed.

I disagree with the naming. A copy should return a copy, not contain support for also changing the content.

In fact, I am considering making Scenario instances fully frozen. This removes the need for the internal model attribute and model.running check, simplifying internal logic and avoiding subtle circular references.

@navneetkumaryadav207001
Copy link
Copy Markdown
Author

Thanks for the discussion.

With the subclassing approach from #3168, I agree that there is no strong need for this anymore: when parameters are known ahead of time, subclassing provides a clean solution, and for fully dynamic cases the existing explicit construction patterns remain available, even if more verbose.

Given that, I’m happy to close this PR and focus on follow-up contributions aligned with the new Scenario design.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants