Historical State Access
==
#### Motivation
The current state (values of state variables) is accessed through the `s` list. When the user requires previous state variable values, they may be accessed through the state history list, `sH`. Accessing the state history should be implemented without creating unintended feedback loops on the current state.

The 3rd parameter of state and policy update functions (labeled as `sH` of type `List[List[dict]]`) provides access to past Partial State Update Block (PSUB) given a negative offset number. `access_block` is used to access past PSUBs (`List[dict]`) from `sH`. For example, an offset of `-2` denotes the second to last PSUB.

#### Exclusion List
Create a list of states to exclude from the reported PSU.
```python
exclusion_list = [
    'nonexistent', 'last_x', '2nd_to_last_x', '3rd_to_last_x', '4th_to_last_x'
]
```
##### Example Policy Updates
###### Last partial state update
```python
def last_update(_params, substep, sH, s):
    return {"last_x": access_block(
            state_history=sH,
            target_field="last_x", # Add a field to the exclusion list
            psu_block_offset=-1,
            exculsion_list=exclusion_list
        )
    }
```
* Note: Although `target_field` adding a field to the exclusion may seem redundant, it is useful in the case of the exclusion list being empty while the `target_field` is assigned to a state or a policy key.
##### Define State Updates
###### 2nd to last partial state update
```python
def second2last_update(_params, substep, sH, s):
    return {"2nd_to_last_x": access_block(sH, "2nd_to_last_x", -2, exclusion_list)}
```


###### 3rd to last partial state update
```python
def third_to_last_x(_params, substep, sH, s, _input):
    return '3rd_to_last_x', access_block(sH, "3rd_to_last_x", -3, exclusion_list)
```
###### 4rd to last partial state update
```python
def fourth_to_last_x(_params, substep, sH, s, _input):
    return '4th_to_last_x', access_block(sH, "4th_to_last_x", -4, exclusion_list)
```
###### Non-exsistent partial state update
* `psu_block_offset >= 0` doesn't exist
```python
def nonexistent(_params, substep, sH, s, _input):
    return 'nonexistent', access_block(sH, "nonexistent", 0, exclusion_list)
```

#### [Example Simulation:](examples/historical_state_access.py)


#### Example Output:
###### State History
```
+----+-------+-----------+------------+-----+
|    |   run |   substep |   timestep |   x |
|----+-------+-----------+------------+-----|
|  0 |     1 |         0 |          0 |   0 |
|  1 |     1 |         1 |          1 |   1 |
|  2 |     1 |         2 |          1 |   2 |
|  3 |     1 |         3 |          1 |   3 |
|  4 |     1 |         1 |          2 |   4 |
|  5 |     1 |         2 |          2 |   5 |
|  6 |     1 |         3 |          2 |   6 |
|  7 |     1 |         1 |          3 |   7 |
|  8 |     1 |         2 |          3 |   8 |
|  9 |     1 |         3 |          3 |   9 |
+----+-------+-----------+------------+-----+
```
###### Accessed State History: 
Example: `last_x`
```
+----+-----------------------------------------------------------------------------------------------------------------------------------------------------+
|    | last_x                                                                                                                                              |
|----+-----------------------------------------------------------------------------------------------------------------------------------------------------|
|  0 | []                                                                                                                                                  |
|  1 | [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}]                                                                                                   |
|  2 | [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}]                                                                                                   |
|  3 | [{'x': 0, 'run': 1, 'substep': 0, 'timestep': 0}]                                                                                                   |
|  4 | [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}] |
|  5 | [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}] |
|  6 | [{'x': 1, 'run': 1, 'substep': 1, 'timestep': 1}, {'x': 2, 'run': 1, 'substep': 2, 'timestep': 1}, {'x': 3, 'run': 1, 'substep': 3, 'timestep': 1}] |
|  7 | [{'x': 4, 'run': 1, 'substep': 1, 'timestep': 2}, {'x': 5, 'run': 1, 'substep': 2, 'timestep': 2}, {'x': 6, 'run': 1, 'substep': 3, 'timestep': 2}] |
|  8 | [{'x': 4, 'run': 1, 'substep': 1, 'timestep': 2}, {'x': 5, 'run': 1, 'substep': 2, 'timestep': 2}, {'x': 6, 'run': 1, 'substep': 3, 'timestep': 2}] |
|  9 | [{'x': 4, 'run': 1, 'substep': 1, 'timestep': 2}, {'x': 5, 'run': 1, 'substep': 2, 'timestep': 2}, {'x': 6, 'run': 1, 'substep': 3, 'timestep': 2}] |
+----+-----------------------------------------------------------------------------------------------------------------------------------------------------+
```