Dynamically Extending And Altering The States¶
We can add fields to the State
or alter the behaviour of the fields dynamically.
Here, we show how to use different experimentalists to sample from a common pool and combine the outputs.
We achieve this by adding a pool
field to the StandardState
and dynamically changing the behaviour of the conditions
field so instead of replacing the conditions
they get extended.
Defining The State¶
We use the standard State object bundled with autora
: StandardState
. This state has four built in fields:
variables
, conditions
, experiment_data
and models
. We can initialize some (or all) of these fields:
import numpy as np
import pandas as pd
from autora.variable import VariableCollection, Variable
from autora.state import StandardState
s = StandardState(
variables=VariableCollection(independent_variables=[Variable("x", value_range=(-15,15))],
dependent_variables=[Variable("y")]),
)
s
StandardState(variables=VariableCollection(independent_variables=[Variable(name='x', value_range=(-15, 15), allowed_values=None, units='', type=<ValueType.REAL: 'real'>, variable_label='', rescale=1, is_covariate=False)], dependent_variables=[Variable(name='y', value_range=None, allowed_values=None, units='', type=<ValueType.REAL: 'real'>, variable_label='', rescale=1, is_covariate=False)], covariates=[]), conditions=None, experiment_data=None, models=[])
Adding Pool To The State¶
First, we add a new field, pool
to state s
. To do this, we must expand the StandardState class, while adding the field. We want the content of this field to be replaced each time a function writes into the field.
from dataclasses import dataclass, field
@dataclass(frozen=True)
class ExtendedStandardState(StandardState):
pool: pd.DataFrame = field(
default_factory=list,
metadata={'delta': 'replace'}
)
s = ExtendedStandardState(
variables=VariableCollection(independent_variables=[Variable("x", value_range=(-15,15))],
dependent_variables=[Variable("y")])
)
s
ExtendedStandardState(variables=VariableCollection(independent_variables=[Variable(name='x', value_range=(-15, 15), allowed_values=None, units='', type=<ValueType.REAL: 'real'>, variable_label='', rescale=1, is_covariate=False)], dependent_variables=[Variable(name='y', value_range=None, allowed_values=None, units='', type=<ValueType.REAL: 'real'>, variable_label='', rescale=1, is_covariate=False)], covariates=[]), conditions=None, experiment_data=None, models=[], pool=[])
We use random_pool
as our pooler and define the output to be the newly created pool
field:
from autora.experimentalist.random import random_pool
from autora.state import on_state
pool = on_state(random_pool, output=["pool"])
s_1 = pool(s, num_samples=10)
s_1
ExtendedStandardState(variables=VariableCollection(independent_variables=[Variable(name='x', value_range=(-15, 15), allowed_values=None, units='', type=<ValueType.REAL: 'real'>, variable_label='', rescale=1, is_covariate=False)], dependent_variables=[Variable(name='y', value_range=None, allowed_values=None, units='', type=<ValueType.REAL: 'real'>, variable_label='', rescale=1, is_covariate=False)], covariates=[]), conditions=None, experiment_data=None, models=[], pool= x 0 -3.599348 1 -14.328625 2 -13.764225 3 3.656028 4 2.723904 5 -7.214785 6 6.466772 7 7.363881 8 13.304111 9 2.923905)
Defining The Experimentalists¶
Here, we use a random sampler To make it use the pool as input, we wrap them in a function. The output will be written into the conditions field.
from autora.experimentalist.random import random_sample
from autora.state import Delta
@on_state
def sample(pool, **kwargs):
return Delta(conditions=random_sample(pool, **kwargs))
s_2 = sample(s_1, num_samples=5)
s_2.conditions
x | |
---|---|
0 | -3.599348 |
1 | -14.328625 |
5 | -7.214785 |
9 | 2.923905 |
8 | 13.304111 |
If we run the sampler on the state again, the conditions get replaced:
s_3 = sample(s_2, num_samples=3)
s_3.conditions
x | |
---|---|
2 | -13.764225 |
3 | 3.656028 |
9 | 2.923905 |
We can change this behaviour, by setting the delta of the state:
s_3.conditions.metadata['delta'] = 'extend'
s_4 = sample(s_3, num_samples=4)
s_4.conditions
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) Cell In[18], line 1 ----> 1 s_3.set_delta('conditions', 'extend') 2 s_4 = sample(s_3, num_samples=4) 3 s_4.conditions AttributeError: 'ExtendedStandardState' object has no attribute 'set_delta'
Defining A Cycle That Dynamically Alters The Behaviour Of A Field¶
We can use this to dynamically switch between replacing and extending the field. This is a toy example since we use the same experimentalist twice, but we could also use other sampling strategies and combine the outputs via this method.
def cycle(s, i):
s = pool(s, num_samples=10)
s.set_delta("conditions", "replace")
s = sample(s, num_samples=2) # now there are always 2 conditions in the field
print(f'cycle {i}, first sample:', s.conditions)
s.set_delta("conditions", "extend")
s = sample(s, num_samples=2) # now there are 4 conditions in the field
print(f'cycle {i}, combined sample:', s.conditions)
print()
return s
for i in range(10):
s = cycle(s, i)
cycle 0, first sample: x 8 6.243647 6 -2.637910 cycle 0, combined sample: x 0 6.243647 1 -2.637910 2 10.854779 3 -9.031437 cycle 1, first sample: x 3 -4.390997 2 -13.689377 cycle 1, combined sample: x 0 -4.390997 1 -13.689377 2 8.103764 3 0.587679 cycle 2, first sample: x 9 13.485559 5 -8.526151 cycle 2, combined sample: x 0 13.485559 1 -8.526151 2 8.072581 3 12.135963 cycle 3, first sample: x 5 13.168087 7 -4.252829 cycle 3, combined sample: x 0 13.168087 1 -4.252829 2 9.545601 3 13.168087 cycle 4, first sample: x 1 -11.610008 8 -5.419989 cycle 4, combined sample: x 0 -11.610008 1 -5.419989 2 10.730890 3 10.875790 cycle 5, first sample: x 0 -0.913466 6 13.441385 cycle 5, combined sample: x 0 -0.913466 1 13.441385 2 -2.473232 3 -0.913466 cycle 6, first sample: x 5 11.894723 6 4.894433 cycle 6, combined sample: x 0 11.894723 1 4.894433 2 -6.875161 3 0.735716 cycle 7, first sample: x 4 -7.696556 3 -6.535279 cycle 7, combined sample: x 0 -7.696556 1 -6.535279 2 -7.981432 3 5.399625 cycle 8, first sample: x 7 -4.805527 8 -4.611733 cycle 8, combined sample: x 0 -4.805527 1 -4.611733 2 -4.611733 3 2.183176 cycle 9, first sample: x 5 -8.000647 7 4.524020 cycle 9, combined sample: x 0 -8.000647 1 4.524020 2 -8.000647 3 -11.450967