<jupyter_start><jupyter_text>Section 6: Advanced Simulation Methods---  Table of Contents* [cadCAD Simulation Methods](cadCAD-Simulation-Methods)  1. [Monte Carlo Method](1.-Monte-Carlo-Method)  2. [Parameter Sweeps](2.-Parameter-Sweeps)  3. [A/B Testing](3.-A/B-Testing)* [cadCAD Simulation Methods Overview](cadCAD-Simulation-Methods-Overview)* [Data Manipulation & Analysis](Data-Manipulation-&-Analysis) --- \begin{align}\large population_t &\large= population_{t-1} + {\Delta population} \quad \textrm{(sheep)} \tag{1} \\\large food_t &\large= food_{t-1} + {\Delta food} \quad \textrm{(tons of grass)} \tag{2}\end{align}where the rate of change ($\Delta$) is:\begin{align}\large {\Delta population} &\large= \alpha * food_{t-1} - \epsilon * population_{t-1} \quad \textrm{(sheep/month)} \\\large {\Delta food} &\large= -\beta * population_{t-1} + \gamma \quad \textrm{(tons of grass/month)}\end{align}where:$\begin{align}\alpha: \quad &\textrm{'reproduction_rate'}\\\epsilon: \quad &\textrm{'death_rate'}\\\beta: \quad &\textrm{'consumption_rate'}\\\gamma: \quad &\textrm{'growth_rate'}\\\end{align}$* A population consumes a food source, and reproduces at a rate proportional to the food source $\alpha$ (alpha), and dies at a rate proportional to the population size $\epsilon$ (epsilon).* The food source is consumed at a rate proportional to the population $\beta$ (beta), and grows at a constant rate $\gamma$ (gamma). <img src="./images/s6-differential-spec-ecosystem-final.png"     alt="Diff spec"     style="width: 60%" /> Import and run the existing ecosystem model code from section 5:<jupyter_code>import math
import pandas as pd
import plotly

pd.options.plotting.backend = "plotly"

from cadCAD.configuration.utils import config_sim

from cadCAD.engine import ExecutionMode, ExecutionContext
from cadCAD.engine import Executor
from cadCAD.configuration import Experiment

from cadCAD import configs
del configs[:] # Clear any prior configs

experiment = Experiment()<jupyter_output><empty_output><jupyter_text>cadCAD Simulation Methods1. [Monte Carlo Method](1.-Monte-Carlo-Method)2. [Parameter Sweeps](2.-Parameter-Sweeps)3. [A/B testing](3.-A/B-Testing)  1. Monte Carlo Method> Monte Carlo methods, or Monte Carlo experiments, are a broad class of computational algorithms that rely on repeated random sampling to obtain numerical results. The underlying concept is to use randomness to solve problems that might be deterministic in principle.Source: https://en.wikipedia.org/wiki/Monte_Carlo_method  Non-determinism> In computer science, a nondeterministic algorithm is an algorithm that, even for the same input, can exhibit different behaviors on different runs, as opposed to a deterministic algorithm.Source: https://en.wikipedia.org/wiki/Nondeterministic_algorithm \begin{align}\large {\Delta food} &\large= -\beta * population_{t-1} + \gamma * rand() \quad \textrm{(tons of grass/month)} \\\end{align}* Addition of a random food growth rate, using `rand()`.<jupyter_code>from numpy import random
random.rand()
# Setting a seed so that we can reproduce the experiment
random.seed(1234)
# With a given seed, generates a random number from a given set
[
    random.rand(),
    random.rand()
]
random.seed(1234)
[
    random.rand(),
    random.rand()
]
random.seed(None)
seeds = [
    random.RandomState(1),
    random.RandomState(2),
    random.RandomState(3),
]
[
    seeds[0].rand(),
    seeds[1].rand(),
    seeds[2].rand(),
]
MONTE_CARLO_RUNS = 3

seeds = [random.RandomState(i) for i in range(MONTE_CARLO_RUNS)]
seeds
initial_state = {
    'population': 50, # number of sheep
    'food': 1000 # tons of grass
}

system_params = {
    'reproduction_rate': [0.3],
    'death_rate': [0.03],
    'consumption_rate': [0.03],
    'growth_rate': [30.0],
}
def s_population(params, substep, state_history, previous_state, policy_input):
    population = previous_state['population'] + policy_input['delta_population'] 
    return 'population', max(math.ceil(population), 0)

def s_food(params, substep, state_history, previous_state, policy_input):
    food = previous_state['food'] + policy_input['delta_food']
    return 'food', max(food, 0)
def p_reproduction(params, substep, state_history, previous_state):
    population_reproduction = params['reproduction_rate'] * previous_state['food']
    return {'delta_population': population_reproduction}

def p_death(params, substep, state_history, previous_state):
    population_death = params['death_rate'] * previous_state['population']
    return {'delta_population': -population_death}

def p_growth(params, substep, state_history, previous_state):
    run = previous_state['run']
    food_growth = params['growth_rate'] * seeds[run - 1].rand()
    return {'delta_food': food_growth}

def p_consumption(params, substep, state_history, previous_state):
    food_consumption = params['consumption_rate'] * previous_state['population']
    return {'delta_food': -food_consumption}
partial_state_update_blocks = [
    {
        'policies': {
            'reproduction': p_reproduction,
            'death': p_death,
            'consumption': p_consumption,
            'growth': p_growth
        },
        'variables': {
            'population': s_population,
            'food': s_food
        }
    }
]
SIMULATION_TIMESTEPS = 500
sim_config = config_sim({
    'N': MONTE_CARLO_RUNS,
    'T': range(SIMULATION_TIMESTEPS),
    'M': system_params
})

experiment.append_configs(
    initial_state = initial_state,
    partial_state_update_blocks = partial_state_update_blocks,
    sim_configs = sim_config,
)
exec_mode = ExecutionMode()
exec_context = ExecutionContext()

simulation = Executor(exec_context=exec_context, configs=configs)
raw_result, tensor_field, sessions = simulation.execute()
simulation_result = pd.DataFrame(raw_result)
simulation_result
df = simulation_result.copy()
df = df[df.simulation == 0]
df
df[df.run == 1].head()
df[df.run == 2].head()
df[df.run == 3].head()<jupyter_output><empty_output><jupyter_text>Simulation Analysis<jupyter_code>import plotly.express as px

px.line(df, x='timestep', y=['population', 'food'], facet_row='run', height=800, width=1000)<jupyter_output><empty_output><jupyter_text>2. Parameter Sweeps<jupyter_code>dictionary = {
    'reproduction_rate': [0.1, 0.2],
    'death_rate': [0.01, 0.02]
}
dictionary['reproduction_rate'][0]
nested_dictionary = {
    'population': [
        {'reproduction_rate': 0.1, 'death_rate': 0.01},
        {'reproduction_rate': 0.2, 'death_rate': 0.02},
    ]
}
nested_dictionary['population'][0]['reproduction_rate']
initial_state = {
    'population': 50, # number of sheep
    'food': 1000 # tons of grass
}

system_params = {
    'population': [
        {'reproduction_rate': 0.1, 'death_rate': 0.01},
        {'reproduction_rate': 0.2, 'death_rate': 0.02},
        {'reproduction_rate': 0.3, 'death_rate': 0.03}
    ],
    'food': [
        {'consumption_rate': 0.01, 'growth_rate': 10.0},
        {'consumption_rate': 0.02, 'growth_rate': 20.0},
        {'consumption_rate': 0.03, 'growth_rate': 30.0}
    ]
}
{
    'population': system_params['population'][0],
    'food': system_params['food'][0]
}
{
    'population': system_params['population'][1],
    'food': system_params['food'][1]
}
def s_population(params, substep, state_history, previous_state, policy_input):
    population = previous_state['population'] + policy_input['delta_population'] 
    return 'population', max(math.ceil(population), 0)

def s_food(params, substep, state_history, previous_state, policy_input):
    food = previous_state['food'] + policy_input['delta_food']
    return 'food', max(food, 0)
def p_reproduction(params, substep, state_history, previous_state):
    population_reproduction = params['population']['reproduction_rate'] * previous_state['food']
    return {'delta_population': population_reproduction}

def p_death(params, substep, state_history, previous_state):
    population_death = params['population']['death_rate'] * previous_state['population']
    return {'delta_population': -population_death}

def p_consumption(params, substep, state_history, previous_state):
    food_consumption = params['food']['consumption_rate'] * previous_state['population']
    return {'delta_food': -food_consumption}
    
def p_growth(params, substep, state_history, previous_state):
    food_growth = params['food']['growth_rate']
    return {'delta_food': food_growth}
partial_state_update_blocks = [
    {
        'policies': {
            'reproduction': p_reproduction,
            'death': p_death,
            'consumption': p_consumption,
            'growth': p_growth
        },
        'variables': {
            'population': s_population,
            'food': s_food
        }
    }
]
MONTE_CARLO_RUNS = 1
SIMULATION_TIMESTEPS = 500

sim_config = config_sim({
    'N': MONTE_CARLO_RUNS,
    'T': range(SIMULATION_TIMESTEPS),
    'M': system_params
})
from pprint import pprint

print('system_params')
pprint(system_params)
print(' ')
print('sim_config')
pprint(sim_config)
experiment.append_configs(
    initial_state = initial_state,
    partial_state_update_blocks = partial_state_update_blocks,
    sim_configs = sim_config
)
exec_mode = ExecutionMode()
exec_context = ExecutionContext()

simulation = Executor(exec_context=exec_context, configs=configs)
raw_result, tensor_field, sessions = simulation.execute()
simulation_result = pd.DataFrame(raw_result)
simulation_result
df = simulation_result.copy()
df = df[df.simulation == 1]
df<jupyter_output><empty_output><jupyter_text>Simulation Analysis<jupyter_code>import plotly.express as px

px.line(df, x='timestep', y=['population', 'food'], facet_row='subset', height=800, width=1000)<jupyter_output><empty_output><jupyter_text>3. A/B Testing<jupyter_code>df = simulation_result.copy()
df
import plotly.express as px

fig = px.line(
    df,
    x='timestep',
    y=['population', 'food'],
    facet_row='simulation',
    facet_col='run',
    height=800,
    template='seaborn'
)

fig.update_layout(
    margin=dict(l=20, r=20, t=20, b=20),
)

fig.show()<jupyter_output><empty_output><jupyter_text>cadCAD Simulation Methods Overview <img src="./images/cadcad-simulation-methods.png"     alt="Simulation methods"     style="width: 600px;" />  Data Manipulation & Analysis<jupyter_code>df = simulation_result.copy()
df
df = df.query("simulation == 1 and run == 2")
df
fig = px.scatter(
    df[df.timestep >= 80],
    x='population',
    y='food',
    color='timestep'
)
fig.show()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13863549980995818, 'fraction_numerical': 0.01653363740022805, 'mean_word_length': 4.748225013653741, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 34, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '428351', 'license': 'MIT', 'n_tokens_mistral': 3588, 'n_tokens_neox': 3357, 'n_words': 768, 'path': 'complete-foundations-bootcamp-output-main/content/section-6-advanced-simulation-methods/notebook.ipynb', 'repo_name': 'redditech/cadCad-training', 'size': '10524'}