diff --git a/.github/actions/install-pnl/action.yml b/.github/actions/install-pnl/action.yml index d5ec8de3949..8571a3293b0 100644 --- a/.github/actions/install-pnl/action.yml +++ b/.github/actions/install-pnl/action.yml @@ -18,7 +18,7 @@ runs: run: | case "$RUNNER_OS" in macOS*) brew install graphviz ;; - Linux*) sudo apt-get install -y graphviz ;; + Linux*) sudo apt-get update && sudo apt-get install -y --no-install-recommends graphviz ;; Windows*) choco install --no-progress -y graphviz --version=2.38.0.20190211 ;; *) echo "Unsupported OS"; exit 1 ;; esac @@ -42,6 +42,7 @@ runs: run: | if [ $(python -c 'import struct; print(struct.calcsize("P") * 8)') == 32 ]; then sed -i /torch/d requirements.txt + sed -i /modeci_mdf/d requirements.txt # pywinpty is a transitive dependency and v1.0+ removed support for x86 wheels # terminado >= 0.10.0 pulls in pywinpty >= 1.1.0 [[ ${{ runner.os }} = Windows* ]] && pip install "pywinpty<1" "terminado<0.10" diff --git a/.github/workflows/pnl-ci-docs.yml b/.github/workflows/pnl-ci-docs.yml index 869c9dd94f5..f2396ef7a04 100644 --- a/.github/workflows/pnl-ci-docs.yml +++ b/.github/workflows/pnl-ci-docs.yml @@ -39,20 +39,24 @@ jobs: on_master: ${{ steps.on_master.outputs.on-branch }} steps: + # increased fetch-depth and tag checkout needed as in pnl-ci.yml - name: Checkout sources - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3 if: ${{ matrix.pnl-version == 'head' }} with: - fetch-depth: 10 + fetch-depth: 200 ref: ${{ github.ref }} - name: Checkout pull base - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3 if: ${{ matrix.pnl-version == 'base' }} with: - fetch-depth: 10 + fetch-depth: 200 ref: ${{ github.base_ref }} + - name: Checkout tags + run: git fetch --tags origin master + - name: Check if on master if: ${{ github.event_name == 'push' }} id: on_master @@ -61,7 +65,7 @@ jobs: branch: master - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2.3.1 + uses: actions/setup-python@v3 with: python-version: ${{ matrix.python-version }} architecture: ${{ matrix.python-architecture }} @@ -75,7 +79,7 @@ jobs: echo ::set-output name=pip_cache_dir::$(python -m pip cache dir) - name: Wheels cache - uses: actions/cache@v2.1.7 + uses: actions/cache@v3 with: path: ${{ steps.pip_cache.outputs.pip_cache_dir }}/wheels key: ${{ runner.os }}-python-${{ matrix.python-version }}-${{ matrix.python-architecture }}-pip-wheels-v2-${{ github.sha }} @@ -103,7 +107,7 @@ jobs: run: git tag -d 'v999.999.999.999' - name: Upload Documentation - uses: actions/upload-artifact@v2.3.1 + uses: actions/upload-artifact@v3 with: name: Documentation-${{matrix.pnl-version}}-${{ matrix.os }}-${{ matrix.python-version }}-${{ matrix.python-architecture }} retention-days: 1 @@ -115,7 +119,7 @@ jobs: - name: Upload PR number for other workflows if: ${{ github.event_name == 'pull_request' }} - uses: actions/upload-artifact@v2.3.1 + uses: actions/upload-artifact@v3 with: name: pr_number path: ./pr_number.txt @@ -142,7 +146,7 @@ jobs: steps: - name: Checkout docs - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3 with: ref: gh-pages diff --git a/.github/workflows/pnl-ci.yml b/.github/workflows/pnl-ci.yml index 3f26414982b..25227973e1d 100644 --- a/.github/workflows/pnl-ci.yml +++ b/.github/workflows/pnl-ci.yml @@ -40,13 +40,21 @@ jobs: os: macos-latest steps: + # increased fetch-depth and tag checkout needed to get correct + # version string from versioneer (must have history to a prior tag); + # otherwise install fails due to circular dependency with modeci_mdf - name: Checkout sources - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3 with: - fetch-depth: 10 + fetch-depth: 200 + + # fetch only master to avoid getting unneeded branches with + # characters invalid on windows + - name: Checkout tags + run: git fetch --tags origin master - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2.3.1 + uses: actions/setup-python@v3 with: python-version: ${{ matrix.python-version }} architecture: ${{ matrix.python-architecture }} @@ -60,7 +68,7 @@ jobs: echo ::set-output name=pip_cache_dir::$(python -m pip cache dir) - name: Wheels cache - uses: actions/cache@v2.1.7 + uses: actions/cache@v3 with: path: ${{ steps.pip_cache.outputs.pip_cache_dir }}/wheels key: ${{ runner.os }}-python-${{ matrix.python-version }}-${{ matrix.python-architecture }}-pip-wheels-v2-${{ github.sha }} @@ -85,7 +93,7 @@ jobs: run: pytest --junit-xml=tests_out.xml --verbosity=0 -n auto ${{ matrix.extra-args }} - name: Upload test results - uses: actions/upload-artifact@v2.3.1 + uses: actions/upload-artifact@v3 with: name: test-results-${{ matrix.os }}-${{ matrix.python-version }}-${{ matrix.python-architecture }}-${{ matrix.extra-args }} path: tests_out.xml @@ -111,7 +119,7 @@ jobs: python setup.py sdist bdist_wheel - name: Upload dist packages - uses: actions/upload-artifact@v2.3.1 + uses: actions/upload-artifact@v3 with: name: dist-${{ matrix.os }}-${{ matrix.python-version }}-${{ matrix.python-architecture }} path: dist/ diff --git a/.github/workflows/test-release.yml b/.github/workflows/test-release.yml index 5be1d382304..32b6467d85e 100644 --- a/.github/workflows/test-release.yml +++ b/.github/workflows/test-release.yml @@ -18,10 +18,10 @@ jobs: wheel: ${{ steps.create_dist.outputs.wheel }} steps: - name: Checkout sources - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2.3.1 + uses: actions/setup-python@v3 with: python-version: ${{ matrix.python-version }} @@ -38,7 +38,7 @@ jobs: echo ::set-output name=wheel::$(ls *.whl) - name: Upload Python dist files - uses: actions/upload-artifact@v2.3.1 + uses: actions/upload-artifact@v3 with: name: Python-dist-files path: dist/ @@ -84,7 +84,7 @@ jobs: path: dist/ - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2.3.1 + uses: actions/setup-python@v3 with: python-version: ${{ matrix.python-version }} @@ -113,7 +113,7 @@ jobs: run: pip install dist/${{ needs.create-python-dist.outputs.sdist }}[dev] - name: Get tests from the repository - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3 - name: Run tests shell: bash @@ -126,7 +126,7 @@ jobs: pytest --junit-xml=tests_out.xml --verbosity=0 -n auto tests - name: Upload test results - uses: actions/upload-artifact@v2.3.1 + uses: actions/upload-artifact@v3 with: name: test-results-${{ matrix.os }}-${{ matrix.python-version }} path: tests_out.xml diff --git a/.gitignore b/.gitignore index f3c0537cf81..0b0f973f543 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,16 @@ # Created by https://www.gitignore.io/api/osx,python,pycharm +# Ignore JSON files created in tests/json/ +# Maybe these should be generated in tmpdir instead +tests/json/*.json + # Log files created by SLURM jobs in this directory Scripts/Debug/predator_prey_opt/logs/ +# Any plots generated from testing DDMs +Scripts/Debug/ddm/*.png + ### OSX ### *.DS_Store .AppleDouble diff --git a/README.rst b/README.rst index bbe1d33cbc4..d04ca20b23c 100644 --- a/README.rst +++ b/README.rst @@ -5,6 +5,10 @@ .. image:: https://mybinder.org/badge.svg :target: https://mybinder.org/v2/gh/PrincetonUniversity/PsyNeuLink/master +.. ***************************************************************************************** +.. ****** NOTE: UPDATES TO THIS PAGE SHOULD ALSO BE MADE TO docs/source.index.rst ********* +.. ***************************************************************************************** + Welcome to PsyNeuLink ===================== diff --git a/Scripts/Debug/Jason_Reward_rate_with_penalty_with_inputs.py b/Scripts/Debug/Jason_Reward_rate_with_penalty_with_inputs.py index ca0d4ebf933..759f1a1c708 100644 --- a/Scripts/Debug/Jason_Reward_rate_with_penalty_with_inputs.py +++ b/Scripts/Debug/Jason_Reward_rate_with_penalty_with_inputs.py @@ -119,8 +119,8 @@ def get_stroop_model(unit_noise_std=.01, dec_noise_std=.1): function=pnl.DriftDiffusionAnalytical(drift_rate=1, threshold =1, noise=1, - starting_point=0, - t0=0.35), + starting_value=0, + non_decision_time=0.35), output_ports=[pnl.RESPONSE_TIME, pnl.PROBABILITY_UPPER_THRESHOLD, pnl.PROBABILITY_LOWER_THRESHOLD] @@ -204,7 +204,7 @@ def get_stroop_model(unit_noise_std=.01, dec_noise_std=.1): inp_task.input_port, reward.input_port, punish.input_port], - state_feature_functions=pnl.AdaptiveIntegrator(rate=0.1), + state_feature_function=pnl.AdaptiveIntegrator(rate=0.1), objective_mechanism=objective_mech, function=pnl.GridSearch(), control_signals=[driftrate_control_signal, diff --git a/Scripts/Debug/Predator-Prey Sebastian REDUCED.py b/Scripts/Debug/Predator-Prey Sebastian REDUCED.py index c62a30a4078..15ec7e4928b 100644 --- a/Scripts/Debug/Predator-Prey Sebastian REDUCED.py +++ b/Scripts/Debug/Predator-Prey Sebastian REDUCED.py @@ -62,7 +62,7 @@ def get_new_episode_flag(): ocm = OptimizationControlMechanism(name='EVC', state_features=[trial_type_input_mech], - # state_feature_functions=FEATURE_FUNCTION, + # state_feature_function=FEATURE_FUNCTION, agent_rep=RegressionCFA( name='RegressionCFA', update_weights=BayesGLM(mu_0=0.5, sigma_0=0.1), diff --git a/Scripts/Debug/Predator-Prey Sebastian.py b/Scripts/Debug/Predator-Prey Sebastian.py index b332f104e11..491cb9f5a63 100644 --- a/Scripts/Debug/Predator-Prey Sebastian.py +++ b/Scripts/Debug/Predator-Prey Sebastian.py @@ -167,7 +167,7 @@ def get_action(variable=[[0,0],[0,0],[0,0]]): ocm = OptimizationControlMechanism(name='EVC', state_features=[trial_type_input_mech], - # state_feature_functions=FEATURE_FUNCTION, + # state_feature_function=FEATURE_FUNCTION, agent_rep=RegressionCFA( name='RegressionCFA', update_weights=BayesGLM(mu_0=0.5, sigma_0=0.1), diff --git a/Scripts/Debug/StabilityFlexibility.py b/Scripts/Debug/StabilityFlexibility.py index ef4b2ff27bf..3bc8d4bdf45 100644 --- a/Scripts/Debug/StabilityFlexibility.py +++ b/Scripts/Debug/StabilityFlexibility.py @@ -69,7 +69,7 @@ def computeAccuracy(variable): gain = np.asarray([[g]]) DRIFT = 1 # Drift Rate -STARTING_POINT = 0.0 # Starting Point +STARTING_VALUE = 0.0 # Starting Point THRESHOLD = 0.0475 # Threshold NOISE = 0.04 # Noise T0 = 0.2 # T0 @@ -123,10 +123,10 @@ def computeAccuracy(variable): ddmCombination.set_log_conditions([pnl.RESULT]) decisionMaker = pnl.DDM(function=pnl.DriftDiffusionAnalytical(drift_rate = DRIFT, - starting_point = STARTING_POINT, + starting_value = STARTING_VALUE, threshold = THRESHOLD, noise = NOISE, - t0 = T0), + non_decision_time = T0), output_ports = [pnl.DECISION_VARIABLE, pnl.RESPONSE_TIME, pnl.PROBABILITY_UPPER_THRESHOLD, pnl.PROBABILITY_LOWER_THRESHOLD], name='DDM') diff --git a/Scripts/Debug/Umemoto_Feb.py b/Scripts/Debug/Umemoto_Feb.py index a8ba6f4b11b..bb33cfca68c 100644 --- a/Scripts/Debug/Umemoto_Feb.py +++ b/Scripts/Debug/Umemoto_Feb.py @@ -13,7 +13,7 @@ # EVC params for Umemoto et al -t0 = 0.2 +non_decision_time = 0.2 c = 0.19 thresh = 0.21 x_0 = 0 # starting point @@ -59,8 +59,8 @@ # drift_rate=(0.1170), threshold=(thresh), noise=(c), - starting_point=(x_0), - t0=t0 + starting_value=(x_0), + non_decision_time=non_decision_time ),name='Decision', output_ports=[ pnl.DECISION_VARIABLE, @@ -71,7 +71,7 @@ pnl.VARIABLE: (pnl.OWNER_VALUE, 2), pnl.FUNCTION: pnl.Linear(0, slope=1.0, intercept=1) } - ],) #drift_rate=(1.0),threshold=(0.2645),noise=(0.5),starting_point=(0), t0=0.15 + ],) #drift_rate=(1.0),threshold=(0.2645),noise=(0.5),non_decision_time=(0), non_decision_time=0.15 Decision.set_log_conditions('InputPort-0')#, log_condition=pnl.PROCESSING) @@ -120,7 +120,7 @@ Umemoto_comp.add_model_based_optimizer(optimizer=pnl.OptimizationControlMechanism(agent_rep=Umemoto_comp, state_features=[Target_Stim.input_port, Distractor_Stim.input_port, Reward.input_port], - state_feature_functions=pnl.AdaptiveIntegrator(rate=1.0), + state_feature_function=pnl.AdaptiveIntegrator(rate=1.0), objective_mechanism=pnl.ObjectiveMechanism(monitor_for_control=[Reward, (Decision.output_ports[pnl.PROBABILITY_UPPER_THRESHOLD], 1, -1)], ), diff --git a/Scripts/Debug/Umemoto_Feb2.py b/Scripts/Debug/Umemoto_Feb2.py index 1b75225342e..13807b92ece 100644 --- a/Scripts/Debug/Umemoto_Feb2.py +++ b/Scripts/Debug/Umemoto_Feb2.py @@ -13,7 +13,7 @@ # EVC params for Umemoto et al -t0 = 0.2 +non_decision_time = 0.2 c = 0.19 thresh = 0.21 x_0 = 0 # starting point @@ -61,8 +61,8 @@ # drift_rate=(0.1170), threshold=(thresh), noise=(c), - starting_point=(x_0), - t0=t0 + starting_value=(x_0), + non_decision_time=non_decision_time ),name='Decision', output_ports=[ pnl.DECISION_VARIABLE, @@ -73,7 +73,7 @@ pnl.VARIABLE: (pnl.OWNER_VALUE, 2), pnl.FUNCTION: pnl.Linear(0, slope=1.0, intercept=1) } - ],) #drift_rate=(1.0),threshold=(0.2645),noise=(0.5),starting_point=(0), t0=0.15 + ],) #drift_rate=(1.0),threshold=(0.2645),noise=(0.5),non_decision_time=(0), non_decision_time=0.15 Decision.set_log_conditions('InputPort-0')#, log_condition=pnl.PROCESSING) Decision.set_log_conditions('PROBABILITY_UPPER_THRESHOLD') @@ -132,7 +132,7 @@ state_features=[Target_Stim.input_port, Distractor_Stim.input_port, Reward.input_port], - state_feature_functions=pnl.AdaptiveIntegrator(rate=1.0), + state_feature_function=pnl.AdaptiveIntegrator(rate=1.0), objective_mechanism=pnl.ObjectiveMechanism( monitor_for_control=[Reward, (Decision.output_ports[pnl.PROBABILITY_UPPER_THRESHOLD], 1, -1)], diff --git a/Scripts/Debug/ddm/__init__.py b/Scripts/Debug/ddm/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Scripts/Debug/ddm/ddm_fit.py b/Scripts/Debug/ddm/ddm_fit.py new file mode 100644 index 00000000000..f0084076e11 --- /dev/null +++ b/Scripts/Debug/ddm/ddm_fit.py @@ -0,0 +1,64 @@ +#%% +import numpy as np +import pandas as pd +import psyneulink as pnl + +from psyneulink.core.components.functions.fitfunctions import make_likelihood_function, \ + MaxLikelihoodEstimator + +ddm_params = dict(starting_value=0.0, rate=0.3, noise=1.0, + threshold=0.6, non_decision_time=0.15, time_step_size=0.01) + +# Create a simple one mechanism composition containing a DDM in integrator mode. +decision = pnl.DDM(function=pnl.DriftDiffusionIntegrator(**ddm_params), + output_ports=[pnl.DECISION_VARIABLE, pnl.RESPONSE_TIME], + name='DDM') + +comp = pnl.Composition(pathways=decision) + +#%% + +# Lets generate an "experimental" dataset to fit. This is a parameter recovery test +# The input will be 500 trials of the same constant stimulus drift rate of 1 +input = np.ones((500, 1)) +inputs_dict = {decision: input} + +# Run the composition to generate some data to fit +comp.run(inputs=inputs_dict, + num_trials=len(input), + execution_mode=pnl.ExecutionMode.LLVMRun) + +# Store the results of this "experiment" as a numpy array. This should be a +# 2D array of shape (len(input), 2). The first column being a discrete variable +# specifying the upper or lower decision boundary and the second column is the +# reaction time. We will put the data into a pandas DataFrame, this makes its +# easier to specify which columns in the data are categorical or not. +data_to_fit = pd.DataFrame(np.squeeze(np.array(comp.results)), + columns=['decision', 'rt']) +data_to_fit['decision'] = pd.Categorical(data_to_fit['decision']) + +#%% + +# Create a likelihood function from the composition itself, this is done +# using probability density approximation via kernel density estimation. +likelihood, param_map = comp.make_likelihood_function( + fit_params=[decision.function.parameters.rate, + decision.function.parameters.starting_value, + decision.function.parameters.non_decision_time], + inputs=inputs_dict, + data_to_fit=data_to_fit, + num_sims_per_trial=100, + combine_trials=True) + +params_to_recover = {k: ddm_params[k] for k in param_map.values()} +print(f"Parameters to recover: {params_to_recover}") +print(f"Data Neg-Log-Likelihood: {-likelihood(**params_to_recover)}") + +mle = MaxLikelihoodEstimator(log_likelihood_function=likelihood, + fit_params_bounds={ + 'rate': (0.0, 1.0), + 'starting_value': (0.0, 0.9), + 'non_decision_time': (0.0, 1.0), + }) + +fit_results = mle.fit(display_iter=True, save_iterations=True) \ No newline at end of file diff --git a/Scripts/Debug/ddm/ddm_plot_check.py b/Scripts/Debug/ddm/ddm_plot_check.py new file mode 100644 index 00000000000..fba891d5006 --- /dev/null +++ b/Scripts/Debug/ddm/ddm_plot_check.py @@ -0,0 +1,151 @@ +#%% +import numpy as np +import psyneulink as pnl + +import matplotlib.pyplot as plt +plt.rcParams["figure.figsize"] = (20,10) + +import matplotlib.pyplot as plt +import seaborn as sns +import pandas as pd + +import wfpt + +from psyneulink.core.components.functions.fitfunctions import simulation_likelihood + + +def ddm_pdf_analytical(drift_rate, threshold, noise, starting_point, non_decision_time, time_step_size=0.01): + from ddm import Model + from ddm.models import DriftConstant, NoiseConstant, BoundConstant, OverlayNonDecision, ICPoint + from ddm.functions import display_model + + model = Model(name='Simple model', + drift=DriftConstant(drift=drift_rate), + noise=NoiseConstant(noise=noise), + bound=BoundConstant(B=threshold), + IC=ICPoint(x0=starting_point), + overlay=OverlayNonDecision(nondectime=non_decision_time), + dx=.001, dt=time_step_size, T_dur=3) + display_model(model) + s = model.solve() + + return model.t_domain(), s.pdf_corr(), s.pdf_err() + + +def ddm_pdf_simulate(drift_rate=0.75, threshold=1.0, noise=0.1, starting_point=0.0, non_decision_time=0.0, + time_step_size=0.01, num_samples=1000000, use_pnl=True, rt_space=None): + + if use_pnl: + decision = pnl.DDM(function=pnl.DriftDiffusionIntegrator(starting_value=0.1234), + output_ports=[pnl.DECISION_VARIABLE, pnl.RESPONSE_TIME], + name='DDM') + + comp = pnl.Composition() + comp.add_node(decision) + + context = pnl.Context() + decision.function.parameters.rate.set(drift_rate, context) + decision.function.parameters.noise.set(noise, context) + decision.function.parameters.threshold.set(threshold, context) + decision.function.parameters.time_step_size.set(time_step_size, context) + decision.function.parameters.starting_value.set(np.array([starting_point]), context) + decision.function.parameters.time_step_size.set(time_step_size, context) + decision.function.parameters.non_decision_time.set(non_decision_time, context) + + input = np.ones((1, 1)) + + comp.run(inputs={decision: input}, + num_trials=num_samples * len(input), + execution_mode=pnl.ExecutionMode.LLVMRun, + context=context) + + results = np.squeeze(np.array(comp.results)) + rts = np.array(np.vsplit(results, len(input))) + + else: + rts = wfpt.simulate_wfpt(starting_point * np.ones(num_samples), + non_decision_time * np.ones(num_samples), + drift_rate * np.ones(num_samples), + threshold * np.ones(num_samples), + dt=time_step_size) + rts = np.expand_dims(np.column_stack((np.sign(rts)*threshold, np.abs(rts))), axis=0) + + # Make a histogram + # hist = bh.Histogram(bh.axis.Boolean(), bh.axis.Regular(int(3 / time_step_size), 0.0, 3.0)) + # hist.fill(rts[:, :, 0].flatten() > 0.0, rts[:, :, 1].flatten()) + + if rt_space is None: + rt_space = np.linspace(0.0, 3.0, 3000) + + df = pd.DataFrame(index=rt_space) + + df[f'Correct KDE (dt={time_step_size})'] = simulation_likelihood(rts, + categorical_dims=np.array([True, False]), + combine_trials=True, + exp_data=np.c_[ + threshold * np.ones(len(rt_space)), rt_space]) + df[f'Error KDE (dt={time_step_size})'] = simulation_likelihood(rts, + categorical_dims=np.array([True, False]), + combine_trials=True, + exp_data=np.c_[ + -threshold * np.ones(len(rt_space)), rt_space]) + + #df[f'Correct Histogram (dt={time_step_size})'] = (hist[True, :] / hist.sum(flow=True) / time_step_size).view() + #df[f'Error Histogram (dt={time_step_size})'] = (hist[False, :] / hist.sum(flow=True) / time_step_size).view() + + return df + + +def ddm_plot_check(): + ddm_params = dict(starting_point=0.1, drift_rate=0.3, noise=1.0, threshold=0.6, non_decision_time=0.8) + + # from numpy.random import rand + # pd.DataFrame({ + # 'drift_rate': (rand() - .5) * 8, + # 'non_decision_time': 0.2 + rand() * 0.3, + # 'threshold': 0.5 + rand() * 1.5, + # 'noise': 1.0 + # }) + + NUM_SAMPLES = 100000 + + rt_space = np.linspace(0.0, 3.0, 30000) + + # Get the analytical + t_domain, pdf_corr, pdf_err = ddm_pdf_analytical(**ddm_params) + + # Interpolate to common rt space + from scipy.interpolate import interpn + anal_df = pd.DataFrame(index=rt_space) + anal_df[f"Correct Analytical"] = interpn((t_domain,), pdf_corr, rt_space, + method='linear', bounds_error=False, fill_value=1e-10) + anal_df[f"Error Analytical"] = interpn((t_domain,), pdf_err, rt_space, + method='linear', bounds_error=False, fill_value=1e-10) + + # Navarro and Fuss solution + # p_err = np.array( + # [wfpt.wfpt_logp(t, 0, starting_point, non_decision_time, drift_rate, threshold, eps=1e-10) for t in + # model_t_domain[1:]]) + # p_corr = np.array( + # [wfpt.wfpt_logp(t, 1, starting_point, non_decision_time, drift_rate, threshold, eps=1e-10) for t in + # model_t_domain[1:]]) + + df = pd.concat([ + anal_df, + ddm_pdf_simulate(**ddm_params, time_step_size=0.01, use_pnl=True, num_samples=NUM_SAMPLES, rt_space=rt_space), + ddm_pdf_simulate(**ddm_params, time_step_size=0.001, use_pnl=True, num_samples=NUM_SAMPLES, rt_space=rt_space), + ddm_pdf_simulate(**ddm_params, time_step_size=0.0001, use_pnl=True, num_samples=NUM_SAMPLES, rt_space=rt_space), + ]) + + fig, axes = plt.subplots(1, 2, sharex=True, sharey=True) + + #df = df.loc[:, ~df.columns.str.contains('Histogram')] + sns.lineplot(data=df.filter(regex='Correct'), ax=axes[0]) + sns.lineplot(data=df.filter(regex='Error'), ax=axes[1]) + plt.show() + + plt.savefig(f"{'_'.join([f'{p}={v}' for p,v in ddm_params.items()])}.png") + + +ddm_plot_check() + diff --git a/Scripts/Debug/ddm/pytorch_ddm.py b/Scripts/Debug/ddm/pytorch_ddm.py new file mode 100644 index 00000000000..786416f6251 --- /dev/null +++ b/Scripts/Debug/ddm/pytorch_ddm.py @@ -0,0 +1,110 @@ +#%% +import time +import torch +from torch import nn + +from typing import Tuple + +if torch.cuda.is_available(): + dev = "cuda:0" +else: + dev = "cpu" + + +class DriftDiffusionModel(torch.nn.Module): + def forward(self, + starting_value: float = 0.0, + rate: float = 1.0, + non_decision_time: float = 0.0, + threshold: float = 1.0, + noise: float = 1.0, + time_step_size: float = 0.01, + num_walkers: int = 1000, + dev: str = "cuda:0") -> Tuple[torch.Tensor, torch.Tensor]: + + """ + A model that simulates many instances of a simple noisy drift diffusion model in parallel. + + Args: + starting_value: The starting value of each particle in the model. + rate: The drift rate for each particle. + non_decision_time: A constant amount of time added to each reaction time that signifies automatic processing + times of stimuli. + threshold: The threshold that a particle must reach to stop integration. + noise: The standard deviation of the Gaussian noise added to each particles position at each time step. + time_step_size: The time step size (in seconds) for the integration process. + num_walkers: The number of particles to simulate. + dev: The device the model should be run on. + + Returns: + A two element tuple containing the reaction times and the decisions + """ + + particle = torch.ones(size=(num_walkers,), device=dev) * starting_value + active = torch.ones(size=(num_walkers,), dtype=torch.bool, device=dev) + rts = torch.zeros(size=(num_walkers,), device=dev) + + for i in range(3000): + #dw = torch.distributions.Normal(loc=rate * time_step_size * active, scale=noise * active).rsample() + dw = torch.normal(mean=rate * time_step_size * active, std=noise * active) + particle = particle + dw * torch.sqrt(time_step_size) + rts = rts + active + active = torch.abs(particle) < threshold + + rts = (non_decision_time + rts * time_step_size) + + decisions = torch.ones(size=(num_walkers,), device=dev) + decisions[particle <= -threshold] = 0 + + return rts, decisions + + +ddm_params = dict(starting_value=0.0, rate=0.3, non_decision_time=0.15, threshold=0.6, noise=1.0, time_step_size=0.001) + +NUM_WALKERS = 1000000 + +# Move params to device +for key, val in ddm_params.items(): + ddm_params[key] = torch.tensor(val).to(dev) + +#%% + +t0 = time.time() +ddm_model = DriftDiffusionModel() +rts, decision = ddm_model(**ddm_params, num_walkers=NUM_WALKERS, dev=dev) +rts = rts.to("cpu") +decision = decision.to("cpu") +print(f"PyTorch Elapsed: {1000.0 * (time.time() - t0)} milliseconds") + +#%% + +# JIT +jit_ddm_model = torch.jit.script(ddm_model) + +#%% +# rts, decision = jit_ddm_model(**ddm_params, num_walkers=NUM_WALKERS) +# +# NUM_TIMES = 50 +# t0 = time.time() +# for i in range(NUM_TIMES): +# rts, decision = jit_ddm_model(**ddm_params, num_walkers=NUM_WALKERS) +# rts = rts.to("cpu") +# decision = decision.to("cpu") +# print(f"JIT Elapsed: {1000 * ((time.time() - t0) / NUM_TIMES)} milliseconds") + +#%% + +jit_ddm_model.save("ddm.pt") + +#%% +# with open('ddm.onnx', 'wb') as file: +# torch.onnx.export(model=torch.jit.script(DriftDiffusionModel()), +# args=tuple(ddm_params.values()) + (torch.tensor(NUM_WALKERS),), +# example_outputs=(rts, decision), +# f=file, +# verbose=True, +# opset_version=12) + +#%% +# import seaborn as sns +# sns.kdeplot(rts) diff --git a/Scripts/Debug/ddm/taichi_ddm.py b/Scripts/Debug/ddm/taichi_ddm.py new file mode 100644 index 00000000000..de8619cd332 --- /dev/null +++ b/Scripts/Debug/ddm/taichi_ddm.py @@ -0,0 +1,70 @@ +import taichi as ti +import taichi_utils as tu + +ti.init(arch=ti.gpu) + +num_simulations = 1000000 +rt = ti.field(ti.f32, num_simulations) +decision = ti.field(ti.i32, num_simulations) + +@ti.func +def ddm_time_step(prev_value, drift_rate, time_step_size): + return prev_value + (tu.rand_normal() + drift_rate * time_step_size) * ti.sqrt(time_step_size) + + +@ti.func +def simulate_ddm(starting_value, non_decision_time, drift_rate, threshold, time_step_size): + particle = starting_value + t = 0 + while abs(particle) < threshold: + particle = ddm_time_step(particle, drift_rate, time_step_size) + t = t + 1 + + rt = (non_decision_time + t * time_step_size) + decision = 1 + if particle < -threshold: + decision = 0 + + return rt, decision + + +@ti.kernel +def simulate_many_ddms(starting_value: ti.f32, + non_decision_time: ti.f32, + drift_rate: ti.f32, + threshold: ti.f32, + time_step_size: ti.f32): + for i in rt: + rt[i], decision[i] = simulate_ddm(starting_value, non_decision_time, + drift_rate, threshold, time_step_size) + + +if __name__ == "__main__": + + ddm_params = dict(starting_value=0.0, non_decision_time=0.15, drift_rate=0.3, threshold=0.6, time_step_size=0.001) + + simulate_many_ddms(*list(ddm_params.values())) + rts = rt.to_numpy() + choices = decision.to_numpy() + + ti.sync() + rts = rt.to_numpy() + choices = decision.to_numpy() + valid = rts > 0.0 + rts = rts[valid] + choices = choices[valid] + + import time + t0 = time.time() + + NUM_TIMES = 50 + for i in range(NUM_TIMES): + simulate_many_ddms(*list(ddm_params.values())) + ti.sync() + rts = rt.to_numpy() + choices = decision.to_numpy() + valid = rts > 0.0 + rts = rts[valid] + choices = choices[valid] + + print(f"Elapsed: { 1000*((time.time() - t0) / NUM_TIMES)} milliseconds") \ No newline at end of file diff --git a/Scripts/Debug/ddm/taichi_test.py b/Scripts/Debug/ddm/taichi_test.py new file mode 100644 index 00000000000..ec7b8efd86e --- /dev/null +++ b/Scripts/Debug/ddm/taichi_test.py @@ -0,0 +1,225 @@ +#%% +import numpy as np +import pandas as pd +import math +import taichi as ti +import taichi_glsl as ts +import taichi_utils as tu + +from ddm import Model +from ddm.models import DriftConstant, NoiseConstant, BoundConstant, OverlayNonDecision, ICPoint +from ddm.functions import display_model +from psyneulink.core.components.functions.fitfunctions import simulation_likelihood, make_likelihood_function, MaxLikelihoodEstimator + + +ti.init(arch=ti.gpu) + +#%% +num_simulations = 1000000 +rt = ti.field(ti.f32, num_simulations) +decision = ti.field(ti.i32, num_simulations) +max_time = 3.0 + + +def ddm_pdf_analytical(drift_rate, threshold, starting_value, non_decision_time, noise=1.0, time_step_size=0.001): + + model = Model(name='Simple model', + drift=DriftConstant(drift=drift_rate), + noise=NoiseConstant(noise=noise), + bound=BoundConstant(B=threshold), + IC=ICPoint(x0=starting_value), + overlay=OverlayNonDecision(nondectime=non_decision_time), + dx=.001, dt=time_step_size, T_dur=3) + s = model.solve() + + return model.t_domain(), s.pdf_corr(), s.pdf_err() + + +@ti.func +def ddm_time_step(prev_value, drift_rate, time_step_size): + return prev_value + (tu.rand_normal() + drift_rate * time_step_size) * ti.sqrt(time_step_size) + + +@ti.func +def simulate_ddm(starting_value, non_decision_time, drift_rate, threshold, time_step_size): + particle = starting_value + t = 0 + while abs(particle) < threshold: + particle = ddm_time_step(particle, drift_rate, time_step_size) + t = t + 1 + + rt = (non_decision_time + t * time_step_size) + decision = 1 + if particle < -threshold: + decision = 0 + + return rt, decision + + +@ti.kernel +def simulate_many_ddms(starting_value: ti.f32, + non_decision_time: ti.f32, + drift_rate: ti.f32, + threshold: ti.f32, + time_step_size: ti.f32): + for i in rt: + rt[i], decision[i] = simulate_ddm(starting_value, non_decision_time, + drift_rate, threshold, time_step_size) + + +@ti.func +def lca_time_step(prev_value, prev_value_f, stimulus, gamma, leak, time_step_size): + drift = time_step_size * (stimulus - leak * prev_value + gamma @ prev_value_f) + return prev_value + (drift + tu.rand_normal2()) * ti.sqrt(time_step_size) + + +@ti.func +def simulate_lca(stimulus, competition, self_excitation, + leak, gain, starting_value, + threshold, non_decision_time, time_step_size): + gamma = ti.Matrix([[competition, self_excitation], [self_excitation, competition]], dt=ti.f32) + + pre_activation = ti.Vector([starting_value, starting_value], dt=ti.f32) + particle = tu.relu(pre_activation) + t = 0 + while particle.max() < threshold and t * time_step_size < max_time: + pre_activation = lca_time_step(pre_activation, particle, stimulus, gamma, leak, time_step_size) + particle = tu.relu(pre_activation) + t = t + 1 + + rt = (non_decision_time + t * time_step_size) + + # If the simulation exceeds the max time, we terminated early, set RT to negative to signal this + # is a failed simulation + if rt >= max_time: + rt = -1 + + # Figure out which threshold was crossed. + decision = 0 + if particle[0] >= threshold: + decision = 0 + + if particle[1] >= threshold: + decision = 1 + + # If multiple dimensions crossed the threshold at the same time then this is a failure case + # as well. With infinite precision this won't happen. + if particle[0] >= threshold and particle[1] >= threshold: + rt = -1 + + return rt, decision + + +stimulus = ti.Vector.field(2, dtype=float, shape=()) +stimulus[None] = [0.1, 0.2] + +@ti.kernel +def simulate_many_lcas(competition: ti.f32, + self_excitation: ti.f32, + leak: ti.f32, + gain: ti.f32, + starting_value: ti.f32, + threshold: ti.f32, + non_decision_time: ti.f32, + time_step_size: ti.f32): + stimulus_vec = stimulus[None] + for i in rt: + rt[i], decision[i] = simulate_lca(stimulus_vec, competition, self_excitation, + leak, gain, starting_value, + threshold, non_decision_time, time_step_size) + + +ddm_params = dict(starting_value=0.0, non_decision_time=0.14, + drift_rate=0.1, threshold=0.6, time_step_size=0.001) +lca_params = dict(competition=0.1, self_excitation=0.1, + leak=0.1, gain=1.0, starting_value=0.0, threshold=0.08, + non_decistion_time=0.3, time_step_size=0.0001) + + +simulate_many_ddms(*list(ddm_params.values())) +#simulate_many_lcas(*list(lca_params.values())) +rts = rt.to_numpy() +choices = decision.to_numpy() + +# import time +# t0 = time.time() +# for i in range(50): +# simulate_many_lcas(*list(lca_params.values())) +# rts = rt.to_numpy() +# choices = decision.to_numpy() +# print(f"Elapsed: {((time.time()-t0)/50.0)*1000} milliseconds") + +ti.sync() +rts = rt.to_numpy() +choices = decision.to_numpy() +valid = rts > 0.0 +rts = rts[valid] +choices = choices[valid] + +# import time +# t0 = time.time() +# +# NUM_TIMES = 50 +# for i in range(NUM_TIMES): +# simulate_many_ddms(*list(ddm_params.values())) +# rts_np = rts.to_numpy() +# +# print(f"Elapsed: { 1000*((time.time() - t0) / NUM_TIMES)} milliseconds") + + +#%% +import time +import matplotlib.pyplot as plt +import seaborn as sns +import boost_histogram as bh +import functools +import operator +from psyneulink.core.components.functions.fitfunctions import simulation_likelihood, make_likelihood_function, MaxLikelihoodEstimator + +rt_space = np.linspace(0, 3.0, num=3000) + +t0 = time.time() +# pdf0 = simulation_likelihood(np.column_stack((choices, rts)), categorical_dims=np.array([True, False]), +# exp_data=np.c_[np.zeros(len(rt_space)), rt_space]) +# pdf1 = simulation_likelihood(np.column_stack((choices, rts)), categorical_dims=np.array([True, False]), +# exp_data=np.c_[np.ones(len(rt_space)), rt_space]) + +hist = bh.Histogram(bh.axis.Integer(0, 2), bh.axis.Regular(3000, 0.0, 3.0)) +hist.fill(choices, rts) +areas = functools.reduce(operator.mul, hist.axes.widths) +density = hist.view() / hist.sum() / areas +pdf0 = density[0, :] +pdf1 = density[1, :] + +print(f"Elapsed: { 1000*(time.time() - t0)} milliseconds") + +df = pd.DataFrame(index=rt_space) +df[f'Correct KDE (dt={ddm_params["time_step_size"]})'] = pdf1 +df[f'Error KDE (dt={ddm_params["time_step_size"]})'] = pdf0 + + +# # Get the analytical +# t_domain, pdf_corr, pdf_err = ddm_pdf_analytical(**ddm_params) +# +# # Interpolate to common rt space +# from scipy.interpolate import interpn +# +# anal_df = pd.DataFrame(index=rt_space) +# anal_df[f"Correct Analytical"] = interpn((t_domain,), pdf_corr, rt_space, +# method='linear', bounds_error=False, fill_value=1e-10) +# anal_df[f"Error Analytical"] = interpn((t_domain,), pdf_err, rt_space, +# method='linear', bounds_error=False, fill_value=1e-10) +# +# df = pd.concat([anal_df, df]) + +fig, axes = plt.subplots(1, 2, sharex=True, sharey=True) +sns.lineplot(data=df.filter(regex='Correct'), ax=axes[0]) +sns.lineplot(data=df.filter(regex='Error'), ax=axes[1]) +plt.show() + +#%% + + + + + diff --git a/Scripts/Debug/ddm/taichi_utils.py b/Scripts/Debug/ddm/taichi_utils.py new file mode 100644 index 00000000000..e7a1099a0f7 --- /dev/null +++ b/Scripts/Debug/ddm/taichi_utils.py @@ -0,0 +1,72 @@ +import math +import taichi as ti +import taichi_glsl as ts + + +@ti.func +def rand_normal(): + """ + Generate a normally distributed random number with mean=0 and variance=1 + + Returns + ------- + A scalar randome number + """ + u0 = ti.random(ti.f32) + u1 = ti.random(ti.f32) + r = ti.sqrt(-2*ti.log(u0)) + theta = 2 * math.pi * u1 + r0 = r * ti.sin(theta) + #r1 = r * ti.cos(theta) + return r0 + +@ti.func +def rand_normal2(): + """ + Generate a normally distributed random number with mean=0 and variance=1 + + Returns + ------- + A scalar randome number + """ + u0 = ti.random(ti.f32) + u1 = ti.random(ti.f32) + r = ti.sqrt(-2*ti.log(u0)) + theta = 2 * math.pi * u1 + r0 = r * ti.sin(theta) + r1 = r * ti.cos(theta) + return ti.Vector([r0, r1]) + + + +@ti.func +def rand_normal_vec(): + v = ti.Vector([0.0, 0.0]) + # for i in ti.static(range(0, len(v), 2)): + # u0 = ti.random(ti.f32) + # u1 = ti.random(ti.f32) + # r = ti.sqrt(-2*ti.log(u0)) + # theta = 2 * math.pi * u1 + # r0 = r * ti.sin(theta) + # v[i] = r0 + # v[i+1] = r * ti.cos(theta) + + return v + + +@ti.pyfunc +def relu(v: ti.template()): + return (ti.abs(v) + v) / 2.0 + +@ti.pyfunc +def logistic(v: ti.template(), gain): + return 1.0 / (1.0 + ti.exp(-gain * v)) + + +@ti.func +def argmax(v: ti.template()): + maxval = v.max() + for i in ti.static(range(2)): + if v[i] == maxval: + return i + diff --git a/Scripts/Debug/ddm/wfpt.py b/Scripts/Debug/ddm/wfpt.py new file mode 100644 index 00000000000..20fafa9bd1e --- /dev/null +++ b/Scripts/Debug/ddm/wfpt.py @@ -0,0 +1,174 @@ +import numpy as np +import math +import logging +from numpy import exp, log, sin, sqrt, pi, tanh, cosh, sinh + +logger = logging.getLogger(__name__) + + +def coth(x): + """ + Hyperbolic cotangent, coth(x) = cosh(x) / sinh(x) + """ + return cosh(x) / sinh(x) + + +def __stdWfptLargeTime(t, w, nterms): + # large time expansion from navarro & fuss + logger.debug("Large time expansion, %i terms" % nterms) + piSqOv2 = 4.93480220054 + + terms = pi * np.fromiter((k * exp(-k ** 2 * t * piSqOv2) * sin(k * pi * w) for k in range(1, nterms)), np.float64) + + return np.sum(terms) + + +def __stdWfptSmallTime(t, w, nterms): + # small time expansion navarro & fuss (todo: gondan et al. improvement) + logger.debug("Small time expansion, %i terms" % nterms) + + fr = -math.floor((nterms - 1) / 2) + to = math.ceil((nterms - 1) / 2) + + terms = 1 / sqrt(2 * pi * t ** 3) * np.fromiter( + ((w + 2 * k) * exp(-((w + 2 * k) ** 2) / (2 * t)) for k in range(fr, to)), np.float64) + return np.sum(terms) + + +def wfpt_logp(t, c, x0, t0, a, z, eps=1e-10): + """ + Log probability of first passage time of double-threshold wiener process + (aka "pure DDM" of Bogacz et al.). Uses series truncation of Navarro & Fuss 2009 + """ + + # boundary sep is 2 * thresh + boundarySep = 2 * z + # initial condition is absolute, so to make it relative divide by boundarySep + relativeInitCond = ((x0 + z) / boundarySep) + # normalize time + normT = (t - t0) / (boundarySep ** 2) + + # if t is below NDT, or x0 is outside bounds, probability of any rt is 0 + if normT < 0 or x0 > z or x0 < -z: + return -np.inf + + if c == 1: # by default return hit of lower bound, so if resp is correct flip + a = -a + relativeInitCond = 1 - relativeInitCond + + largeK = np.int(sqrt((-2 * log(pi * normT * eps)) / (pi ** 2 * normT))) + smallK = 2 + sqrt(-2 * normT * log(2 * eps * sqrt(2 * pi * normT))) + if largeK < smallK: + # make sure eps is small enough for for bound to be valid + if eps > (1 / (2 * sqrt(2 * pi * normT))): + smallK = 2 + p = __stdWfptLargeTime(normT, relativeInitCond, math.ceil(largeK)) + else: + # make sure eps is small enough for for bound to be valid + if eps > (1 / (pi * sqrt(normT))): + smallK = math.ceil((1 / (pi * sqrt(t)))) + p = __stdWfptSmallTime(normT, relativeInitCond, math.ceil(smallK)) + + # scale from the std case to whatever is our actual + scaler = (1 / boundarySep ** 2) * exp(-a * boundarySep * relativeInitCond - (a ** 2 * t / 2)) + + return scaler * p + #return log(scaler * p) + + +def __standardize_bogacz(x0, a, z, s): + """ + Standardize the way Bogacz et al. 2006 do: + threshold/drift ratio, signal to noise ratio, x0 to drift ratio + """ + ztilde = z / a + atilde = (a / s) ** 2 + x0tilde = x0 / a + return ztilde, atilde, x0tilde + + +def __standardize_srivastava(x0, a, z, s): + """ + Standardize the way Srivastava et al. (submitted) do: + normalized threshold, normalized starting point + """ + kz = (a * z) / (s * s) + kx = (a * x0) / (s * s) + return kz, kx + + +def __simulate_wfpt_single(x0, t0, a, z, dt): + particle = x0 + t = 0; + while abs(particle) < z: + particle = particle + np.random.normal(loc=a * dt, scale=sqrt(dt)) + t = t + 1 + return t0 + t * dt if particle > z else -t0 - t * dt + + +def simulate_wfpt(x0, t0, a, z, dt=0.01): + """ + Draws from the Wiener first passage time. Slow and imprecise, + used primarily for testing. Production usage of this function + is not recommended. + """ + # promote if we get scalars (probably not the best way to do this) + x0 = np.atleast_1d(x0) + t0 = np.atleast_1d(t0) + a = np.atleast_1d(a) + z = np.atleast_1d(z) + + return np.fromiter((__simulate_wfpt_single(_x0, _t0, _a, _z, dt) for _x0, _t0, _a, _z in zip(x0, t0, a, z)), + np.float64) + + +def wfpt_rt(x0, t0, a, z, s=1): + """ + Expected first passage time of a two-boundary wiener process. + Uses Bogacz et al. 2006 expression for nonzero drift, + Srivastava et al. expression for zero-drift. + """ + if abs(a) < 1e-8: # a close to 0 (avoid float comparison) + # use expression for limit a->0 from Srivastava et al. 2016 + return t0 + (z ** 2 - x0 ** 2) / (s ** 2) + # expression from Bogacz et al. 2006 for nonzero drift + else: + ztilde, atilde, x0tilde = __standardize_bogacz(x0, a, z, s) + return ztilde * tanh(ztilde * atilde) + ((2 * ztilde * (1 - exp(-2 * x0tilde * atilde))) / ( + exp(2 * ztilde * atilde) - exp(-2 * ztilde * atilde)) - x0tilde) + t0 + + +def wfpt_er(x0, t0, a, z, s=1): + """ + Crossing probability in the -drift direction (aka "Error rate") for wiener process. + Uses Bogacz et al. 2006 expression for nonzero drift, Srivastava et al. + expression for zero-drift. + """ + if abs(a) < 1e-8: # a close to 0 (avoid float comparison) + # use expression for limit a->0 from Srivastava et al. 2016 + return (z - x0) / (2 * z) + # expression from Bogacz et al. 2006 for nonzero drift + else: + ztilde, atilde, x0tilde = __standardize_bogacz(x0, a, z, s) + return 1 / (1 + exp(2 * ztilde * atilde)) - ( + (1 - exp(-2 * x0 * atilde)) / (exp(2 * ztilde * atilde) - exp(-2 * ztilde * atilde))) + + +def wfpt_dt_upper(x0, t0, a, z, s=1): + """ + Expected conditional first passage time, conditioned on crossing threshold + in the +drift direction (aka "upper" or "correct") + """ + + if abs(a) < 1e-8: # a close to 0 (avoid float comparison) + return (4 * x ** 2 - (z + x0) ** 2) / (3 * s ** 2) + kz, kx = __standardize_srivastava(x0, a, z, s) + return (s ** 2) / (a ** 2) * (2 * kz * coth(2 * kz) - (kx + kz) * coth(kx + kz)) + + +def wfpt_dt_lower(x0, t0, a, z, s=1): + """ + Expected conditional first passage time, conditioned on crossing threshold + in the -drift direction (aka "lower" or "error") + """ + return wfpt_dt_upper(-x0, t0, a, z, s) \ No newline at end of file diff --git a/Scripts/Debug/lca/onnx_lca.py b/Scripts/Debug/lca/onnx_lca.py new file mode 100644 index 00000000000..3ccab45bbd7 --- /dev/null +++ b/Scripts/Debug/lca/onnx_lca.py @@ -0,0 +1,277 @@ +import torch +import onnx +import onnxruntime as ort + +from typing import Union, Iterable, Tuple, Optional, Callable, Any + + +if torch.cuda.is_available(): + def_dev = torch.device("cuda:0") +else: + def_dev = torch.device("cpu") + + +def scalar(val: torch.Tensor): + """Helper function to get scalars as Python numbers""" + return val.item() + + +class LCALayer(torch.nn.Module): + def __init__( + self, + threshold: Union[float, torch.FloatTensor, None] = torch.tensor(1.0), + leak: Union[torch.FloatTensor, float] = torch.tensor(0.1), + competition: Union[torch.FloatTensor, float] = torch.tensor(0.1), + self_excitation: Union[torch.FloatTensor, float] = torch.tensor(0.0), + non_decision_time: Union[torch.FloatTensor, float] = torch.tensor(0.0), + activation_function: Callable = torch.relu, + noise: Union[float, torch.Tensor, None] = torch.tensor(1.0), + time_step_size: Union[torch.FloatTensor, float] = torch.tensor(0.01), + ): + """ + An implementation of a Leaky Competing Accumulator as a layer. Each call to forward of this module only + implements one time step of the integration. See module LCAModel if you want to simulate an LCA to completion. + + Args: + threshold: The threshold that accumulators must reach to stop integration. If None, accumulators will + never stop integrating even when the pass the threshold. + leak: The decay rate, which reflects leakage of the activation. + competition: The weight to apply for inhibitory influence from other activations. Positive values lead + to inhibitory effects from other accumulators. + self_excitation: The weight to apply for the scaling factor for the recurrent excitation + non_decision_time: The time that should be added to reaction times to account for stimulus encoding and + response generation. This parameter shifts the results reactions times by and offset. This parameter + is not actually used by LCALayer since the forward method only computes a timestep at a time. However, + this is a common LCA model parameter so it should be stored with the others. It is added to final + reaction time generated from LCAModel.forward. + activation_function: The non-linear function to apply to pre activities to get activities. This is + torch.relu by default, but can be any callable. + noise: The standard deviation of the Gaussian noise added to each particles position at each time step. + time_step_size: The time step size (in seconds) for the integration process. + + """ + super().__init__() + + require_grad = False + + self.leak = leak + self.competition = competition + self.self_excitation = self_excitation + self.noise = noise + self.time_step_size = time_step_size + self.non_decision_time = non_decision_time + self._sqrt_step_size = torch.sqrt( + torch.tensor(0.001, requires_grad=require_grad).to(leak.device) + ) + self.threshold = threshold + self.activation_function = activation_function + + def forward( + self, + ff_input: torch.Tensor, + pre_activities: torch.Tensor, + activities: torch.Tensor, + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """ + Compute one time step of integration for a batch of independent leaky competing accumulator + instances. + + Args: + ff_input: The current input activity for the accumulators + pre_activities: The activity of the accumulator without the application of the non-linearity + activation_func. A 2D tensors of shape [batch_size, num_accumulators]. batch_size in + this case is each independent accumulator model instance. Or in other words, a simulation of the model. + activities: The current activity of each accumulator instance. This is the value after + the non-linearity activation_func has been applied to pre_activities. A 2D tensors of shape + [batch_size, num_accumulators]. batch_size in this case is each independent accumulator + model instance. Or in other words, a simulation of the model. + + Returns: + The current output activities of the accumulators, of same shape as activities. + """ + num_simulations, num_lca_dim = activities.shape + + dev = self.leak.device + + # Mark all accumulators as active by default + active = torch.ones(size=(num_simulations, 1), device=dev) + + # If threshold is provided, only integrate accumulators until they reach the threshold. + # if self.threshold is not None: + # active = torch.all( + # torch.abs(activities) < self.threshold, dim=1, keepdim=True + # ) + + # Construct a gamma matrix, this is multiplied by each accumulator vector to compute + # the competitive inhibition and self excitation between units. + gamma = (torch.eye(num_lca_dim, device=dev) == 0.0) * self.competition + gamma.fill_diagonal_(-self.self_excitation) + + # Perform one time step of the integration + pre_activities = ( + pre_activities + + (ff_input - self.leak * pre_activities - torch.matmul(activities, gamma)) + * active + * self.time_step_size + ) + + # If standard deviation of noise is provided. Generate a noise for each accumulator. + # Only active accumulators will get noise + if self.noise is not None: + dw = torch.normal( + mean=torch.zeros(activities.size(), device=dev), + std=active * self.noise * torch.ones(activities.size(), device=dev), + ) + pre_activities = pre_activities + dw * self._sqrt_step_size + + # Calculate the post activation function activities. Don't overwrite pre_activities, we will need these for + # the next timestep. + activities = self.activation_function(pre_activities) + + return pre_activities, activities, active + + +class LCAModel(torch.nn.Module): + def __init__( + self, + lca_layer: LCALayer, + num_lca_dim: int, + num_simulations: int = 10000, + num_time_steps: int = 3000, + ): + """ + A model that simulates a leaky competing accumulator model (Usher and McClelland). + + References: + + Usher M, McClelland JL. The time course of perceptual choice: the leaky, competing accumulator model. + Psychol Rev. 2001 Jul;108(3):550-92. doi: 10.1037/0033-295x.108.3.550. PMID: 11488378. + + Args: + lca_layer: The LCALayer that computes the integration for each timestep. + num_lca_dim: The number of LCA units or accumulators. + num_simulations: The number of parallel independent simulations to run. + num_time_steps: The total number of time steps to run. + + """ + + super().__init__() + + self.lca_layer = lca_layer + self.num_lca_dim = num_lca_dim + self.num_simulations = num_simulations + self.num_time_steps = num_time_steps + + def forward(self, ff_input: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]: + """ + + Args: + ff_input: A vector specifying the feed forward input for each accumulator. + This is typically a representation of the stimulus, task, or both. + + Returns: + A tuple with two vectors, the activations before and after applying the non-linear + activation function. + """ + dev = ff_input.device + + # Mark all accumulators as active by default + active = torch.ones(size=[int(self.num_simulations), 1], device=dev) + + pre_activities = torch.zeros( + size=[int(self.num_simulations), int(self.num_lca_dim)], device=dev + ) + activities = torch.zeros( + size=[int(self.num_simulations), int(self.num_lca_dim)], device=dev + ) + + rts = torch.zeros(size=[int(self.num_simulations), 1], device=dev) + + # Simulate N time steps of the model. This could be done with a while(active) type loop but this is slightly + # faster actually on the GPU. + for time_i in range(int(self.num_time_steps)): + + # Compute the LCA activities + pre_activities, activities, active = self.lca_layer( + ff_input=ff_input, pre_activities=pre_activities, activities=activities + ) + + # Only increment reaction time for active simulations + rts = rts + active + + # Convert the time step index to actual time + rts = rts * self.lca_layer.time_step_size + + # Include the non-decision time in the reaction time. + rts = rts + self.lca_layer.non_decision_time + + # Figure out which accumulator crossed the threshold, this is the decision + torch.max(activities, dim=1) + + max_values, decisions = torch.max(activities, dim=1, keepdim=True) + + # Find any simulations that had multiple accumulators cross the threshold at the same time. + # Exclude these for simplicity. + # good = torch.logical_and( + # torch.sum(activities == max_values, dim=1) == 1, ~torch.squeeze(active) + # ) + # decisions = decisions[good] + # rts = rts[good] + + return rts, decisions + +if __name__ == "__main__": + + lca_params = dict( + threshold=0.06, + leak=10.0, + competition=0.0, + self_excitation=6.2, + non_decision_time=0.0, + noise=0.1, + # noise=None, + time_step_size=0.001, + ) + + # Convert all the lca parameters to torch.FloatTensors + lca_params = {k: torch.tensor(v, device=def_dev) for k, v in lca_params.items()} + + + lca = LCAModel( + lca_layer=LCALayer( + **lca_params, + activation_function=torch.relu, + ), + num_lca_dim=torch.tensor(2), + num_simulations=torch.tensor(50000), + num_time_steps=torch.tensor(3000), + ) + + # Compile things for a bit of a performance boost + lca = torch.jit.script(lca) + + # Create some input for the LCA, typically this would be generated from another part of the model + # that processes stimulus or tasks information into an N sized vector, where N is the number of + # dimensions in the LCA accumulator. + input_array = [1.02, 1.02 + 0.02] + ff_input = torch.Tensor(input_array).to(def_dev) + + # Run things to get some example outputs. + outputs = lca(ff_input) + + torch.onnx.export(lca, # model being run + ff_input, # model input (or a tuple for multiple inputs) + "lca.onnx", # where to save the model (can be a file or file-like object) + export_params=True, # store the trained parameter weights inside the model file + opset_version=13, # the ONNX version to export the model to + do_constant_folding=False, # whether to execute constant folding for optimization + input_names=['ff_input'], # the model's input names + output_names=['rts', 'decisions'], # the model's output names + #operator_export_type=torch.onnx.OperatorExportTypes.ONNX_ATEN_FALLBACK, + example_outputs=outputs, + # dynamic_axes={'input': {0: 'batch_size'}, # variable length axes + # 'output': {0: 'batch_size'}} + ) + + onnx_model = onnx.load("lca.onnx") + onnx.checker.check_model(onnx_model) diff --git a/Scripts/Debug/lca/pytorch_lca.py b/Scripts/Debug/lca/pytorch_lca.py new file mode 100644 index 00000000000..cb70c6639ad --- /dev/null +++ b/Scripts/Debug/lca/pytorch_lca.py @@ -0,0 +1,447 @@ +import torch +import numpy as np +import time + +import matplotlib.pyplot as plt +import seaborn as sns +import pandas as pd + + +from typing import Union, Iterable, Tuple, Optional, Callable + +import psyneulink as pnl + + +if torch.cuda.is_available(): + def_dev = "cuda:0" +else: + def_dev = "cpu" + + +class LCALayer(torch.nn.Module): + def __init__( + self, + threshold: Union[float, None] = 1.0, + leak: float = 0.1, + competition: float = 0.1, + self_excitation: float = 0.0, + non_decision_time: float = 0.0, + activation_function: Callable = torch.relu, + noise: Union[float, torch.Tensor, None] = 1.0, + time_step_size: float = 0.01, + dev: Optional[Union[str, torch.device]] = "cpu" + ): + """ + An implementation of a Leaky Competing Accumulator as a layer. Each call to forward of this module only + implements one time step of the integration. See module LCAModel if you want to simulate an LCA to completion. + + Args: + threshold: The threshold that accumulators must reach to stop integration. If None, accumulators will + never stop integrating even when the pass the threshold. + leak: The decay rate, which reflects leakage of the activation. + competition: The weight to apply for inhibitory influence from other activations. Positive values lead + to inhibitory effects from other accumulators. + self_excitation: The weight to apply for the scaling factor for the recurrent excitation + non_decision_time: The time that should be added to reaction times to account for stimulus encoding and + response generation. This parameter shifts the results reactions times by and offset. This parameter + is not actually used by LCALayer since the forward method only computes a timestep at a time. However, + this is a common LCA model parameter so it should be stored with the others. It is added to final + reaction time generated from LCAModel.forward. + activation_function: The non-linear function to apply to pre activities to get activities. This is + torch.relu by default, but can be any callable. + noise: The standard deviation of the Gaussian noise added to each particles position at each time step. + time_step_size: The time step size (in seconds) for the integration process. + dev: Device to run compute on. + + """ + super().__init__() + + require_grad = False + + self.leak = leak + self.competition = competition + self.self_excitation = self_excitation + self.noise = noise + self.time_step_size = time_step_size + self.non_decision_time = non_decision_time + self._sqrt_step_size = torch.sqrt( + torch.tensor(0.001, requires_grad=require_grad).to(dev) + ) + self.threshold = threshold + self.activation_function = activation_function + self.dev = dev + + def forward( + self, + ff_input: torch.Tensor, + pre_activities: torch.Tensor, + activities: torch.Tensor, + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """ + Compute one time step of integration for a batch of independent leaky competing accumulator + instances. + + Args: + ff_input: The current input activity for the accumulators + pre_activities: The activity of the accumulator without the application of the non-linearity + activation_func. A 2D tensors of shape [batch_size, num_accumulators]. batch_size in + this case is each independent accumulator model instance. Or in other words, a simulation of the model. + activities: The current activity of each accumulator instance. This is the value after + the non-linearity activation_func has been applied to pre_activities. A 2D tensors of shape + [batch_size, num_accumulators]. batch_size in this case is each independent accumulator + model instance. Or in other words, a simulation of the model. + + Returns: + The current output activities of the accumulators, of same shape as activities. + """ + num_simulations, num_lca_dim = activities.shape + + # Mark all accumulators as active by default + active = torch.ones(size=(num_simulations, 1), device=self.dev) + + # If threshold is provided, only integrate accumulators until they reach the threshold. + if self.threshold is not None: + active = torch.all( + torch.abs(activities) < self.threshold, dim=1, keepdim=True + ) + + # Construct a gamma matrix, this is multiplied by each accumulator vector to compute + # the competitive inhibition and self excitation between units. + gamma = (torch.eye(num_lca_dim, device=self.dev) == 0.0) * self.competition + gamma.fill_diagonal_(-self.self_excitation) + + # Perform one time step of the integration + pre_activities = ( + pre_activities + + (ff_input - self.leak * pre_activities - torch.matmul(activities, gamma)) + * active + * self.time_step_size + ) + + # If standard deviation of noise is provided. Generate a noise for each accumulator. + # Only active accumulators will get noise + if self.noise is not None: + dw = torch.normal( + mean=torch.zeros(activities.size(), device=self.dev), + std=active * self.noise * torch.ones(activities.size(), device=self.dev), + ) + pre_activities = pre_activities + dw * self._sqrt_step_size + + # Calculate the post activation function activities. Don't overwrite pre_activities, we will need these for + # the next timestep. + activities = self.activation_function(pre_activities) + + return pre_activities, activities, active + + +class LCAModel(torch.nn.Module): + def __init__( + self, + lca_layer: LCALayer, + num_lca_dim: int, + num_simulations: int = 10000, + num_time_steps: int = 3000, + save_activities: bool = False, + dev: Optional[Union[str, torch.device]] = "cpu" + ): + """ + A model that simulates a leaky competing accumulator model (Usher and McClelland). + + References: + + Usher M, McClelland JL. The time course of perceptual choice: the leaky, competing accumulator model. + Psychol Rev. 2001 Jul;108(3):550-92. doi: 10.1037/0033-295x.108.3.550. PMID: 11488378. + + Args: + lca_layer: The LCALayer that computes the integration for each timestep. + num_lca_dim: The number of LCA units or accumulators. + num_simulations: The number of parallel independent simulations to run. + num_time_steps: The total number of time steps to run. + save_activities: Should activities be saved. If True, make sure the number of simulations is low. + + """ + + super().__init__() + + self.lca_layer = lca_layer + self.num_lca_dim = num_lca_dim + self.num_simulations = num_simulations + self.num_time_steps = num_time_steps + self.save_activities = save_activities + self.dev = dev + + def forward(self, ff_input: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]: + """ + + Args: + ff_input: A vector specifying the feed forward input for each accumulator. + This is typically a representation of the stimulus, task, or both. + + Returns: + A tuple with two vectors, the activations before and after applying the non-linear + activation function. + """ + + # Mark all accumulators as active by default + active = torch.ones(size=(self.num_simulations, 1), device=self.dev) + + if self.save_activities: + pre_activities = torch.zeros( + size=(self.num_simulations, self.num_lca_dim, self.num_time_steps + 1), + device=self.dev, + ) + activities = torch.zeros( + size=(self.num_simulations, self.num_lca_dim, self.num_time_steps + 1), + device=self.dev, + ) + else: + pre_activities = torch.zeros( + size=(self.num_simulations, self.num_lca_dim), device=self.dev + ) + activities = torch.zeros( + size=(self.num_simulations, self.num_lca_dim), device=self.dev + ) + + rts = torch.zeros(size=(self.num_simulations, 1), device=self.dev) + + # Simulate N time steps of the model. This could be done with a while(active) type loop but this is slightly + # faster actually on the GPU. + for time_i in range(self.num_time_steps): + + # Compute the LCA activities + if self.save_activities: + ( + pre_activities[:, :, time_i + 1], + activities[:, :, time_i + 1], + active, + ) = self.lca_layer( + ff_input=ff_input, + pre_activities=pre_activities[:, :, time_i], + activities=activities[:, :, time_i], + ) + else: + pre_activities, activities, active = self.lca_layer( + ff_input=ff_input, pre_activities=pre_activities, activities=activities + ) + + # Only increment reaction time for active simulations + rts = rts + active + + # Convert the time step index to actual time + rts = rts * self.lca_layer.time_step_size + + # Include the non-decision time in the reaction time. + rts = rts + self.lca_layer.non_decision_time + + # Figure out which accumulator crossed the threshold, this is the decision + torch.max(activities, dim=1) + + if not self.save_activities: + max_values, decisions = torch.max(activities, dim=1, keepdim=True) + + # Find any simulations that had multiple accumulators cross the threshold at the same time. + # Exclude these for simplicity. + good = torch.logical_and( + torch.sum(activities == max_values, dim=1) == 1, ~torch.squeeze(active) + ) + decisions = decisions[good] + rts = rts[good] + + else: + decisions = torch.argmax(activities[:, :, self.num_time_steps], dim=1) + + if self.save_activities: + return pre_activities, activities + else: + return rts, decisions + + +def make_pnl_lca( + num_lca_dim: int = 2, + threshold: Union[float, None] = 1.0, + leak: float = 0.1, + competition: float = 0.1, + self_excitation: float = 0.0, + non_decision_time: float = 0.0, + activation_function: Callable = pnl.ReLU, + noise: Union[float, torch.Tensor, None] = 1.0, + time_step_size: float = 0.01, +): + + if noise is not None: + noise_func = lambda: rng.normal(loc=0.0, scale=noise) + else: + noise_func = 0.0 + + lca = pnl.LCAMechanism( + default_variable=[[0.0 for _ in range(num_lca_dim)]], + size=num_lca_dim, + threshold=threshold, + function=activation_function, + leak=leak, + competition=competition, + self_excitation=self_excitation, + noise=noise_func, + time_step_size=time_step_size, + termination_measure=max, + termination_comparison_op=">=", + reset_stateful_function_when=pnl.AtTrialStart(), + # execute_until_finished=True, + # max_executions_before_finished=sys.maxsize, + name="LCA", + ) + + lca.set_log_conditions([pnl.RESULT]) + + comp = pnl.Composition(name="LCA-Comp") + comp.add_node(lca) + + return comp, lca + + +if __name__ == "__main__": + + # Set to true if you want to plot an example histories of activations + save_activities = False + + if save_activities: + num_simulations = 10 + else: + num_simulations = 50000 + + lca_params = dict( + threshold=0.06, + leak=10.0, + competition=0.0, + self_excitation=6.2, + non_decision_time=0.0, + noise=0.1, + # noise=None, + time_step_size=0.001, + ) + + lca = LCAModel( + lca_layer=LCALayer( + **lca_params, + activation_function=torch.relu, + dev=def_dev + ), + num_lca_dim=2, + num_simulations=num_simulations, + num_time_steps=3000, + save_activities=save_activities, + dev=def_dev + ) + + # Compile things for a bit of a performance boost + lca = torch.jit.script(lca) + + rng = np.random.RandomState(seed=42) + comp, pnl_lca_mech = make_pnl_lca( + num_lca_dim=2, activation_function=pnl.ReLU, **lca_params + ) + + # Create some input for the LCA, typically this would be generated from another part of the model + # that processes stimulus or tasks information into an N sized vector, where N is the number of + # dimensions in the LCA accumulator. + input_array = [1.02, 1.02 + 0.02] + input_pnl = {pnl_lca_mech: [input_array]} + ff_input = torch.Tensor(input_array).to(def_dev) + + # Run the PNL LCA + comp.run(input_pnl, execution_mode=pnl.ExecutionMode.Python, num_trials=10) + pnl_results = comp.results + + # Get the LCA activities from the log if running in non-compiled mode. Just get one trial's worth + pnl_activities = np.array( + [ + t.value.tolist() + for t in pnl_lca_mech.log.get_logged_entries()["RESULT"]["LCA-Comp"] + if t.time.trial == 0 + ] + ) + + # Warm things up before running things for timing + lca(ff_input) + lca(ff_input) + + t0 = time.time() + + # Run things ten times so we can get a rough average execution time. + for i in range(10): + # Run many independent simulations of the same LCA model + if save_activities: + pre_activities, activities = lca(ff_input=ff_input) + activities = activities.to("cpu").numpy() + pre_activities = pre_activities.to("cpu").numpy() + else: + rts, decisions = lca(ff_input=ff_input) + rts = rts.to("cpu").numpy().flatten() + decisions = decisions.to("cpu").numpy().flatten() + + t1 = time.time() + print(f"Average Elapsed: {(t1-t0) / 10.0} seconds") + + + if save_activities: + pre_activities = np.transpose(pre_activities[0, :, :]) + activities = np.transpose(activities[0, :, :]) + rt_i = max(np.argmax(activities, axis=0)) + 1 + activities = activities[0:rt_i, :] + pre_activities = pre_activities[0:rt_i, :] + preact_df = pd.DataFrame( + pre_activities, columns=[f"{i}" for i in range(pre_activities.shape[1])] + ) + preact_df["name"] = "pre activation" + preact_df["t"] = np.arange(rt_i) * lca.lca_layer.time_step_size + act_df = pd.DataFrame( + activities, columns=[f"{i}" for i in range(activities.shape[1])] + ) + act_df["name"] = "post activation" + act_df["t"] = np.arange(rt_i) * lca.lca_layer.time_step_size + results = pd.concat([preact_df, act_df]) + results = pd.melt(results, id_vars=["name", "t"], var_name="lca_unit") + + # Add the PNL results + for i in range(lca.num_lca_dim): + results = pd.concat( + [ + results, + pd.DataFrame( + { + "name": "PNL post activation", + "t": (np.arange(pnl_activities.shape[0]) + 1) + * lca.lca_layer.time_step_size, + "lca_unit": str(i), + "value": pnl_activities[:, i], + } + ), + ] + ) + + #%% + g = sns.FacetGrid( + results[results["name"].str.contains("post activation")], + col="lca_unit", + hue="name", + ) + g.map_dataframe(sns.lineplot, x="t", y="value") + g.set_axis_labels("Time (s)", "Activity") + g.add_legend() + + ax1, ax2 = g.axes[0] + + ax1.axhline(lca.lca_layer.threshold, ls="--") + ax2.axhline(lca.lca_layer.threshold, ls="--") + + ax1.axvline((rt_i - 1) * lca.lca_layer.time_step_size, ls="--") + ax2.axvline((rt_i - 1) * lca.lca_layer.time_step_size, ls="--") + + plt.show() + #%% + + else: + results = pd.DataFrame({"reaction_time": rts, "decision": decisions}) + sns.kdeplot(data=results, x="reaction_time", hue="decision") + plt.xlim([0.0, 3.5]) + plt.show() diff --git a/Scripts/Debug/markus_test_umemoto.py b/Scripts/Debug/markus_test_umemoto.py index 1ce9434553e..973c7d1b3c6 100644 --- a/Scripts/Debug/markus_test_umemoto.py +++ b/Scripts/Debug/markus_test_umemoto.py @@ -15,7 +15,7 @@ # EVC params for Umemoto et al -t0 = 0.2 +non_decision_time = 0.2 c = 0.19 thresh = 0.21 x_0 = 0 # starting point @@ -74,8 +74,8 @@ # drift_rate=(0.3), threshold=(thresh), noise=(c), - starting_point=(x_0), - t0=t0 + starting_value=(x_0), + non_decision_time=non_decision_time ),name='Decision', output_ports=[ pnl.DECISION_VARIABLE, @@ -86,7 +86,7 @@ pnl.VARIABLE: (pnl.OWNER_VALUE, 2), pnl.FUNCTION: psyneulink.core.components.functions.nonstateful.transferfunctions.Linear(0, slope=1.0, intercept=1) } - ],) #drift_rate=(1.0),threshold=(0.2645),noise=(0.5),starting_point=(0), t0=0.15 + ],) #drift_rate=(1.0),threshold=(0.2645),noise=(0.5),non_decision_time=(0), non_decision_time=0.15 print(Decision.execute([1])) diff --git a/Scripts/Debug/new_umemoto.py b/Scripts/Debug/new_umemoto.py index 621b0b3744a..9af1657ce5d 100644 --- a/Scripts/Debug/new_umemoto.py +++ b/Scripts/Debug/new_umemoto.py @@ -13,7 +13,7 @@ # EVC params for Umemoto et al -t0 = 0.2 +non_decision_time = 0.2 c = 0.19 thresh = 0.21 x_0 = 0 # starting point @@ -55,8 +55,8 @@ # drift_rate=(0.1170), threshold=(thresh), noise=(c), - starting_point=(x_0), - t0=t0 + starting_value=(x_0), + non_decision_time=non_decision_time ),name='Decision', output_ports=[ pnl.DECISION_VARIABLE, @@ -67,7 +67,7 @@ pnl.VARIABLE: (pnl.OWNER_VALUE, 2), pnl.FUNCTION: pnl.Linear(0, slope=1.0, intercept=1) } - ],) #drift_rate=(1.0),threshold=(0.2645),noise=(0.5),starting_point=(0), t0=0.15 + ],) #drift_rate=(1.0),threshold=(0.2645),noise=(0.5),non_decision_time=(0), non_decision_time=0.15 Decision.set_log_conditions('InputPort-0') @@ -114,7 +114,7 @@ Umemoto_comp.add_model_based_optimizer(optimizer=pnl.OptimizationControlMechanism(agent_rep=Umemoto_comp, state_features={pnl.SHADOW_EXTERNAL_INPUTS: [Target_Stim, Distractor_Stim, Reward]}, - state_feature_functions=pnl.AdaptiveIntegrator(rate=1.0), + state_feature_function=pnl.AdaptiveIntegrator(rate=1.0), objective_mechanism=pnl.ObjectiveMechanism(monitor_for_control=[Reward, (Decision.output_ports[pnl.PROBABILITY_UPPER_THRESHOLD], 1, -1)], ), diff --git a/Scripts/Debug/predator_prey_opt/predator_prey_dmt.py b/Scripts/Debug/predator_prey_opt/predator_prey_dmt.py index 0eb89fb2ed7..9d862001c2e 100644 --- a/Scripts/Debug/predator_prey_opt/predator_prey_dmt.py +++ b/Scripts/Debug/predator_prey_opt/predator_prey_dmt.py @@ -195,7 +195,7 @@ def get_action(variable=[[0, 0], [0, 0], [0, 0]]): # ************************************** CONOTROL APPARATUS *********************************************************** self.ocm = OptimizationControlMechanism(name='EVC', state_features=[self.prey_pred_trial_input_mech, self.single_prey_trial_input_mech, self.double_prey_trial_input_mech], - # state_feature_functions=FEATURE_FUNCTION, + # state_feature_function=FEATURE_FUNCTION, agent_rep=RegressionCFA( update_weights=BayesGLM(mu_0=-0.0, sigma_0=0.0001), prediction_terms=[PV.F, PV.C, PV.COST] @@ -416,21 +416,20 @@ def run_search(): import joblib import hypertunity as ht - #client = Client(scheduler_file='scheduler.json') - client = Client() + client = Client(scheduler_file='scheduler.json') + #client = Client() # Setup local cluster print(client) domain = ht.Domain({ "cost_rate": set([-.8]) }) - # with joblib.parallel_backend('dask'): - # with joblib.Parallel() as parallel: - # print("Doing the work ... ") - # results = parallel(joblib.delayed(run_games)(*domain.sample().as_namedtuple()) for s in range(1)) - # - # print(results) - run_games(-.8) + with joblib.parallel_backend('dask'): + with joblib.Parallel() as parallel: + print("Doing the work ... ") + results = parallel(joblib.delayed(run_games)(*domain.sample().as_namedtuple()) for s in range(1)) + + print(results) if __name__ == "__main__": run_search() diff --git a/Scripts/Debug/stability_flexibility/pytorch_lca.py b/Scripts/Debug/stability_flexibility/pytorch_lca.py new file mode 100644 index 00000000000..e9324755ac3 --- /dev/null +++ b/Scripts/Debug/stability_flexibility/pytorch_lca.py @@ -0,0 +1,303 @@ +import torch +import numpy as np +import time + +import matplotlib.pyplot as plt +import seaborn as sns +import pandas as pd + +from typing import Union, Iterable, Tuple, Optional, Callable + +if torch.cuda.is_available(): + dev = "cuda:0" +else: + dev = "cpu" + + +class LCALayer(torch.nn.Module): + def __init__(self, + threshold: Union[float, None] = 1.0, + leak: float = 0.1, + competition: float = 0.1, + self_excitation: float = 0.0, + non_decision_time: float = 0.0, + activation_function: Callable = torch.relu, + noise: Union[float, torch.Tensor, None] = 1.0, + time_step_size: float = 0.01): + """ + + Args: + threshold: The threshold that accumulators must reach to stop integration. If None, accumulators will + never stop integrating even when the pass the threshold. + leak: The decay rate, which reflects leakage of the activation. + competition: The weight to apply for inhibitory influence from other activations. Positive values lead + to inhibitory effects from other accumulators. + self_excitation: The weight to apply for the scaling factor for the recurrent excitation + non_decision_time: The time that should be added to reaction times to account for stimulus encoding and + response generation. This parameter shifts the results reactions times by and offset. This parameter + is not actually used by LCALayer since the forward method only computes a timestep at a time. However, + this is a common LCA model parameter so it should be stored with the others. It is added to final + reaction time generated from LCAModel.forward. + activation_function: The non-linear function to apply to pre activities to get activities. This is + torch.relu by default, but can be any callable. + noise: The standard deviation of the Gaussian noise added to each particles position at each time step. + time_step_size: The time step size (in seconds) for the integration process. + dev: Device to run compute on. + + """ + super(LCALayer, self).__init__() + + require_grad = False + + self.leak = leak + self.competition = competition + self.self_excitation = self_excitation + self.noise = noise + self.time_step_size = time_step_size + self.non_decision_time = non_decision_time + self._sqrt_step_size = torch.sqrt(torch.tensor(0.001, requires_grad=require_grad).to(dev)) + self.threshold = threshold + self.activation_function = activation_function + + def forward(self, + input: torch.Tensor, + pre_activities: torch.Tensor, + activities: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """ + Compute one time step of integration for a batch of independent leaky competing accumulator + instances. + + Args: + input: The current input activity for the accumulators + pre_activities: The activity of the accumulator without the application of the non-linearity + activation_func. A 2D tensors of shape [batch_size, num_accumulators]. batch_size in + this case is each independent accumulator model instance. Or in other words, a simulation of the model. + activities: The current activity of each accumulator instance. This is the value after + the non-linearity activation_func has been applied to pre_activities. A 2D tensors of shape + [batch_size, num_accumulators]. batch_size in this case is each independent accumulator + model instance. Or in other words, a simulation of the model. + + Returns: + The current output activities of the accumulators, of same shape as activities. + """ + dev = "cuda:0" + num_simulations, num_lca_dim = activities.shape + + # Mark all accumulators as active by default + active = torch.ones(size=(num_simulations, 1), device=dev) + + # If threshold is provided, only integrate accumulators until they reach the threshold. + if self.threshold is not None: + active = torch.all(torch.abs(activities) < self.threshold, dim=1, keepdim=True) + + # Construct a gamma matrix, this is multiplied by each accumulator vector to compute + # the competitive inhibition and self excitation between units. + gamma = (torch.eye(num_lca_dim, device=dev) == 0.0) * -self.competition + gamma.fill_diagonal_(self.self_excitation) + + # Perform one time step of the integration + pre_activities = pre_activities + (input - self.leak * pre_activities + + torch.sum(torch.matmul(activities, gamma), + dim=1, keepdim=True)) * active * self.time_step_size + + # If standard deviation of noise is provided. Generate a noise for each accumulator. + # Only active accumulators will get noise + if self.noise is not None: + dw = torch.normal(mean=torch.zeros(activities.size(), device=dev), + std=active * self.noise * torch.ones(activities.size(), device=dev)) + pre_activities = pre_activities + dw * self._sqrt_step_size + + # Calculate the post activation function activities. Don't overwrite pre_activities, we will need these for + # the next timestep. + activities = self.activation_function(pre_activities) + + return pre_activities, activities, active + + +class LCAModel(torch.nn.Module): + def __init__(self, + lca_layer: LCALayer, + num_lca_dim: int, + num_simulations: int = 10000, + num_time_steps: int = 3000, + save_activities: bool = False): + """ + A model that simulates a leaky competing accumulator model (Usher and McClelland). + + References: + + Usher M, McClelland JL. The time course of perceptual choice: the leaky, competing accumulator model. + Psychol Rev. 2001 Jul;108(3):550-92. doi: 10.1037/0033-295x.108.3.550. PMID: 11488378. + + Args: + lca_layer: The LCALayer that computes the integration for each timestep. + num_lca_dim: The number of LCA units or accumulators. + num_simulations: The number of parallel independent simulations to run. + num_time_steps: The total number of time steps to run. + save_activities: Should activities be saved. If True, make sure the number of simulations is low. + + """ + + super(LCAModel, self).__init__() + + self.lca_layer = lca_layer + self.num_lca_dim = num_lca_dim + self.num_simulations = num_simulations + self.num_time_steps = num_time_steps + self.save_activities = save_activities + + def forward(self, input: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]: + """ + + Args: + input: + + Returns: + + """ + dev = "cuda:0" + + # Mark all accumulators as active by default + active = torch.ones(size=(self.num_simulations, 1), device=dev) + + if self.save_activities: + pre_activities = torch.zeros(size=(self.num_simulations, + self.num_lca_dim, + self.num_time_steps + 1), device=dev) + activities = torch.zeros(size=(self.num_simulations, + self.num_lca_dim, + self.num_time_steps + 1), device=dev) + else: + pre_activities = torch.zeros(size=(self.num_simulations, self.num_lca_dim), device=dev) + activities = torch.zeros(size=(self.num_simulations, self.num_lca_dim), device=dev) + + rts = torch.zeros(size=(self.num_simulations, 1), device=dev) + + # Simulate N time steps of the model. + for time_i in range(self.num_time_steps): + + # Compute the LCA activities + if self.save_activities: + pre_activities[:, :, time_i+1], activities[:, :, time_i+1], active = \ + self.lca_layer(input=input, + pre_activities=pre_activities[:, :, time_i], + activities=activities[:, :, time_i]) + else: + pre_activities, activities, active = self.lca_layer(input=input, pre_activities=pre_activities, + activities=activities) + + # Only increment reaction time for active simulations + rts = rts + active + + # Convert the time step index to actual time + rts = rts * self.lca_layer.time_step_size + + # Include the non-decision time in the reaction time. + rts = rts + self.lca_layer.non_decision_time + + # Figure out which accumulator crossed the threshold, this is the decision + torch.max(activities, dim=1) + + if not self.save_activities: + max_values, decisions = torch.max(activities, dim=1, keepdim=True) + + # Find any simulations that had multiple accumulators cross the threshold at the same time. + # Exclude these for simplicity. + good = torch.logical_and(torch.sum(activities == max_values, dim=1) == 1, ~torch.squeeze(active)) + decisions = decisions[good] + rts = rts[good] + + else: + decisions = torch.argmax(activities[:, :, self.num_time_steps], dim=1) + + if self.save_activities: + return pre_activities, activities + else: + return rts, decisions + + +if __name__ == "__main__": + + save_activities = False + + if save_activities: + num_simulations = 100 + else: + num_simulations = 50000 + + lca = LCAModel(lca_layer=LCALayer( + threshold=0.16, + leak=1.22, + competition=5.53, + self_excitation=0.0, + non_decision_time=0.45, + activation_function=torch.relu, + noise=np.sqrt(0.1), + time_step_size=0.001), + num_lca_dim=2, + num_simulations=num_simulations, + num_time_steps=3000, + save_activities=save_activities + ) + + lca = torch.jit.script(lca) + + # Create some input for the LCA, typically this would be generated from another part of the model + # that processes stimulus or tasks information into an N sized vector, where N is the number of + # dimensions in the LCA accumulator. + input = torch.Tensor([1.02, 1.02+0.25]).to(dev) + + # rts, decisions = lca(input) + # average_rt = rts.mean() + # average_rt.backward() + + # Warm things up before running things for timing + lca(input) + lca(input) + + t0 = time.time() + + for i in range(10): + # Run many independent simulations of the same LCA model + if save_activities: + pre_activities, activities = lca(input=input) + activities = activities.to("cpu").numpy() + pre_activities = pre_activities.to("cpu").numpy() + else: + rts, decisions = lca(input=input) + rts = rts.to("cpu").numpy().flatten() + decisions = decisions.to("cpu").numpy().flatten() + + t1 = time.time() + print(f"Average Elapsed: {(t1-t0) / 10.0} seconds") + + if save_activities: + pre_activities = np.transpose(pre_activities[0, :, :]) + activities = np.transpose(activities[0, :, :]) + preact_df = pd.DataFrame(pre_activities, columns=[f"{i}" for i in range(pre_activities.shape[1])]) + preact_df['name'] = 'x' + preact_df['t'] = np.arange(3001) * lca.lca_layer.time_step_size + act_df = pd.DataFrame(activities, columns=[f"{i}" for i in range(activities.shape[1])]) + act_df['name'] = 'f(x)' + act_df['t'] = np.arange(3001) * lca.lca_layer.time_step_size + results = pd.concat([preact_df, act_df]) + results = pd.melt(results, id_vars=['name', 't'], var_name='lca_unit') + + g = sns.FacetGrid(results, col="name", hue="lca_unit") + g.map_dataframe(sns.lineplot, x="t", y="value") + g.set_axis_labels("Time (s)", "Activity") + g.add_legend() + + ax1, ax2 = g.axes[0] + + ax1.axhline(lca.lca_layer.threshold, ls='--') + ax2.axhline(lca.lca_layer.threshold, ls='--') + + plt.show() + + else: + results = pd.DataFrame({'reaction_time': rts, 'decision': decisions}) + sns.kdeplot(data=results, x='reaction_time', hue='decision') + plt.xlim([0.0, 3.5]) + plt.show() + diff --git a/Scripts/Debug/stability_flexibility/pytorch_stability_flexibility.py b/Scripts/Debug/stability_flexibility/pytorch_stability_flexibility.py new file mode 100644 index 00000000000..83b11ef75fd --- /dev/null +++ b/Scripts/Debug/stability_flexibility/pytorch_stability_flexibility.py @@ -0,0 +1,133 @@ +from typing import Union, Iterable, Tuple, Optional, Callable + +import numpy as np +import torch + +from pytorch_lca import LCALayer + +if torch.cuda.is_available(): + dev = "cuda:0" +else: + dev = "cpu" + + +class DriftDiffusionModel(torch.nn.Module): + def forward(self, + activities: torch.Tensor, + rate: float = 1.0, + threshold: float = 1.0, + noise: float = 1.0, + time_step_size: float = 0.01) -> Tuple[torch.Tensor, torch.Tensor]: + + """ + A model that simulates many instances of a simple noisy drift diffusion model in parallel. + + Args: + activities: The current actitivies of the DDM + rate: The drift rate for each particle. + threshold: The threshold that a particle must reach to stop integration. + noise: The standard deviation of the Gaussian noise added to each particles position at each time step. + time_step_size: The time step size (in seconds) for the integration process. + + Returns: + A two element tuple containing the reaction times and the decisions + """ + + if threshold is not None: + active = torch.abs(activities) < threshold + else: + active = torch.ones(size=activities.size(), dev=dev) + + dw = torch.normal(mean=rate * time_step_size * active, std=noise * active) + activities = activities + dw * np.sqrt(time_step_size) + + return activities, active + + +# Model Parameters +GAIN = 1.0 +LEAK = 1.0 +COMP = 7.5 +AUTOMATICITY = 0.15 # Automaticity Weight +STARTING_VALUE = 0.0 # Starting Point +THRESHOLD = 0.5 # Threshold +LCA_NOISE = None # Noise +DDM_NOISE = 0.1 +SCALE = 1.0 # Scales DDM inputs so threshold can be set to 1 +NON_DECISION_TIME = 0.1 + +# Number of simulations to run. Each simulation is independent. +NUM_SIMULATIONS = 1000 + +# Run the model +N_TIME_STEPS = 3000 +TIME_STEP_SIZE = 0.01 + +stimuli = np.array([[-1, -1], + [-1, -1], + [1, 1], + [-1, 1], + [-1, -1], + [-1, 1]]) + +tasks = np.array([[0, 1], + [1, 0], + [1, 0], + [1, 0], + [1, 0], + [0, 1]]) + +lca = LCALayer() +ddm = DriftDiffusionModel() + +cue_stimulus_intervals = np.array([[0.3], [0.3], [0.3], [0.3], [0.3], [0.3]]) + +NUM_TRIALS = len(stimuli) + +# Initialize the LCA task activities, these are maintained throughout the whole +# experiment. +lca_activities = torch.zeros(size=(NUM_SIMULATIONS, 2), device=dev) + +for trial_idx in range(NUM_TRIALS): + + # Reset DDM activities for this trial. + ddm_activities = torch.ones(size=(NUM_SIMULATIONS,), device=dev) * STARTING_VALUE + rts = torch.zeros(size=(NUM_SIMULATIONS,), device=dev) + + stimulus = torch.from_numpy(stimuli[trial_idx]).float().to(dev) + task = torch.from_numpy(tasks[trial_idx]).float().to(dev) + csi = torch.from_numpy(cue_stimulus_intervals[trial_idx]).float().to(dev) + + # Compute the Automaticity-weighted Stimulus Input + auto_weight_stim = torch.sum(stimulus * AUTOMATICITY) + + # Simulate N time steps of the model for this trial + for time_i in range(N_TIME_STEPS): + + # Compute the LCA task activities + lca_activities, _ = lca(input=task, + activities=lca_activities, + threshold=None, + leak=LEAK, + competition=COMP, + self_excitation=0.0, + noise=None, + time_step_size=TIME_STEP_SIZE) + + # If the Cue Stimulus Interval time has passed, start the decision process. + if time_i * TIME_STEP_SIZE > csi: + # Compute the drift rate for the DDM from the task activations and the stimulus + non_automatic_component = torch.sum(lca_activities * stimulus, dim=1) + drift_rate = non_automatic_component + auto_weight_stim + + ddm_activities, ddm_active = ddm(activities=ddm_activities, rate=drift_rate, threshold=THRESHOLD, + noise=DDM_NOISE, time_step_size=TIME_STEP_SIZE) + + # Compute the reaction time for each simulation. + rts = rts + ddm_active + + # Compute reaction times in seconds for these trials + rts = (NON_DECISION_TIME + rts * TIME_STEP_SIZE) + + decisions = torch.ones(size=(NUM_SIMULATIONS,), device=dev) + decisions[ddm_activities <= -THRESHOLD] = 0 diff --git a/Scripts/Debug/stability_flexibility/stability_flexibility.py b/Scripts/Debug/stability_flexibility/stability_flexibility.py new file mode 100644 index 00000000000..8c0b54f0be8 --- /dev/null +++ b/Scripts/Debug/stability_flexibility/stability_flexibility.py @@ -0,0 +1,276 @@ +import psyneulink as pnl +import numpy as np +import random +import pytest +import pandas as pd + + +# Define function to generate a counterbalanced trial sequence with a specified switch trial frequency +def generateTrialSequence(N, Frequency): + # Compute trial number + nTotalTrials = N + switchFrequency = Frequency + + nSwitchTrials = int(nTotalTrials * switchFrequency) + nRepeatTrials = int(nTotalTrials - nSwitchTrials) + + # Determine task transitions + transitions = [1] * nSwitchTrials + [0] * nRepeatTrials + order = np.random.permutation(list(range(nTotalTrials))) + transitions[:] = [transitions[i] for i in order] + + # Determine stimuli with 50% congruent trials + stimuli = [[1, 1]] * int(nSwitchTrials / 4) + [[1, -1]] * int(nSwitchTrials / 4) + [[-1, -1]] * int( + nSwitchTrials / 4) + [[-1, 1]] * int(nSwitchTrials / 4) + \ + [[1, 1]] * int(nRepeatTrials / 4) + [[1, -1]] * int(nRepeatTrials / 4) + [[-1, -1]] * int( + nRepeatTrials / 4) + [[-1, 1]] * int(nRepeatTrials / 4) + stimuli[:] = [stimuli[i] for i in order] + + # stimuli[:] = [[1, 1]] * nTotalTrials + + # Determine cue-stimulus intervals + CSI = [1200] * int(nSwitchTrials / 8) + [1200] * int(nSwitchTrials / 8) + \ + [1200] * int(nSwitchTrials / 8) + [1200] * int(nSwitchTrials / 8) + \ + [1200] * int(nSwitchTrials / 8) + [1200] * int(nSwitchTrials / 8) + \ + [1200] * int(nSwitchTrials / 8) + [1200] * int(nSwitchTrials / 8) + \ + [1200] * int(nRepeatTrials / 8) + [1200] * int(nRepeatTrials / 8) + \ + [1200] * int(nRepeatTrials / 8) + [1200] * int(nRepeatTrials / 8) + \ + [1200] * int(nRepeatTrials / 8) + [1200] * int(nRepeatTrials / 8) + \ + [1200] * int(nRepeatTrials / 8) + [1200] * int(nRepeatTrials / 8) + CSI[:] = [CSI[i] for i in order] + + # Set the task order + tasks = [[1, 0]] * (nTotalTrials + 1) + for i in list(range(nTotalTrials)): + if transitions[i] == 0: + tasks[i + 1] = tasks[i] + if transitions[i] == 1: + if tasks[i] == [1, 0]: + tasks[i + 1] = [0, 1] + if tasks[i] == [0, 1]: + tasks[i + 1] = [1, 0] + tasks = tasks[1:] + + # Determine correct response based on stimulus and task input + correctResponse = np.sum(np.multiply(tasks, stimuli), axis=1) + + # # Check whether combinations of transitions, stimuli and CSIs are counterbalanced + + # # This is used later to check whether trials are counterbalanced + # stimuli_type = [1] * int(nSwitchTrials/4) + [2] * int(nSwitchTrials/4) + [3] * int(nSwitchTrials/4) + [4] * int(nSwitchTrials/4) + \ + # [1] * int(nRepeatTrials/4) + [2] * int(nRepeatTrials/4) + [3] * int(nRepeatTrials/4) + [4] * int(nRepeatTrials/4) + # stimuli_type[:] = [stimuli_type[i] for i in order] + + # Trials = pd.DataFrame({'TrialType': transitions, + # 'Stimuli': stimuli_type, + # 'CSI': CSI + # }, columns= ['TrialType', 'Stimuli', 'CSI']) + # + # trial_counts = Trials.pivot_table(index=['TrialType', 'Stimuli', 'CSI'], aggfunc='size') + # print (trial_counts) + + return tasks, stimuli, CSI, correctResponse + + +# Stability-Flexibility Model + +def run_stab_flex(taskTrain, stimulusTrain, cueTrain, + gain=1.0, leak=1.0, competition=7.5, + lca_time_step_size=0.1, + non_decision_time=0.0, + automaticity=.15, + starting_point=0.0, + threshold=0.2, + ddm_noise=0.1, + lca_noise=0.0, + short_csi=None, + delta_csi=None, + scale=1, + ddm_time_step_size=0.001, + rng_seed=None): + # If the user has specified a short_csi and delta_csi as parameters, modify cueTrain + # such that its min is replaced with short_csi and its max (short_csi + delta_csi) + if delta_csi and short_csi: + csi_params = np.zeros(cueTrain.shape) + csi_params[cueTrain == np.min(cueTrain)] = short_csi + csi_params[cueTrain == np.max(cueTrain)] = short_csi + delta_csi + + GAIN = gain + LEAK = leak + COMP = competition + AUTOMATICITY = automaticity # Automaticity Weight + + STARTING_POINT = starting_point # Starting Point + THRESHOLD = threshold # Threshold + NOISE = ddm_noise # Noise + SCALE = scale # Scales DDM inputs so threshold can be set to 1 + + # Task Layer: [Color, Motion] {0, 1} Mutually Exclusive + # Origin Node + taskLayer = pnl.TransferMechanism(size=2, + function=pnl.Linear(slope=1, intercept=0), + output_ports=[pnl.RESULT], + name='Task Input [I1, I2]') + + # Stimulus Layer: [Color Stimulus, Motion Stimulus] + # Origin Node + stimulusInfo = pnl.TransferMechanism(size=2, + function=pnl.Linear(slope=1, intercept=0), + output_ports=[pnl.RESULT], + name="Stimulus Input [S1, S2]") + + # Cue-To-Stimulus Interval Layer + # Origin Node + cueInterval = pnl.TransferMechanism(size=1, + function=pnl.Linear(slope=1, intercept=0), + output_ports=[pnl.RESULT], + name='Cue-Stimulus Interval') + + # Correct Response Info + # Origin Node + correctResponseInfo = pnl.TransferMechanism(size=1, + function=pnl.Linear(slope=1, intercept=0), + output_ports=[pnl.RESULT], + name='Correct Response Info') + + # Control Module Layer: [Color Activation, Motion Activation] + controlModule = pnl.LCAMechanism(size=2, + function=pnl.Logistic(gain=GAIN), + leak=LEAK, + competition=COMP, + self_excitation=0, + noise=0, + termination_measure=pnl.TimeScale.TRIAL, + termination_threshold=1200, + time_step_size=lca_time_step_size, + name='Task Activations [Act1, Act2]') + + # Control Mechanism Setting Cue-To-Stimulus Interval + csiController = pnl.ControlMechanism(monitor_for_control=cueInterval, + control_signals=[(pnl.TERMINATION_THRESHOLD, controlModule)], + modulation=pnl.OVERRIDE) + + # Hadamard product of controlModule and Stimulus Information + nonAutomaticComponent = pnl.TransferMechanism(size=2, + function=pnl.Linear(slope=1, intercept=0), + input_ports=pnl.InputPort(combine=pnl.PRODUCT), + output_ports=[pnl.RESULT], + name='Non-Automatic Component [S1*Act1, S2*Act2]') + + # Multiply Stimulus Input by the automaticity weight + congruenceWeighting = pnl.TransferMechanism(size=2, + function=pnl.Linear(slope=AUTOMATICITY, intercept=0), + output_ports=[pnl.RESULT], + name="Automaticity-weighted Stimulus Input [w*S1, w*S2]") + + # Summation of nonAutomatic and Automatic Components + ddmCombination = pnl.TransferMechanism(size=1, + function=pnl.Linear(slope=1, intercept=0), + input_ports=pnl.InputPort(combine=pnl.SUM), + output_ports=[pnl.RESULT], + name="Drift = (w*S1 + w*S2) + (S1*Act1 + S2*Act2)") + + # Ensure upper boundary of DDM is always correct response by multiplying DDM input by correctResponseInfo + ddmRecodeDrift = pnl.TransferMechanism(size=1, + function=pnl.Linear(slope=1, intercept=0), + input_ports=pnl.InputPort(combine=pnl.PRODUCT), + output_ports=[pnl.RESULT], + name='Recoded Drift = Drift * correctResponseInfo') + + # Scale DDM inputs + ddmInputScale = pnl.TransferMechanism(size=1, + function=pnl.Linear(slope=SCALE, intercept=0), + output_ports=[pnl.RESULT], + name='Scaled DDM Input') + + # Decision Module + decisionMaker = pnl.DDM(function=pnl.DriftDiffusionIntegrator(starting_value=STARTING_POINT, + threshold=THRESHOLD, + noise=NOISE, + time_step_size=ddm_time_step_size), + reset_stateful_function_when=pnl.AtTrialStart(), + output_ports=[pnl.DECISION_VARIABLE, pnl.RESPONSE_TIME], + name='DDM') + + taskLayer.set_log_conditions([pnl.RESULT]) + stimulusInfo.set_log_conditions([pnl.RESULT]) + cueInterval.set_log_conditions([pnl.RESULT]) + correctResponseInfo.set_log_conditions([pnl.RESULT]) + controlModule.set_log_conditions([pnl.RESULT, 'termination_threshold']) + nonAutomaticComponent.set_log_conditions([pnl.RESULT]) + congruenceWeighting.set_log_conditions([pnl.RESULT]) + ddmCombination.set_log_conditions([pnl.RESULT]) + ddmRecodeDrift.set_log_conditions([pnl.RESULT]) + ddmInputScale.set_log_conditions([pnl.RESULT]) + decisionMaker.set_log_conditions([pnl.DECISION_VARIABLE, pnl.RESPONSE_TIME]) + + # Composition Creation + stabilityFlexibility = pnl.Composition() + + # Node Creation + stabilityFlexibility.add_node(taskLayer) + stabilityFlexibility.add_node(stimulusInfo) + stabilityFlexibility.add_node(cueInterval) + stabilityFlexibility.add_node(correctResponseInfo) + stabilityFlexibility.add_node(controlModule) + stabilityFlexibility.add_node(csiController) + stabilityFlexibility.add_node(nonAutomaticComponent) + stabilityFlexibility.add_node(congruenceWeighting) + stabilityFlexibility.add_node(ddmCombination) + stabilityFlexibility.add_node(ddmRecodeDrift) + stabilityFlexibility.add_node(ddmInputScale) + stabilityFlexibility.add_node(decisionMaker) + + # Projection Creation + stabilityFlexibility.add_projection(sender=taskLayer, receiver=controlModule) + stabilityFlexibility.add_projection(sender=controlModule, receiver=nonAutomaticComponent) + stabilityFlexibility.add_projection(sender=stimulusInfo, receiver=nonAutomaticComponent) + stabilityFlexibility.add_projection(sender=stimulusInfo, receiver=congruenceWeighting) + stabilityFlexibility.add_projection(sender=nonAutomaticComponent, receiver=ddmCombination) + stabilityFlexibility.add_projection(sender=congruenceWeighting, receiver=ddmCombination) + stabilityFlexibility.add_projection(sender=ddmCombination, receiver=ddmRecodeDrift) + stabilityFlexibility.add_projection(sender=correctResponseInfo, receiver=ddmRecodeDrift) + stabilityFlexibility.add_projection(sender=ddmRecodeDrift, receiver=ddmInputScale) + stabilityFlexibility.add_projection(sender=ddmInputScale, receiver=decisionMaker) + + # Hot-fix currently necessary to allow control module and DDM to execute in parallel in compiled mode + # We need two gates in order to output both values (decision and response) from the ddm + decisionGate = pnl.ProcessingMechanism(size=1, name="DECISION_GATE") + stabilityFlexibility.add_node(decisionGate) + + responseGate = pnl.ProcessingMechanism(size=1, name="RESPONSE_GATE") + stabilityFlexibility.add_node(responseGate) + + stabilityFlexibility.add_projection(sender=decisionMaker.output_ports[0], receiver=decisionGate) + stabilityFlexibility.add_projection(sender=decisionMaker.output_ports[1], receiver=responseGate) + + # Sets scheduler conditions, so that the gates are not executed (and hence the composition doesn't finish) until decisionMaker is finished + stabilityFlexibility.scheduler.add_condition(decisionGate, pnl.WhenFinished(decisionMaker)) + stabilityFlexibility.scheduler.add_condition(responseGate, pnl.WhenFinished(decisionMaker)) + + inputs = {taskLayer: taskTrain, + stimulusInfo: stimulusTrain, + cueInterval: cueTrain} + + stabilityFlexibility.run(inputs, execution_mode=pnl.ExecutionMode.LLVMRun) + + return stabilityFlexibility + + +tasks, stimuli, CSI, correctResponse = generateTrialSequence(256, 0.5) + +comp = run_stab_flex(taskTrain=tasks, stimulusTrain=stimuli, cueTrain=CSI) + +#comp.show_graph() + +# taskLayer.log.print_entries() +# stimulusInfo.log.print_entries() +# cueInterval.log.print_entries() +# correctResponseInfo.log.print_entries() +# controlModule.log.print_entries() +# nonAutomaticComponent.log.print_entries() +# congruenceWeighting.log.print_entries() +# ddmCombination.log.print_entries() +# ddmRecodeDrift.log.print_entries() +# ddmInputScale.log.print_entries() +# decisionMaker.log.print_entries() diff --git a/Scripts/Debug/stability_flexibility_simple.py b/Scripts/Debug/stability_flexibility_simple.py index b2bf6b133c1..d8a6ed9d30b 100644 --- a/Scripts/Debug/stability_flexibility_simple.py +++ b/Scripts/Debug/stability_flexibility_simple.py @@ -64,7 +64,7 @@ def computeAccuracy(variable): gain = np.asarray([[g]]) DRIFT = 1 # Drift Rate -STARTING_POINT = 0.0 # Starting Point +STARTING_VALUE = 0.0 # Starting Point THRESHOLD = 0.0475 # Threshold NOISE = 0.04 # Noise T0 = 0.2 # T0 @@ -116,10 +116,10 @@ def computeAccuracy(variable): ddmCombination.set_log_conditions([pnl.RESULT]) decisionMaker = pnl.DDM(function=pnl.DriftDiffusionAnalytical(drift_rate=DRIFT, - starting_point=STARTING_POINT, + starting_value=STARTING_VALUE, threshold=THRESHOLD, noise=NOISE, - t0=T0), + non_decision_time=T0), output_ports=[pnl.DECISION_VARIABLE, pnl.RESPONSE_TIME, pnl.PROBABILITY_UPPER_THRESHOLD, pnl.PROBABILITY_LOWER_THRESHOLD], @@ -164,7 +164,7 @@ def computeAccuracy(variable): meta_controller = pnl.OptimizationControlMechanism(agent_rep=stabilityFlexibility, state_features=[inputLayer.input_port, stimulusInfo.input_port], - state_feature_functions=pnl.Buffer(history=100), + state_feature_function=pnl.Buffer(history=100), objective_mechanism=objective_mech, function=pnl.GridSearch(), control_signals=[signal]) diff --git a/Scripts/Examples/EVC OCM.py b/Scripts/Examples/EVC OCM.py index 362ac5e07db..055eb6d33db 100644 --- a/Scripts/Examples/EVC OCM.py +++ b/Scripts/Examples/EVC OCM.py @@ -16,8 +16,8 @@ ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3)})), noise=0.5, - starting_point=0, - t0=0.45), + starting_value=0, + non_decision_time=0.45), output_ports=[DECISION_VARIABLE, RESPONSE_TIME, PROBABILITY_UPPER_THRESHOLD], @@ -32,7 +32,7 @@ comp.add_model_based_optimizer(optimizer=OptimizationControlMechanism(name='OCM', agent_rep=comp, state_features=[Input.input_port, reward.input_port], - state_feature_functions=AdaptiveIntegrator(rate=0.5), + state_feature_function=AdaptiveIntegrator(rate=0.5), objective_mechanism=ObjectiveMechanism( name='OCM Objective Mechanism', function=LinearCombination(operation=PRODUCT), diff --git a/Scripts/Examples/EVC-Gratton Composition.py b/Scripts/Examples/EVC-Gratton Composition.py index 071ae433155..ac4e9c0bdd7 100644 --- a/Scripts/Examples/EVC-Gratton Composition.py +++ b/Scripts/Examples/EVC-Gratton Composition.py @@ -18,8 +18,8 @@ function=pnl.DriftDiffusionAnalytical(drift_rate=(1.0), threshold=(0.2645), noise=(0.5), - starting_point=(0), - t0=0.15), + starting_value=(0), + non_decision_time=0.15), output_ports=[pnl.DECISION_VARIABLE, pnl.RESPONSE_TIME, pnl.PROBABILITY_UPPER_THRESHOLD] @@ -65,7 +65,7 @@ state_features=[target_stim.input_port, flanker_stim.input_port, reward.input_port], - state_feature_functions=pnl.AdaptiveIntegrator( + state_feature_function=pnl.AdaptiveIntegrator( rate=1.0), objective_mechanism=objective_mech, function=pnl.GridSearch(), diff --git a/Scripts/Examples/EVC-Gratton-GaussianProcess.py b/Scripts/Examples/EVC-Gratton-GaussianProcess.py index 5148e22d8a9..74b6905d919 100644 --- a/Scripts/Examples/EVC-Gratton-GaussianProcess.py +++ b/Scripts/Examples/EVC-Gratton-GaussianProcess.py @@ -34,8 +34,8 @@ ), ), noise=(0.5), - starting_point=(0), - t0=0.45 + starting_value=(0), + non_decision_time=0.45 ), output_ports=[ pnl.DECISION_VARIABLE, @@ -52,7 +52,7 @@ comp.add_linear_processing_pathway(task_execution_pathway) ocm = pnl.OptimizationControlMechanism(state_features=[Input, Reward], - state_feature_functions=pnl.AdaptiveIntegrator(rate=0.5), + state_feature_function=pnl.AdaptiveIntegrator(rate=0.5), agent_rep=comp, # function=pnl.GaussianProcessOptimization, function=pnl.GridSearch, diff --git a/Scripts/Examples/Gating-Mechanism. with UDF.py b/Scripts/Examples/Gating-Mechanism. with UDF.py index bf8e94f03f3..91d51d3fc83 100644 --- a/Scripts/Examples/Gating-Mechanism. with UDF.py +++ b/Scripts/Examples/Gating-Mechanism. with UDF.py @@ -1,5 +1,7 @@ import functools + import numpy as np + import psyneulink as pnl import psyneulink.core.components.functions.nonstateful.transferfunctions @@ -51,7 +53,7 @@ def my_sinusoidal_fct(input, # pnl.FUNCTION: my_sinusoidal_fct} output_ports={pnl.NAME: 'RESULTS USING UDF', # pnl.VARIABLE: (pnl.OWNER_VALUE, 0), - pnl.FUNCTION: psyneulink.core.components.functions.nonstateful.transferfunctions.Linear(slope=pnl.GATING) + pnl.FUNCTION: psyneulink.core.components.functions.nonstateful.transferfunctions.Linear(slope=pnl.GATE) # pnl.FUNCTION: pnl.Logistic(gain=pnl.GATING) # pnl.FUNCTION: my_linear_fct # pnl.FUNCTION: my_exp_fct diff --git a/Scripts/Examples/Mixed-NN-and-DDM.py b/Scripts/Examples/Mixed-NN-and-DDM.py index d0a35c7d9fc..72a97c42c4a 100644 --- a/Scripts/Examples/Mixed-NN-and-DDM.py +++ b/Scripts/Examples/Mixed-NN-and-DDM.py @@ -19,7 +19,7 @@ function=psyneulink.core.components.functions.nonstateful.distributionfunctions.DriftDiffusionAnalytical( drift_rate=0.5, threshold=1, - starting_point=0.0 + starting_value=0.0 ) ) diff --git a/Scripts/Examples/RL-DDM.py b/Scripts/Examples/RL-DDM.py index 8b453b9ae9b..254dfecbe29 100644 --- a/Scripts/Examples/RL-DDM.py +++ b/Scripts/Examples/RL-DDM.py @@ -28,7 +28,7 @@ function=psyneulink.core.components.functions.nonstateful.distributionfunctions.DriftDiffusionAnalytical( drift_rate=pnl.CONTROL, threshold=pnl.CONTROL, - starting_point=pnl.CONTROL, + starting_value=pnl.CONTROL, noise=pnl.CONTROL, ), output_ports=[pnl.SELECTED_INPUT_ARRAY], diff --git a/Scripts/Examples/StabilityFlexibility.py b/Scripts/Examples/StabilityFlexibility.py index 2a5f3b2c23f..8de929a983f 100644 --- a/Scripts/Examples/StabilityFlexibility.py +++ b/Scripts/Examples/StabilityFlexibility.py @@ -70,7 +70,7 @@ def computeAccuracy(variable): gain = np.asarray([[g]]) DRIFT = 1 # Drift Rate -STARTING_POINT = 0.0 # Starting Point +STARTING_VALUE = 0.0 # Starting Point THRESHOLD = 0.0475 # Threshold NOISE = 0.04 # Noise T0 = 0.2 # T0 @@ -124,10 +124,10 @@ def computeAccuracy(variable): ddmCombination.set_log_conditions([pnl.RESULT]) decisionMaker = pnl.DDM(function=pnl.DriftDiffusionAnalytical(drift_rate = DRIFT, - starting_point = STARTING_POINT, + starting_value = STARTING_VALUE, threshold = THRESHOLD, noise = NOISE, - t0 = T0), + non_decision_time = T0), output_ports = [pnl.DECISION_VARIABLE, pnl.RESPONSE_TIME, pnl.PROBABILITY_UPPER_THRESHOLD, pnl.PROBABILITY_LOWER_THRESHOLD], name='DDM') @@ -177,7 +177,7 @@ def computeAccuracy(variable): meta_controller = pnl.OptimizationControlMechanism(agent_rep=stabilityFlexibility, state_features=[inputLayer.input_port, stimulusInfo.input_port], - state_feature_functions=pnl.Buffer(history=3), + state_feature_function=pnl.Buffer(history=3), objective_mechanism=objective_mech, function=pnl.GridSearch(), control_signals=[signal]) diff --git a/Scripts/Examples/Stroop Model.py b/Scripts/Examples/Stroop Model.py index 16925530d64..982fb67cec1 100644 --- a/Scripts/Examples/Stroop Model.py +++ b/Scripts/Examples/Stroop Model.py @@ -32,8 +32,8 @@ function=DriftDiffusionAnalytical(drift_rate=(1.0), threshold=(0.2645), noise=(0.5), - starting_point=(0), - t0=0.15), + starting_value=(0), + non_decision_time=0.15), output_ports=[DECISION_VARIABLE, RESPONSE_TIME, PROBABILITY_UPPER_THRESHOLD] diff --git a/Scripts/Examples/Tutorial/Stroop Model - EVC.py b/Scripts/Examples/Tutorial/Stroop Model - EVC.py index 1db6570ad1d..e4ab6f08344 100644 --- a/Scripts/Examples/Tutorial/Stroop Model - EVC.py +++ b/Scripts/Examples/Tutorial/Stroop Model - EVC.py @@ -32,8 +32,8 @@ function=DriftDiffusionAnalytical(drift_rate=(1.0), threshold=(0.2645), noise=(0.5), - starting_point=(0), - t0=0.15), + starting_value=(0), + non_decision_time=0.15), output_ports=[DECISION_VARIABLE, RESPONSE_TIME, PROBABILITY_UPPER_THRESHOLD] @@ -64,8 +64,8 @@ evc = OptimizationControlMechanism(name='EVC', agent_rep=Stroop_model, state_features=[color_input.input_port, word_input.input_port, reward.input_port], - state_feature_functions=AdaptiveIntegrator(rate=1.0), - # state_feature_functions=AdaptiveIntegrator, + state_feature_function=AdaptiveIntegrator(rate=1.0), + # state_feature_function=AdaptiveIntegrator, objective_mechanism= \ ObjectiveMechanism( name='EVC Objective Mechanism', diff --git a/Scripts/Models (Under Development)/Bustamante_Stroop_XOR_LVOC_Model_VZ.py b/Scripts/Models (Under Development)/Bustamante_Stroop_XOR_LVOC_Model_VZ.py index 7d5cea9a171..da22452c576 100644 --- a/Scripts/Models (Under Development)/Bustamante_Stroop_XOR_LVOC_Model_VZ.py +++ b/Scripts/Models (Under Development)/Bustamante_Stroop_XOR_LVOC_Model_VZ.py @@ -85,7 +85,7 @@ def adj_cost_fct(v): function=pnl.DriftDiffusionAnalytical( threshold=2.27, noise=0.4, - t0=.4 + non_decision_time=.4 ), output_ports=[ pnl.PROBABILITY_UPPER_THRESHOLD, diff --git a/Scripts/Models (Under Development)/ColorMotionTask_FULL.py b/Scripts/Models (Under Development)/ColorMotionTask_FULL.py index 8c9f79c5e85..74447feaf8d 100644 --- a/Scripts/Models (Under Development)/ColorMotionTask_FULL.py +++ b/Scripts/Models (Under Development)/ColorMotionTask_FULL.py @@ -122,9 +122,9 @@ def incongruent(colorResponse, motionResponse): function=Linear(slope=optimal_motion_control)) decision = DDM(name='Decision', function=DriftDiffusionAnalytical( - starting_point=0, + starting_value=0, noise=0.5, - t0=0.2, + non_decision_time=0.2, threshold=0.45), output_ports=[PROBABILITY_UPPER_THRESHOLD, RESPONSE_TIME], ) diff --git a/Scripts/Models (Under Development)/ColorMotionTask_SIMPLE.py b/Scripts/Models (Under Development)/ColorMotionTask_SIMPLE.py index 58f220b2738..445a500d562 100644 --- a/Scripts/Models (Under Development)/ColorMotionTask_SIMPLE.py +++ b/Scripts/Models (Under Development)/ColorMotionTask_SIMPLE.py @@ -9,9 +9,9 @@ function=Linear(slope=optimal_motion_control)) decision = DDM(name='Decision', function=DriftDiffusionAnalytical( - starting_point=0, + starting_value=0, noise=0.5, - t0=0.2, + non_decision_time=0.2, threshold=0.45), output_ports=[PROBABILITY_UPPER_THRESHOLD, RESPONSE_TIME], ) diff --git a/Scripts/Models (Under Development)/Predator-Prey Model DQN LVOC.py b/Scripts/Models (Under Development)/Predator-Prey Model DQN LVOC.py index f6525841a6d..52db2a7a4fa 100644 --- a/Scripts/Models (Under Development)/Predator-Prey Model DQN LVOC.py +++ b/Scripts/Models (Under Development)/Predator-Prey Model DQN LVOC.py @@ -161,7 +161,7 @@ def get_action(variable=[[0,0],[0,0],[0,0]]): ocm = OptimizationControlMechanism(name='EVC', state_features=trial_type_input_mech, - state_feature_functions=FEATURE_FUNCTION, + state_feature_function=FEATURE_FUNCTION, agent_rep=RegressionCFA( update_weights=BayesGLM(mu_0=0.5, sigma_0=0.1), prediction_terms=[PV.F, PV.C, PV.COST] diff --git a/conftest.py b/conftest.py index 92c98215b47..8521ae6c014 100644 --- a/conftest.py +++ b/conftest.py @@ -68,8 +68,10 @@ def pytest_generate_tests(metafunc): metafunc.parametrize("comp_mode", get_comp_execution_modes()) if "autodiff_mode" in metafunc.fixturenames: - auto_modes = [pnlvm.ExecutionMode.Python, - pytest.param(pnlvm.ExecutionMode.LLVMRun, marks=pytest.mark.llvm)] + auto_modes = [ + pnlvm.ExecutionMode.Python, + pytest.param(pnlvm.ExecutionMode.LLVMRun, marks=pytest.mark.llvm) + ] metafunc.parametrize("autodiff_mode", auto_modes) def pytest_runtest_call(item): diff --git a/dev_requirements.txt b/dev_requirements.txt index 9dc8d8afd90..95b05810996 100644 --- a/dev_requirements.txt +++ b/dev_requirements.txt @@ -1,9 +1,9 @@ jupyter<=1.0.0 -pytest<6.2.6 +pytest<7.1.2 pytest-benchmark<3.4.2 pytest-cov<3.0.1 -pytest-helpers-namespace<2021.4.30 +pytest-helpers-namespace<2021.12.30 pytest-profiling<=1.7.0 -pytest-pycodestyle<=2.2.0 -pytest-pydocstyle<=2.2.0 +pytest-pycodestyle<2.4.0 +pytest-pydocstyle<2.4.0 pytest-xdist<2.6.0 diff --git a/doc_requirements.txt b/doc_requirements.txt index 1e90f009848..043ea79e043 100644 --- a/doc_requirements.txt +++ b/doc_requirements.txt @@ -1,3 +1,3 @@ psyneulink-sphinx-theme<1.2.3.1 sphinx<4.2.1 -sphinx_autodoc_typehints<1.13.0 +sphinx_autodoc_typehints<1.16.0 diff --git a/docs/source/AutodiffComposition.rst b/docs/source/AutodiffComposition.rst index b4f147de430..7f3d25f6266 100644 --- a/docs/source/AutodiffComposition.rst +++ b/docs/source/AutodiffComposition.rst @@ -1,6 +1,12 @@ AutodiffComposition =================== +.. container:: related + + *Related* + + * `Composition_Learning` + .. automodule:: psyneulink.library.compositions.autodiffcomposition :members: :private-members: diff --git a/docs/source/Composition.rst b/docs/source/Composition.rst index 5bad64708e7..116e05881fe 100644 --- a/docs/source/Composition.rst +++ b/docs/source/Composition.rst @@ -24,6 +24,8 @@ Composition :maxdepth: 1 Pathway + CompositionInterfaceMechanism + OptimizationControlMechanism Scheduling Visualization Report @@ -31,4 +33,4 @@ Composition .. automodule:: psyneulink.core.compositions.composition :members: Composition, NodeRole, Graph :private-members: - :exclude-members: Parameters, show_structure, CompositionError, get_inputs_format + :exclude-members: Parameters, show_structure, CompositionError, get_inputs_format, external_input_ports_of_all_input_nodes, external_input_ports diff --git a/docs/source/CompositionFunctionApproximator.rst b/docs/source/CompositionFunctionApproximator.rst index f9392286136..6964c227df4 100644 --- a/docs/source/CompositionFunctionApproximator.rst +++ b/docs/source/CompositionFunctionApproximator.rst @@ -1,7 +1,6 @@ CompositionFunctionApproximator =============================== - .. container:: subclasses *Subclasses* @@ -11,8 +10,16 @@ CompositionFunctionApproximator RegressionCFA -.. toctree:: - :maxdepth: 2 + | + +.. container:: related + + *Related* + + .. toctree:: + :maxdepth: 1 + + OptimizationControlMechanism .. automodule:: psyneulink.core.compositions.compositionfunctionapproximator :members: diff --git a/docs/source/CompositionInterfaceMechanism.rst b/docs/source/CompositionInterfaceMechanism.rst index 7a9b18233b0..1773f096394 100644 --- a/docs/source/CompositionInterfaceMechanism.rst +++ b/docs/source/CompositionInterfaceMechanism.rst @@ -1,6 +1,16 @@ CompositionInterfaceMechanism ============================= +.. container:: related + + *Related* + + .. toctree:: + :maxdepth: 1 + + Mechanism + Composition + .. automodule:: psyneulink.core.components.mechanisms.processing.compositioninterfacemechanism :members: :private-members: diff --git a/docs/source/Core.rst b/docs/source/Core.rst index e66bd4c40ee..292689884fd 100644 --- a/docs/source/Core.rst +++ b/docs/source/Core.rst @@ -93,4 +93,4 @@ Core - `Compilation` - `Report` - `Log` - - `json` + - `mdf` diff --git a/docs/source/OptimizationControlMechanism.rst b/docs/source/OptimizationControlMechanism.rst index 371812fb1a6..6c63e3aff0b 100644 --- a/docs/source/OptimizationControlMechanism.rst +++ b/docs/source/OptimizationControlMechanism.rst @@ -4,4 +4,4 @@ OptimizationControlMechanism .. automodule:: psyneulink.core.components.mechanisms.modulatory.control.optimizationcontrolmechanism :members: :private-members: - :exclude-members: Linear, random, Parameters, OptimizationControlMechanismError + :exclude-members: Linear, random, Parameters, OptimizationControlMechanismError, state_dict diff --git a/docs/source/ParameterEstimationComposition.rst b/docs/source/ParameterEstimationComposition.rst index b0a50802329..deaf93a9b85 100644 --- a/docs/source/ParameterEstimationComposition.rst +++ b/docs/source/ParameterEstimationComposition.rst @@ -1,6 +1,15 @@ ParameterEstimationComposition ============================== +.. container:: related + + *Related* + + .. toctree:: + :maxdepth: 1 + + OptimizationControlMechanism + .. toctree:: :maxdepth: 2 diff --git a/docs/source/_static/Optimization_fig.svg b/docs/source/_static/Optimization_fig.svg index 46594b558a0..e69e444f6ba 100644 --- a/docs/source/_static/Optimization_fig.svg +++ b/docs/source/_static/Optimization_fig.svg @@ -1,3179 +1,1470 @@ + viewBox="0 0 1681.1 596.4" style="enable-background:new 0 0 1681.1 596.4;" xml:space="preserve"> - + - - - - - - - - - - - - - - - - - - - - - -A -Optimization - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OptimizationCont - r - olMechanism - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Composition or + + + + + + + + + + + + + + + + + + + + OptimizationControlMechanism + - - - - - - - - - - CompositionFunctionApp - r - oximator + + + + + + + + + + + + + + + + + + + + + Composition or + + + CompositionFunctionApproximator + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OptimizationFunction + + + + + + + + + + + + + + + + + + + + + OptimizationFunction + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - sea - r - ch_function + + + + + + + + + + + + + + + + + + + search_function + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - sea - r - ch_space + + + + + + + + + + + + + + + + + + + search_space + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - agent_ - r - ep + + + + + + + + + + + + + + + + + + + agent_rep + - - - - - - - - - - - - + + + + + + + + - + - - + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + (adapt) + + + + + + call function + + + + pass argument + + + + + + Execution + + + + Update + + + feature values + + + + + + + + + + - + - - + + - - - - - - - - - - (adapt) - + + + + + + + + + (Adapt) + + Optimize + + + control_allocation + + + Implement + + + control_allocation + + + + + + + + + + + + + objective_function + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - call function - - - - - - - - - - - - - - - - - - - - pass a - r - gument + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + return/assign value + + + + + + + + + + + + + + + + + evaluate + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Execution + + + + + + + + + + + + + + + + + + + + + evaluate_agent_rep + - - - - - - - - - - - - - - - - - - - Update + + + + + + + + + + + + + + + + + + + outcome + - - - - - - - - - - featu - r - e values - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Adapt) - - - - + + + + + + + + + State - - - - - - - - - - - Optimize - - - - - - - - - - - cont - r - ol_allocation - - - - - - - - - - - Implement - - - - - - - - - - - cont - r - ol_allocation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - objective_function - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + Objective + + + + + + Mechanism - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - r - etu - r - n/assign value - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - evaluate - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - evaluate_agent_ - r - ep - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - outcome - - - - - - - - - - - - - State - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Objective - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + Composition Inputs + - - - - - - - - - - Mechanism + + + + + + + + + + + + + + + + + + + + + Monitored + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Composition Inputs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Monito - r - ed - - - - - - - - - - - - - - - - - - - - - - - - V - alues - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - net_outcome - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - cont - r - ol_allocation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - state_featu - r - es - - - -B - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Mechanism - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Mechanism - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Mechanism - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Model-based - - - - - - - - - - - - - - - - - - - - - - - - Cont - r - ol - - - - - - - - - - - - - - - - - - - - - - Evaluation - - - - - - - - - - - - - - - - - - - - - - - - Processing - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Mechanism - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Mechanism - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Mechanism - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Objective - - - - - - - - - - - - - - - - - - - - - - Mechanism - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - “Model-f - r - ee” - - - - - - - - - - - - - - - - - - - - Features - - - - - - - - - - - - - - - - - - - - Outcome - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Optimization - - - - - - - - - - - Cont - r - ol - - - - - - - - - - - Mechanism - - - - - - - - - - - - - - - - - - - - - - Simulation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Objective - - - - - - - - - - - - - - - - - - - - - - Mechanism - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - agent_rep - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + Values - - - - - - - - - - agent_rep - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Composition - - - - - - - - - - - Composition - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Optimization - - - - - - - - - - - Cont - r - ol + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + net_outcome + - - - - - - - - - - Mechanism + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + control_allocation + - - - - - - - - - - - - + + + + + + + + - + - - + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + state_features + - + - - + + - - + + + + + + + + + + + + + + + + + + + - + - - + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + Mechanism + - - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + Mechanism + - - - - - - - - - - + + + + + + + + + - - - - - - - - - - Composition + + + + + + + + + Mechanism + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + Model-based + - - - - - - - - - - Function + + + + + + + + - - - - - - - - - - + + + + + + + + + Control + - - - - - - - - - Approximator - - - - - - - - - - - - + + + + + + + + + + Evaluation + + + + + + + + + + + + + + + + + + + + Processing + + + + + + + + + + + + + + + + + + + + + + + Mechanism + + + + + + + + + + + + + + + + + + + + + Mechanism + + + + + + + + + + + + + + + + + + + + + Mechanism + + + + + + + + + + + + + + + + + + + + + + + + + + + Objective + + + + + + Mechanism + + + + + + + + + + + + + + + + + “Model-free” + + + + Features + + + + Outcome + + + + + + + + + + + + + + + + + + + + + + + + + + + Optimization + + + Control + + + Mechanism + + + + + + + + + + + + Simulation + + + + + + + + + + + + + + + Objective + + + + + + Mechanism + + + + + + + + + + + + + agent_rep + + + + + + + + + + - + - - + + - - - - - - - - - - + + + + + + + + + + + agent_rep + + + + + + + Composition + + + Composition + + + + + - - - - - - - - - - - - + + + + + + + + + Optimization + + + Control + + + Mechanism + + + + + + + + + + - + - - + + - - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Composition + + + + + + or + + + + + + Composition + + + + + + Function + + + + + + Approximator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - - - - - - - - - - Adaptation - + + + + + + + + + Adaptation @@ -3181,4 +1472,11 @@ + + +A +B + +Forms of Optimization +Control Flow diff --git a/docs/source/_static/input_port_shadowing_1.svg b/docs/source/_static/input_port_shadowing_1.svg new file mode 100644 index 00000000000..109d59ba5bb --- /dev/null +++ b/docs/source/_static/input_port_shadowing_1.svg @@ -0,0 +1,1186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OutputPort-0 + + + + + + + + + + + OutputPorts + + + + + + + + + + + Mechanism + + + + + + + + + + + : + + + + + + + + + + + Mech + + + + + + + + + + + + + + + + + + + + + + + ParameterPorts + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + intercept + + + + + + + + + + + + + + + + + + + + + slope + + + + + + + + + + + + + + + + + + + + + + + InputPorts + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + InputPort-0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OutputPort-0 + + + + + + + + + + + OutputPorts + + + + + + + + + + + Mechanism + + + + + + + + + + + : + + + + + + + + + + + Shadowed Mech + + + + + + + + + + + + + + + + + + + + + + + ParameterPorts + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + intercept + + + + + + + + + + + + + + + + + + + + + slope + + + + + + + + + + + + + + + + + + + + + + + InputPorts + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + InputPort-0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OutputPort-0 + + + + + + + + + + + OutputPorts + + + + + + + + + + + Mechanism + + + + + + + + + + + : + + + + + + + + + + + Shadowing Mech + + + + + + + + + + + + + + + + + + + + + + + ParameterPorts + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + intercept + + + + + + + + + + + + + + + + + + + + + slope + + + + + + + + + + + + + + + + + + + + + + + InputPorts + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Shadowed input of Shadowed Mech[InputPort-0] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/_static/input_port_shadowing_2.svg b/docs/source/_static/input_port_shadowing_2.svg new file mode 100644 index 00000000000..fada5f18e1a --- /dev/null +++ b/docs/source/_static/input_port_shadowing_2.svg @@ -0,0 +1,2480 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Outer Composition + + + + + + + + + + + + + + + + + + + + + + + + + Nested Composition + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + INPUT_CIM_Nested Composition_INPUT_CIM_Mech_InputPort-0 + + + + + + + + + + + + + OutputPorts + + + + + + + + + + + + + Mechanism + + + + + + + + + + + + + : + + + + + + + + + + + + + Outer Composition Input_CIM + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + INPUT_CIM_Mech_InputPort-0 + + + + + + + + + + + + + OutputPorts + + + + + + + + + + + + + Mechanism + + + + + + + + + + + + + : + + + + + + + + + + + + + Nested Composition Input_CIM + + + + + + + + + + + + + + + + + + + + + + + + + + + InputPorts + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + INPUT_CIM_Mech_InputPort-0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OutputPort-0 + + + + + + + + + + + + + OutputPorts + + + + + + + + + + + + + Mechanism + + + + + + + + + + + + + : + + + + + + + + + + + + + Shadowing Mech + + + + + + + + + + + + + + + + + + + + + + + + + + + ParameterPorts + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + intercept + + + + + + + + + + + + + + + + + + + + + + + + + slope + + + + + + + + + + + + + + + + + + + + + + + + + + + InputPorts + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Shadowed input of Mech[InputPort-0] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OutputPort-0 + + + + + + + + + + + + + OutputPorts + + + + + + + + + + + + + Mechanism + + + + + + + + + + + + + : + + + + + + + + + + + + + Mech + + + + + + + + + + + + + + + + + + + + + + + + + + + ParameterPorts + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + intercept + + + + + + + + + + + + + + + + + + + + + + + + + slope + + + + + + + + + + + + + + + + + + + + + + + + + + + InputPorts + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + InputPort-0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mechanism + + + + + + + + + + + + + : + + + + + + + + + + + + + Outer Composition Output_CIM + + + + + + + + + + + + + + + + + + + + + + + + + + + InputPorts + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OUTPUT_CIM_Nested Composition_OUTPUT_CIM_Mech_OutputPort-0 + + + + + + + + + + + + + + + + + + + + + + + + + OUTPUT_CIM_Shadowing Mech_OutputPort-0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OUTPUT_CIM_Mech_OutputPort-0 + + + + + + + + + + + + + OutputPorts + + + + + + + + + + + + + Mechanism + + + + + + + + + + + + + : + + + + + + + + + + + + + Nested Composition Output_CIM + + + + + + + + + + + + + + + + + + + + + + + + + + + InputPorts + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OUTPUT_CIM_Mech_OutputPort-0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/_static/stroop_conflict_monitoring.json b/docs/source/_static/stroop_conflict_monitoring.json index aa3962a1454..e4a9e5c40cb 100644 --- a/docs/source/_static/stroop_conflict_monitoring.json +++ b/docs/source/_static/stroop_conflict_monitoring.json @@ -1,7040 +1,3343 @@ { - "graphs": [ - { - "controller": "CONTROL", - "edges": { - "ControlProjection for TASK[gain]": { - "functions": [ - { + "Stroop_model": { + "format": "ModECI MDF v0.3.3", + "generating_application": "PsyNeuLink v0.10.0.0+489.g58e55963a3", + "graphs": { + "Stroop_model": { + "conditions": { + "node_specific": { + "word_hidden": { + "type": "EveryNCalls", "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.5 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": { - "source": "ControlProjection for TASK[gain].input_ports.intercept", - "type": "float", - "value": 0.0 - }, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": { - "source": "ControlProjection for TASK[gain].input_ports.slope", - "type": "float", - "value": 1.0 - } - }, - "name": "Linear Function-81", - "type": { - "generic": "Linear" + "dependency": "TASK", + "n": 10 } - } - ], - "name": "ControlProjection for TASK[gain]", - "parameters": { - "PNL": { - "control_signal": null, - "control_signal_params": null, - "execution_count": 0, - "has_initializers": false }, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "weight": null - }, - "receiver": "TASK", - "receiver_port": "gain", - "sender": "CONTROL", - "sender_port": "TASK[gain] ControlSignal", - "type": { - "PNL": "ControlProjection", - "generic": null - } - }, - "MappingProjection from Conflict Monitor[OUTCOME] to CONTROL[OUTCOME]": { - "functions": [ - { + "color_hidden": { + "type": "EveryNCalls", "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "is_finished_flag": true, - "matrix": { - "source": "MappingProjection from Conflict Monitor[OUTCOME] to CONTROL[OUTCOME].input_ports.matrix", - "type": "numpy.array", - "value": [ - [ - 1.0 - ] - ] - }, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0 - }, - "name": "LinearMatrix Function-2", - "type": { - "PNL": "LinearMatrix", - "generic": null + "dependency": "TASK", + "n": 10 } - } - ], - "name": "MappingProjection from Conflict Monitor[OUTCOME] to CONTROL[OUTCOME]", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false }, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "matrix": [ - [ - 1.0 - ] - ], - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "weight": null - }, - "receiver": "CONTROL", - "receiver_port": "OUTCOME", - "sender": "Conflict Monitor", - "sender_port": "OUTCOME", - "type": { - "PNL": "MappingProjection", - "generic": null - } - }, - "MappingProjection from OUTPUT[OutputPort-0] to Conflict Monitor[InputPort-0]": { - "functions": [ - { + "OUTPUT": { + "type": "All", "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.5, - 0.5 - ] - }, - "bounds": null, - "execute_until_finished": true, - "is_finished_flag": true, - "matrix": { - "source": "MappingProjection from OUTPUT[OutputPort-0] to Conflict Monitor[InputPort-0].input_ports.matrix", - "type": "numpy.array", - "value": [ - [ - 1.0, - 0.0 - ], - [ - 0.0, - 1.0 - ] - ] - }, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0 - }, - "name": "LinearMatrix Function-1", - "type": { - "PNL": "LinearMatrix", - "generic": null + "args": [ + { + "type": "EveryNCalls", + "args": { + "dependency": "color_hidden", + "n": 1 + } + }, + { + "type": "EveryNCalls", + "args": { + "dependency": "word_hidden", + "n": 1 + } + } + ] } - } - ], - "name": "MappingProjection from OUTPUT[OutputPort-0] to Conflict Monitor[InputPort-0]", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false }, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "matrix": [ - [ - 1.0, - 0.0 - ], - [ - 0.0, - 1.0 - ] - ], - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "weight": null - }, - "receiver": "Conflict Monitor", - "receiver_port": "Value of OUTPUT [OutputPort-0]", - "sender": "OUTPUT", - "sender_port": "OutputPort-0", - "type": { - "PNL": "MappingProjection", - "generic": null - } - }, - "MappingProjection from OUTPUT[OutputPort-0] to DECISION[ARRAY]": { - "functions": [ - { + "DECISION": { + "type": "EveryNCalls", "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.5, - 0.5 - ] - }, - "bounds": null, - "execute_until_finished": true, - "is_finished_flag": true, - "matrix": { - "source": "MappingProjection from OUTPUT[OutputPort-0] to DECISION[ARRAY].input_ports.matrix", - "type": "numpy.array", - "value": [ - [ - 1.0, - 0.0 - ], - [ - 0.0, - 1.0 - ] - ] - }, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0 - }, - "name": "LinearMatrix Function-10", - "type": { - "PNL": "LinearMatrix", - "generic": null + "dependency": "OUTPUT", + "n": 1 } } - ], - "name": "MappingProjection from OUTPUT[OutputPort-0] to DECISION[ARRAY]", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false - }, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "matrix": [ - [ - 1.0, - 0.0 - ], - [ - 0.0, - 1.0 - ] - ], - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "weight": null }, - "receiver": "DECISION", - "receiver_port": "ARRAY", - "sender": "OUTPUT", - "sender_port": "OutputPort-0", - "type": { - "PNL": "MappingProjection", - "generic": null - } - }, - "MappingProjection from TASK[RESULT] to color_hidden[InputPort-0]": { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.6283161882953663, - 0.6283161882953663 - ] - }, - "bounds": null, - "execute_until_finished": true, - "is_finished_flag": true, - "matrix": { - "source": "MappingProjection from TASK[RESULT] to color_hidden[InputPort-0].input_ports.matrix", - "type": "numpy.array", - "value": [ - [ - 4.0, - 4.0 - ], - [ - 0.0, - 0.0 - ] - ] - }, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0 - }, - "name": "LinearMatrix Function-8", - "type": { - "PNL": "LinearMatrix", - "generic": null - } - } - ], - "name": "MappingProjection from TASK[RESULT] to color_hidden[InputPort-0]", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false + "termination": { + "environment_sequence": { + "type": "Never", + "args": {} }, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "matrix": [ - [ - 4.0, - 4.0 - ], - [ - 0.0, - 0.0 - ] - ], - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "weight": null - }, - "receiver": "color_hidden", - "receiver_port": "InputPort-0", - "sender": "TASK", - "sender_port": "RESULT", - "type": { - "PNL": "MappingProjection", - "generic": null - } - }, - "MappingProjection from TASK[RESULT] to word_hidden[InputPort-0]": { - "functions": [ - { + "environment_state_update": { + "type": "AllHaveRun", "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.6283161882953663, - 0.6283161882953663 - ] - }, - "bounds": null, - "execute_until_finished": true, - "is_finished_flag": true, - "matrix": { - "source": "MappingProjection from TASK[RESULT] to word_hidden[InputPort-0].input_ports.matrix", - "type": "numpy.array", - "value": [ - [ - 0.0, - 0.0 - ], - [ - 4.0, - 4.0 - ] - ] - }, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0 - }, - "name": "LinearMatrix Function-9", - "type": { - "PNL": "LinearMatrix", - "generic": null + "dependencies": [] } } - ], - "name": "MappingProjection from TASK[RESULT] to word_hidden[InputPort-0]", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false - }, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "matrix": [ - [ - 0.0, - 0.0 - ], - [ - 4.0, - 4.0 - ] - ], - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "weight": null - }, - "receiver": "word_hidden", - "receiver_port": "InputPort-0", - "sender": "TASK", - "sender_port": "RESULT", - "type": { - "PNL": "MappingProjection", - "generic": null } }, - "MappingProjection from color_hidden[OutputPort-0] to OUTPUT[InputPort-0]": { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.017986209962091562, - 0.017986209962091562 - ] - }, - "bounds": null, - "execute_until_finished": true, - "is_finished_flag": true, - "matrix": { - "source": "MappingProjection from color_hidden[OutputPort-0] to OUTPUT[InputPort-0].input_ports.matrix", - "type": "numpy.array", - "value": [ - [ - 2.0, - -2.0 - ], - [ - -2.0, - 2.0 - ] - ] - }, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0 - }, - "name": "LinearMatrix Function-4", - "type": { - "PNL": "LinearMatrix", - "generic": null - } - } + "metadata": { + "type": "Composition", + "results": [], + "input_specification": null, + "retain_old_simulation_data": false, + "simulation_results": [], + "variable": [ + 0 ], - "name": "MappingProjection from color_hidden[OutputPort-0] to OUTPUT[InputPort-0]", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false - }, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "matrix": [ - [ - 2.0, - -2.0 - ], - [ - -2.0, - 2.0 - ] - ], - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "weight": null - }, - "receiver": "OUTPUT", - "receiver_port": "InputPort-0", - "sender": "color_hidden", - "sender_port": "OutputPort-0", - "type": { - "PNL": "MappingProjection", - "generic": null - } - }, - "MappingProjection from color_input[OutputPort-0] to color_hidden[InputPort-0]": { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0, - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "is_finished_flag": true, - "matrix": { - "source": "MappingProjection from color_input[OutputPort-0] to color_hidden[InputPort-0].input_ports.matrix", - "type": "numpy.array", - "value": [ - [ - 2.0, - -2.0 - ], - [ - -2.0, - 2.0 - ] - ] - }, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0 - }, - "name": "LinearMatrix Function-3", - "type": { - "PNL": "LinearMatrix", - "generic": null - } - } + "max_executions_before_finished": 1000, + "execute_until_finished": true, + "has_initializers": false, + "node_ordering": [ + "color_input", + "color_hidden", + "OUTPUT", + "word_input", + "word_hidden", + "task_input", + "TASK", + "DECISION", + "Conflict_Monitor", + "CONTROL" ], - "name": "MappingProjection from color_input[OutputPort-0] to color_hidden[InputPort-0]", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false - }, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "matrix": [ - [ - 2.0, - -2.0 - ], - [ - -2.0, - 2.0 - ] - ], - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "weight": null - }, - "receiver": "color_hidden", - "receiver_port": "InputPort-0", - "sender": "color_input", - "sender_port": "OutputPort-0", - "type": { - "PNL": "MappingProjection", - "generic": null - } - }, - "MappingProjection from task_input[OutputPort-0] to TASK[InputPort-0]": { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0, - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "is_finished_flag": true, - "matrix": { - "source": "MappingProjection from task_input[OutputPort-0] to TASK[InputPort-0].input_ports.matrix", - "type": "numpy.array", - "value": [ - [ - 1.0, - 0.0 - ], - [ - 0.0, - 1.0 - ] - ] - }, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0 - }, - "name": "LinearMatrix Function-7", - "type": { - "PNL": "LinearMatrix", - "generic": null - } - } + "required_node_roles": [ + [ + "Conflict_Monitor", + "NodeRole.CONTROLLER_OBJECTIVE" + ] ], - "name": "MappingProjection from task_input[OutputPort-0] to TASK[InputPort-0]", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false - }, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "matrix": [ - [ - 1.0, - 0.0 - ], - [ - 0.0, - 1.0 - ] - ], - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "weight": null - }, - "receiver": "TASK", - "receiver_port": "InputPort-0", - "sender": "task_input", - "sender_port": "OutputPort-0", - "type": { - "PNL": "MappingProjection", - "generic": null - } - }, - "MappingProjection from word_hidden[OutputPort-0] to OUTPUT[InputPort-0]": { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.017986209962091562, - 0.017986209962091562 + "controller": { + "CONTROL": { + "metadata": { + "type": "ControlMechanism", + "input_port_variables": null, + "output_labels_dict": {}, + "variable": [ + [ + 1.0 ] - }, - "bounds": null, + ], "execute_until_finished": true, - "is_finished_flag": true, - "matrix": { - "source": "MappingProjection from word_hidden[OutputPort-0] to OUTPUT[InputPort-0].input_ports.matrix", - "type": "numpy.array", - "value": [ - [ - 3.0, - -3.0 - ], - [ - -3.0, - 3.0 - ] - ] - }, + "has_initializers": false, + "outcome": null, + "modulation": "multiplicative_param", + "simulation_ids": [], "max_executions_before_finished": 1000, - "num_executions_before_finished": 0 - }, - "name": "LinearMatrix Function-6", - "type": { - "PNL": "LinearMatrix", - "generic": null - } - } - ], - "name": "MappingProjection from word_hidden[OutputPort-0] to OUTPUT[InputPort-0]", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false - }, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "matrix": [ - [ - 3.0, - -3.0 - ], - [ - -3.0, - 3.0 - ] - ], - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "weight": null - }, - "receiver": "OUTPUT", - "receiver_port": "InputPort-0", - "sender": "word_hidden", - "sender_port": "OutputPort-0", - "type": { - "PNL": "MappingProjection", - "generic": null - } - }, - "MappingProjection from word_input[OutputPort-0] to word_hidden[InputPort-0]": { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0, - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "is_finished_flag": true, - "matrix": { - "source": "MappingProjection from word_input[OutputPort-0] to word_hidden[InputPort-0].input_ports.matrix", - "type": "numpy.array", - "value": [ - [ - 3.0, - -3.0 - ], - [ - -3.0, - 3.0 - ] - ] - }, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0 - }, - "name": "LinearMatrix Function-5", - "type": { - "PNL": "LinearMatrix", - "generic": null - } - } - ], - "name": "MappingProjection from word_input[OutputPort-0] to word_hidden[InputPort-0]", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false - }, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "matrix": [ - [ - 3.0, - -3.0 - ], - [ - -3.0, - 3.0 - ] - ], - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "weight": null - }, - "receiver": "word_hidden", - "receiver_port": "InputPort-0", - "sender": "word_input", - "sender_port": "OutputPort-0", - "type": { - "PNL": "MappingProjection", - "generic": null - } - }, - "TASK recurrent projection": { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.6283161882953663, - 0.6283161882953663 - ] - }, - "bounds": null, - "execute_until_finished": true, - "is_finished_flag": true, - "matrix": { - "source": "TASK recurrent projection.input_ports.matrix", - "type": "numpy.array", - "value": [ - [ - 0.0, - -1.0 - ], - [ - -1.0, - 0.0 - ] - ] - }, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0 - }, - "name": "LinearMatrix Function-0", - "type": { - "PNL": "LinearMatrix", - "generic": null - } - } - ], - "name": "TASK recurrent projection", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false - }, - "auto": 1, - "execute_until_finished": true, - "exponent": null, - "hetero": 0, - "is_finished_flag": true, - "matrix": [ - [ - 0.0, - -1.0 - ], - [ - -1.0, - 0.0 - ] - ], - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "weight": null - }, - "receiver": "TASK", - "receiver_port": "InputPort-0", - "sender": "TASK", - "sender_port": "RESULT", - "type": { - "PNL": "AutoAssociativeProjection", - "generic": null - } - } - }, - "name": "Stroop_model", - "nodes": { - "CONTROL": { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - [ - 1.0 - ] - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_control_signals": 1, - "num_executions_before_finished": 0 - }, - "name": "Default Control Function-0", - "type": { - "PNL": "DefaultAllocationFunction", - "generic": null - } - } - ], - "input_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 - ] - }, - "execute_until_finished": true, - "exponents": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": 0.0, - "operation": "sum", - "scale": 1.0, - "weights": null - }, - "name": "LinearCombination Function-85", - "type": { - "PNL": "LinearCombination", - "generic": null - } - } - ], - "name": "OUTCOME", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "internal_only": false, - "require_projection_in_composition": true, - "shadow_inputs": null, - "variable": [ - 1.0 - ] - }, - "combine": null, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null, - "weight": null - }, - "shape": "(1,)", - "type": { - "PNL": "InputPort", - "generic": null - } - } - ], - "name": "CONTROL", - "output_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "LinearCombination": "LinearCombination", - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3 - }, - "SimpleIntegrator": "SimpleIntegrator", - "adjustment_cost": null, - "adjustment_cost_fct": "Linear", - "adjustment_cost_fct_add_param": 0.0, - "adjustment_cost_fct_mult_param": 1.0, - "bounds": null, - "combine_costs_fct": "Reduce", - "combine_costs_fct_add_param": 0.0, - "combine_costs_fct_mult_param": 1.0, - "combined_costs": null, - "duration_cost": null, - "duration_cost_fct": "SimpleIntegrator", - "duration_cost_fct_add_param": 0.0, - "duration_cost_fct_mult_param": 0.0, - "enabled_cost_functions": 2, - "execute_until_finished": true, - "intensity": [ - 0 - ], - "intensity_cost": [ - 1.6487212707001282 - ], - "intensity_cost_fct": "Exponential", - "intensity_cost_fct_add_param": 0.0, - "intensity_cost_fct_mult_param": 1.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "transfer_fct": "Linear", - "transfer_fct_add_param": null, - "transfer_fct_mult_param": null, - "variable": [ - 0.5 - ] - }, - "name": "TransferWithCosts Function-0", - "type": { - "PNL": "TransferWithCosts", - "generic": null - } - } - ], - "name": "TASK[gain] ControlSignal", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.5 - ] - }, - "adjustment_cost": 0, - "adjustment_cost_function": "Linear", - "allocation_samples": null, - "combine_costs_function": "Reduce", - "cost": null, - "cost_options": 2, - "duration_cost": 0, - "duration_cost_function": "SimpleIntegrator", - "execute_until_finished": true, - "intensity_cost": null, - "intensity_cost_function": "Exponential", - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "modulation": "multiplicative_param", - "num_executions_before_finished": 0, - "projections": [ - [ - "TASK.input_ports.gain", - null, - null, - { - "PROJECTION_TYPE": "ControlProjection" - } - ] + "input_labels_dict": {}, + "net_outcome": null, + "control_signal_costs": null, + "input_ports": [ + "OUTCOME" ], - "transfer_function": "Linear" - }, - "shape": "(1,)", - "type": { - "PNL": "ControlSignal", - "generic": null - } - } - ], - "parameters": { - "PNL": { - "control_signal_costs": null, - "execution_count": 0, - "has_initializers": false, - "input_labels_dict": {}, - "input_port_variables": null, - "modulation": "multiplicative_param", - "net_outcome": null, - "outcome": null, - "output_labels_dict": {}, - "previous_value": null, - "simulation_ids": [], - "variable": [ - [ - 1.0 - ] - ] - }, - "combine_costs": "gANjbnVtcHkKc3VtCnEALg==\n", - "compute_net_outcome": "gANjZGlsbC5fZGlsbApfY3JlYXRlX2Z1bmN0aW9uCnEAKGNkaWxsLl9kaWxsCl9sb2FkX3R5cGUK\ncQFYCAAAAENvZGVUeXBlcQKFcQNScQQoSwJLAEsCSwJLQ0MIfAB8ARgAUwBxBU6FcQYpWAcAAABv\ndXRjb21lcQdYBAAAAGNvc3RxCIZxCVhsAAAAL2hvbWUva2F0aGVyaW5lL2NvZGUvUHN5TmV1TGlu\nay9wc3luZXVsaW5rL2NvcmUvY29tcG9uZW50cy9tZWNoYW5pc21zL21vZHVsYXRvcnkvY29udHJv\nbC9jb250cm9sbWVjaGFuaXNtLnB5cQpYCAAAADxsYW1iZGE+cQtNQQRDAHEMKSl0cQ1ScQ5jcHN5\nbmV1bGluay5jb3JlLmNvbXBvbmVudHMubWVjaGFuaXNtcy5tb2R1bGF0b3J5LmNvbnRyb2wuY29u\ndHJvbG1lY2hhbmlzbQpfX2RpY3RfXwpoC05OfXEPTnRxEFJxES4=\n", - "compute_reconfiguration_cost": null, - "costs": null, - "default_allocation": [ - 0.5 - ], - "execute_until_finished": true, - "input_ports": [ - "OUTCOME" - ], - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "monitor_for_control": [], - "num_executions_before_finished": 0, - "objective_mechanism": { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, + "outcome_input_ports": "[(InputPort OUTCOME)]", + "costs": null, + "compute_net_outcome": "gANjZGlsbC5fZGlsbApfY3JlYXRlX2Z1bmN0aW9uCnEAKGNkaWxsLl9kaWxsCl9jcmVhdGVfY29k\nZQpxAShLAksASwJLAktDQwh8AHwBGABTAHECToVxAylYBwAAAG91dGNvbWVxBFgEAAAAY29zdHEF\nhnEGWGwAAAAvaG9tZS9rYXRoZXJpbmUvY29kZS9Qc3lOZXVMaW5rL3BzeW5ldWxpbmsvY29yZS9j\nb21wb25lbnRzL21lY2hhbmlzbXMvbW9kdWxhdG9yeS9jb250cm9sL2NvbnRyb2xtZWNoYW5pc20u\ncHlxB1gIAAAAPGxhbWJkYT5xCE2cBEMAcQkpKXRxClJxC2Nwc3luZXVsaW5rLmNvcmUuY29tcG9u\nZW50cy5tZWNoYW5pc21zLm1vZHVsYXRvcnkuY29udHJvbC5jb250cm9sbWVjaGFuaXNtCl9fZGlj\ndF9fCmgITk59cQxOdHENUnEOLg==\n", + "objective_mechanism": { + "Conflict_Monitor": { + "metadata": { + "type": "ObjectiveMechanism", + "output_labels_dict": {}, "variable": [ [ 0.0, 0.0 ] - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "matrix": [ - [ - 0, - -2.5 ], - [ - -2.5, - 0 + "input_port_variables": null, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "input_labels_dict": {}, + "has_initializers": false, + "output_ports": [ + "OUTCOME" + ], + "input_ports": [ + { + "OUTPUT": { + "metadata": { + "type": "ProcessingMechanism", + "output_labels_dict": {}, + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "input_port_variables": null, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "input_labels_dict": {}, + "has_initializers": false, + "output_ports": null, + "input_ports": null + }, + "input_ports": { + "OUTPUT_input_port_MappingProjection_from_color_hidden_OutputPort_0__to_OUTPUT_InputPort_0_": { + "shape": "(2,)", + "type": "float64" + }, + "OUTPUT_input_port_MappingProjection_from_word_hidden_OutputPort_0__to_OUTPUT_InputPort_0_": { + "shape": "(2,)", + "type": "float64" + } + }, + "functions": { + "OUTPUT_input_combination_function": { + "function": { + "onnx::ReduceSum": { + "data": "combination_function_input_data", + "axes": 0 + } + }, + "args": { + "data": "combination_function_input_data", + "axes": 0 + } + }, + "OUTPUT_input_combination_function_dimreduce": { + "value": "OUTPUT_input_combination_function[0][0]", + "args": { + "variable0": "OUTPUT_input_combination_function" + } + }, + "Logistic_Function_1": { + "function": { + "logistic": { + "offset": 0.0, + "gain": 1.0, + "scale": 1.0, + "x_0": 0, + "bias": 0.0, + "variable0": "OUTPUT_input_combination_function_dimreduce" + } + }, + "args": { + "offset": 0.0, + "gain": 1.0, + "scale": 1.0, + "x_0": 0, + "bias": 0.0, + "variable0": "OUTPUT_input_combination_function_dimreduce" + }, + "metadata": { + "type": "Logistic", + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "execute_until_finished": true, + "has_initializers": false, + "enable_output_type_conversion": true, + "output_type": "FunctionOutputType.NP_2D_ARRAY", + "changes_shape": false, + "max_executions_before_finished": 1000, + "bounds": [ + 0, + 1 + ], + "function_stateful_params": {} + } + } + }, + "parameters": { + "combination_function_input_data": { + "value": "[OUTPUT_input_port_MappingProjection_from_color_hidden_OutputPort_0__to_OUTPUT_InputPort_0_, OUTPUT_input_port_MappingProjection_from_word_hidden_OutputPort_0__to_OUTPUT_InputPort_0_]" + } + }, + "output_ports": { + "OUTPUT_OutputPort_0": { + "value": "Logistic_Function_1", + "metadata": { + "type": "OutputPort", + "variable": [ + 0.5, + 0.5 + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "require_projection_in_composition": true, + "projections": null + } + } + } + } + } ] - ], - "max_executions_before_finished": 1000, - "metric": "energy", - "metric_fct": null, - "normalize": false, - "num_executions_before_finished": 0, - "transfer_fct": null - }, - "name": "Stability Function-0", - "type": { - "PNL": "Energy", - "generic": null - } - } - ], - "input_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, + }, + "input_ports": { + "Conflict_Monitor_Value_of_OUTPUT__OutputPort_0_": { + "shape": "(1, 2)", + "type": "float64", + "metadata": { + "type": "InputPort", + "shadow_inputs": null, "variable": [ [ 0.0, 0.0 ] - ] - }, - "execute_until_finished": true, - "exponents": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": 0.0, - "operation": "sum", - "scale": 1.0, - "weights": null - }, - "name": "LinearCombination Function-77", - "type": { - "PNL": "LinearCombination", - "generic": null + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "internal_only": true, + "require_projection_in_composition": true, + "exponent": null, + "default_input": null, + "combine": null, + "projections": [ + [ + "OUTPUT.output_ports.OutputPort-0", + null, + null, + { + "PROJECTION_TYPE": "MappingProjection" + } + ] + ], + "weight": null + } } - } - ], - "name": "Value of OUTPUT [OutputPort-0]", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "internal_only": false, - "require_projection_in_composition": true, - "shadow_inputs": null, - "variable": [ - [ - 0.0, - 0.0 - ] - ] }, - "combine": null, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": [ - [ - "OUTPUT.output_ports.OutputPort-0", - null, - null, - { - "PROJECTION_TYPE": "MappingProjection" - } - ] - ], - "weight": null - }, - "shape": "(1, 2)", - "type": { - "PNL": "InputPort", - "generic": null - } - } - ], - "name": "Conflict Monitor", - "output_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - -0.0 - ] + "functions": { + "Stability_Function_0": { + "function": { + "energy": { + "variable0": "Conflict_Monitor_Value_of_OUTPUT__OutputPort_0_" + } }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-71", - "type": { - "generic": "Linear" + "args": { + "variable0": "Conflict_Monitor_Value_of_OUTPUT__OutputPort_0_" + }, + "metadata": { + "type": "Energy", + "output_type": "FunctionOutputType.NP_2D_ARRAY", + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "changes_shape": false, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "enable_output_type_conversion": true, + "metric_fct": { + "Distance_Function_4": { + "function": { + "distance": {} + }, + "args": {}, + "metadata": { + "type": "Distance", + "output_type": "FunctionOutputType.DEFAULT", + "variable": [ + [ + [ + 0.0, + 0.0 + ] + ], + [ + [ + 0.0, + 0.0 + ] + ] + ], + "changes_shape": false, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "enable_output_type_conversion": false, + "metric": "energy", + "normalize": false, + "function_stateful_params": {} + } + } + }, + "metric": "energy", + "matrix": [ + [ + 0, + -2.5 + ], + [ + -2.5, + 0 + ] + ], + "transfer_fct": null, + "normalize": false, + "function_stateful_params": {} + } } - } - ], - "name": "OUTCOME", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - -0.0 - ] }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "OutputPort", - "generic": null + "output_ports": { + "Conflict_Monitor_OUTCOME": { + "value": "Stability_Function_0", + "metadata": { + "type": "OutputPort", + "variable": [ + -0.0 + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "require_projection_in_composition": true, + "projections": null + } + } + } } - } - ], - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "input_labels_dict": {}, - "input_port_variables": null, - "output_labels_dict": {}, - "previous_value": null, - "variable": [ - [ - 0.0, - 0.0 - ] - ] }, - "execute_until_finished": true, - "input_ports": [ + "output_ports": [ { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - [ - 0.0, - 0.0 - ] + "name": "gain", + "MECHANISM": { + "TASK": { + "metadata": { + "type": "LCAMechanism", + "input_port_variables": null, + "output_labels_dict": {}, + "variable": [ + [ + 0.0, + 0.0 ] - }, - "bias": { - "source": "OUTPUT.input_ports.bias", - "type": "float", - "value": 0.0 - }, - "bounds": null, + ], "execute_until_finished": true, - "gain": { - "source": "OUTPUT.input_ports.gain", - "type": "float", - "value": 1.0 - }, - "is_finished_flag": true, + "has_initializers": false, + "termination_measure_value": 0.0, "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": { - "source": "OUTPUT.input_ports.offset", - "type": "float", - "value": 0.0 - }, - "scale": { - "source": "OUTPUT.input_ports.scale", - "type": "float", - "value": 1.0 - }, - "x_0": { - "source": "OUTPUT.input_ports.x_0", - "type": "float", - "value": 0.0 - } - }, - "name": "Logistic Function-3", - "type": { - "generic": "Logistic" - } - } - ], - "input_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, + "input_labels_dict": {}, + "input_ports": null, + "matrix": "InverseHollowMatrix", + "integrator_function": { + "LeakyCompetingIntegrator_Function_0": { + "value": "previous_value + (-rate * previous_value + variable0) * time_step_size + noise * (time_step_size ** 0.5)", + "args": { + "time_step_size": 0.1, + "offset": 0.0, + "rate": 0.5, + "noise": 0.0 + }, + "metadata": { + "type": "LeakyCompetingIntegrator", + "initializer": [ + [ + 0.5, + 0.5 + ] + ], "variable": [ [ 0.0, 0.0 - ], + ] + ], + "execute_until_finished": true, + "has_initializers": true, + "enable_output_type_conversion": false, + "output_type": "FunctionOutputType.DEFAULT", + "changes_shape": false, + "max_executions_before_finished": 1000, + "function_stateful_params": { + "previous_value": { + "id": "previous_value", + "default_initial_value": [ + [ + 0.5, + 0.5 + ] + ], + "value": "LeakyCompetingIntegrator_Function_0" + } + } + } + } + }, + "combination_function": { + "LinearCombination_Function_23": { + "function": { + "linearcombination": { + "offset": 0.0, + "scale": 1.0 + } + }, + "args": { + "offset": 0.0, + "scale": 1.0 + }, + "metadata": { + "type": "LinearCombination", + "variable": [ [ 0.0, 0.0 ] - ] - }, - "execute_until_finished": true, - "exponents": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": 0.0, - "operation": "sum", - "scale": 1.0, - "weights": null - }, - "name": "LinearCombination Function-33", - "type": { - "PNL": "LinearCombination", - "generic": null + ], + "execute_until_finished": true, + "has_initializers": false, + "enable_output_type_conversion": false, + "output_type": "FunctionOutputType.DEFAULT", + "changes_shape": false, + "max_executions_before_finished": 1000, + "exponents": null, + "weights": null, + "operation": "sum", + "function_stateful_params": {} + } } - } - ], - "name": "InputPort-0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "internal_only": false, - "require_projection_in_composition": true, - "shadow_inputs": null, - "variable": [ - [ - 0.0, - 0.0 - ], - [ - 0.0, - 0.0 - ] + }, + "integrator_mode": true, + "has_recurrent_input_port": false, + "on_resume_integrator_mode": "current_value", + "clip": null, + "output_ports": [ + "RESULTS" + ], + "enable_learning": false, + "integrator_function_value": [ + [ + 0 ] + ], + "termination_comparison_op": ">=", + "termination_threshold": null, + "termination_measure": "max" + }, + "input_ports": { + "TASK_input_port_TASK_recurrent_projection": { + "shape": "(2,)", + "type": "float64" }, - "combine": null, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null, - "weight": null + "TASK_input_port_MappingProjection_from_task_input_OutputPort_0__to_TASK_InputPort_0_": { + "shape": "(2,)", + "type": "float64" + } }, - "shape": "(2, 2)", - "type": { - "PNL": "InputPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 + "functions": { + "TASK_input_combination_function": { + "function": { + "onnx::ReduceSum": { + "data": "combination_function_input_data", + "axes": 0 + } }, - "name": "Linear Function-15", - "type": { - "generic": "Linear" + "args": { + "data": "combination_function_input_data", + "axes": 0 } - } - ], - "name": "scale", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 1.0 - ] }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { + "TASK_input_combination_function_dimreduce": { + "value": "TASK_input_combination_function[0][0]", "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-16", - "type": { - "generic": "Linear" + "variable0": "TASK_input_combination_function" } - } - ], - "name": "offset", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { + "Logistic_Function_5": { + "function": { + "logistic": { + "offset": 0.0, + "gain": 1.0, + "scale": 1.0, + "x_0": 0, + "bias": 0.0, + "variable0": "LeakyCompetingIntegrator_Function_0" + } + }, "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ + "offset": 0.0, + "gain": 1.0, + "scale": 1.0, + "x_0": 0, + "bias": 0.0, + "variable0": "LeakyCompetingIntegrator_Function_0" + }, + "metadata": { + "type": "Logistic", + "variable": [ + [ + 0.0, 0.0 ] - }, - "bounds": null, + ], "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, + "has_initializers": false, + "enable_output_type_conversion": true, + "output_type": "FunctionOutputType.NP_2D_ARRAY", + "changes_shape": false, "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-17", - "type": { - "generic": "Linear" + "bounds": [ + 0, + 1 + ], + "function_stateful_params": {} } - } - ], - "name": "x_0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { + "LeakyCompetingIntegrator_Function_0": { + "value": "previous_value + (-0.5 * previous_value + TASK_input_combination_function_dimreduce) * 0.1 + 0.0 * (0.1 ** 0.5)", "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 + "time_step_size": 0.1, + "offset": 0.0, + "rate": 0.5, + "noise": 0.0, + "variable0": "TASK_input_combination_function_dimreduce" + }, + "metadata": { + "type": "LeakyCompetingIntegrator", + "initializer": [ + [ + 0.5, + 0.5 ] - }, - "bounds": null, + ], + "variable": [ + [ + 0.0, + 0.0 + ] + ], "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, + "has_initializers": true, + "enable_output_type_conversion": false, + "output_type": "FunctionOutputType.DEFAULT", + "changes_shape": false, "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-18", - "type": { - "generic": "Linear" + "function_stateful_params": { + "previous_value": { + "id": "previous_value", + "default_initial_value": [ + [ + 0.5, + 0.5 + ] + ], + "value": "LeakyCompetingIntegrator_Function_0" + } + } } } - ], - "name": "gain", + }, "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 1.0 - ] + "hetero": { + "value": -1.0 }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-19", - "type": { - "generic": "Linear" - } - } - ], - "name": "bias", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] + "smoothing_factor": { + "value": 0.5 }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null + "auto": { + "value": 0.0 + }, + "competition": { + "value": 1.0 + }, + "combination_function_input_data": { + "value": "[TASK_input_port_TASK_recurrent_projection, TASK_input_port_MappingProjection_from_task_input_OutputPort_0__to_TASK_InputPort_0_]" + }, + "previous_value": { + "default_initial_value": [ + [ + 0.5, + 0.5 + ] + ], + "value": "LeakyCompetingIntegrator_Function_0" + } }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - } - ], - "name": "OUTPUT", - "output_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.5, - 0.5 - ] - }, - "bounds": null, + "output_ports": { + "TASK_RESULT": { + "value": "Logistic_Function_5", + "metadata": { + "type": "OutputPort", + "variable": [ + 0.5, + 0.5 + ], "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-21", - "type": { - "generic": "Linear" + "has_initializers": false, + "require_projection_in_composition": true, + "projections": null } } - ], - "name": "OutputPort-0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.5, - 0.5 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(2,)", - "type": { - "PNL": "OutputPort", - "generic": null } } - ], - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "input_labels_dict": {}, - "input_port_variables": null, - "output_labels_dict": {}, - "previous_value": null, - "variable": [ - [ - 0.0, - 0.0 - ] - ] - }, - "execute_until_finished": true, - "input_ports": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "output_ports": null - }, - "type": { - "PNL": "ProcessingMechanism", - "generic": null } } ], - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "output_ports": [ - "OUTCOME" + "default_allocation": [ + 0.5 + ], + "reconfiguration_cost": null, + "outcome_input_ports_option": "separate", + "combine_costs": "gANjbnVtcHkKc3VtCnEALg==\n", + "compute_reconfiguration_cost": null, + "monitor_for_control": [] + }, + "input_ports": { + "CONTROL_OUTCOME": { + "shape": "(1,)", + "type": "float64", + "metadata": { + "type": "InputPort", + "shadow_inputs": null, + "variable": [ + 0.0 + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "internal_only": true, + "require_projection_in_composition": true, + "exponent": null, + "default_input": null, + "combine": null, + "projections": null, + "weight": null + } + } + }, + "functions": { + "Default_Control_Function_0": { + "function": { + "defaultallocationfunction": { + "num_control_signals": 1, + "variable0": "CONTROL_OUTCOME" + } + }, + "args": { + "num_control_signals": 1, + "variable0": "CONTROL_OUTCOME" + }, + "metadata": { + "type": "DefaultAllocationFunction", + "output_type": "FunctionOutputType.NP_2D_ARRAY", + "variable": [ + [ + 1.0 + ] + ], + "changes_shape": false, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "enable_output_type_conversion": true, + "function_stateful_params": {} + } + } + }, + "output_ports": { + "CONTROL_TASK_gain__ControlSignal": { + "value": "Default_Control_Function_0", + "metadata": { + "type": "ControlSignal", + "require_projection_in_composition": true, + "variable": [ + 0.5 + ], + "execute_until_finished": true, + "has_initializers": false, + "max_executions_before_finished": 1000, + "projections": [ + [ + "TASK.input_ports.gain", + null, + null, + { + "PROJECTION_TYPE": "ControlProjection" + } + ] + ], + "modulation": "multiplicative_param", + "allocation_samples": null + } + } + } + } + } + }, + "nodes": { + "color_input": { + "metadata": { + "type": "ProcessingMechanism", + "output_labels_dict": {}, + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "input_port_variables": null, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "input_labels_dict": {}, + "has_initializers": false, + "output_ports": null, + "input_ports": null + }, + "input_ports": { + "color_input_InputPort_0": { + "shape": "(2,)", + "type": "float64", + "metadata": { + "type": "InputPort", + "shadow_inputs": null, + "variable": [ + 0.0, + 0.0 + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "internal_only": false, + "require_projection_in_composition": true, + "exponent": null, + "default_input": null, + "combine": null, + "projections": null, + "weight": null + } + } + }, + "functions": { + "Linear_Function_3": { + "function": { + "linear": { + "slope": 1.0, + "intercept": 0.0, + "variable0": "color_input_InputPort_0" + } + }, + "args": { + "slope": 1.0, + "intercept": 0.0, + "variable0": "color_input_InputPort_0" + }, + "metadata": { + "type": "Linear", + "output_type": "FunctionOutputType.NP_2D_ARRAY", + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "changes_shape": false, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "enable_output_type_conversion": true, + "bounds": null, + "function_stateful_params": {} + } + } + }, + "output_ports": { + "color_input_OutputPort_0": { + "value": "Linear_Function_3", + "metadata": { + "type": "OutputPort", + "variable": [ + 0.0, + 0.0 + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "require_projection_in_composition": true, + "projections": null + } + } + } + }, + "color_hidden": { + "metadata": { + "type": "ProcessingMechanism", + "output_labels_dict": {}, + "variable": [ + [ + 0.0, + 0.0 ] + ], + "input_port_variables": null, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "input_labels_dict": {}, + "has_initializers": false, + "output_ports": null, + "input_ports": null + }, + "input_ports": { + "color_hidden_input_port_MappingProjection_from_color_input_OutputPort_0__to_color_hidden_InputPort_0_": { + "shape": "(2,)", + "type": "float64" }, - "type": { - "PNL": "ObjectiveMechanism", - "generic": null + "color_hidden_input_port_MappingProjection_from_TASK_RESULT__to_color_hidden_InputPort_0_": { + "shape": "(2,)", + "type": "float64" } }, - "output_ports": [ - { - "MECHANISM": { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - [ - 0.0, - 0.0 - ] - ] - }, - "bias": { - "source": "TASK.input_ports.bias", - "type": "float", - "value": 0.0 - }, - "bounds": null, - "execute_until_finished": true, - "gain": { - "source": "TASK.input_ports.gain", - "type": "float", - "value": 1.0 - }, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": { - "source": "TASK.input_ports.offset", - "type": "float", - "value": 0.0 - }, - "scale": { - "source": "TASK.input_ports.scale", - "type": "float", - "value": 1.0 - }, - "x_0": { - "source": "TASK.input_ports.x_0", - "type": "float", - "value": 0.0 - } - }, - "name": "Logistic Function-5", - "type": { - "generic": "Logistic" - } - } + "functions": { + "color_hidden_input_combination_function": { + "function": { + "onnx::ReduceSum": { + "data": "combination_function_input_data", + "axes": 0 + } + }, + "args": { + "data": "combination_function_input_data", + "axes": 0 + } + }, + "color_hidden_input_combination_function_dimreduce": { + "value": "color_hidden_input_combination_function[0][0]", + "args": { + "variable0": "color_hidden_input_combination_function" + } + }, + "Logistic_Function_0": { + "function": { + "logistic": { + "offset": 0.0, + "gain": 1.0, + "scale": 1.0, + "x_0": 0, + "bias": -4.0, + "variable0": "color_hidden_input_combination_function_dimreduce" + } + }, + "args": { + "offset": 0.0, + "gain": 1.0, + "scale": 1.0, + "x_0": 0, + "bias": -4.0, + "variable0": "color_hidden_input_combination_function_dimreduce" + }, + "metadata": { + "type": "Logistic", + "variable": [ + [ + 0.0, + 0.0 + ] ], - "input_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - [ - 0.0, - 0.0 - ], - [ - 0.0, - 0.0 - ] - ] - }, - "execute_until_finished": true, - "exponents": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": 0.0, - "operation": "sum", - "scale": 1.0, - "weights": null - }, - "name": "LinearCombination Function-65", - "type": { - "PNL": "LinearCombination", - "generic": null - } - } - ], - "name": "InputPort-0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "internal_only": false, - "require_projection_in_composition": true, - "shadow_inputs": null, - "variable": [ - [ - 0.0, - 0.0 - ], - [ - 0.0, - 0.0 - ] - ] - }, - "combine": null, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null, - "weight": null - }, - "shape": "(2, 2)", - "type": { - "PNL": "InputPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-39", - "type": { - "generic": "Linear" - } - } - ], - "name": "scale", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-40", - "type": { - "generic": "Linear" - } - } - ], - "name": "offset", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-41", - "type": { - "generic": "Linear" - } - } - ], - "name": "x_0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-42", - "type": { - "generic": "Linear" - } - } - ], - "name": "gain", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-43", - "type": { - "generic": "Linear" - } - } - ], - "name": "bias", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.5 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-44", - "type": { - "generic": "Linear" - } - } - ], - "name": "integration_rate", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.5 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.1 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-45", - "type": { - "generic": "Linear" - } - } - ], - "name": "time_step_size", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.1 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-46", - "type": { - "generic": "Linear" - } - } - ], - "name": "competition", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.5 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-47", - "type": { - "generic": "Linear" - } - } - ], - "name": "smoothing_factor", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.5 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.5 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-48", - "type": { - "generic": "Linear" - } - } - ], - "name": "leak", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.5 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - -1.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-49", - "type": { - "generic": "Linear" - } - } - ], - "name": "hetero", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - -1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-50", - "type": { - "generic": "Linear" - } - } - ], - "name": "noise", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-51", - "type": { - "generic": "Linear" - } - } - ], - "name": "auto", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - } - ], - "name": "TASK", - "output_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.6283161882953663, - 0.6283161882953663 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-54", - "type": { - "generic": "Linear" - } - } - ], - "name": "RESULT", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.6283161882953663, - 0.6283161882953663 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(2,)", - "type": { - "PNL": "OutputPort", - "generic": null - } - } - ], - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "input_labels_dict": {}, - "input_port_variables": null, - "output_labels_dict": {}, - "previous_value": null, - "variable": [ - [ - 0.0, - 0.0 - ] - ] - }, - "auto": 0.0, - "clip": null, - "combination_function": "LinearCombination", - "competition": 1.0, - "enable_learning": false, - "execute_until_finished": true, - "has_integrated": false, - "has_recurrent_input_port": false, - "hetero": -1.0, - "initial_value": [ - [ - 0.5, - 0.5 - ] - ], - "input_ports": null, - "integration_rate": 0.5, - "integrator_function": "LeakyCompetingIntegrator", - "integrator_function_value": [ - [ - 0 - ] - ], - "integrator_mode": true, - "is_finished_flag": true, - "leak": 0.5, - "learning_condition": null, - "learning_function": "Hebbian", - "learning_rate": null, - "matrix": "HollowMatrix", - "max_executions_before_finished": 1000, - "noise": 0.0, - "num_executions_before_finished": 0, - "on_resume_integrator_mode": "instantaneous_mode_value", - "output_ports": [ - "RESULT" - ], - "smoothing_factor": 0.5, - "termination_comparison_op": ">=", - "termination_measure": "max", - "termination_measure_value": 0.0, - "termination_threshold": null, - "time_step_size": 0.1 - }, - "type": { - "PNL": "LCAMechanism", - "generic": null - } - }, - "name": "gain" - } - ], - "reconfiguration_cost": null, - "system": null - }, - "type": { - "PNL": "ControlMechanism", - "generic": null - } - }, - "Conflict Monitor": { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - [ - 0.0, - 0.0 - ] - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "matrix": [ - [ - 0, - -2.5 - ], - [ - -2.5, - 0 - ] - ], - "max_executions_before_finished": 1000, - "metric": "energy", - "metric_fct": null, - "normalize": false, - "num_executions_before_finished": 0, - "transfer_fct": null - }, - "name": "Stability Function-0", - "type": { - "PNL": "Energy", - "generic": null - } - } - ], - "input_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - [ - 0.0, - 0.0 - ] - ] - }, - "execute_until_finished": true, - "exponents": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": 0.0, - "operation": "sum", - "scale": 1.0, - "weights": null - }, - "name": "LinearCombination Function-77", - "type": { - "PNL": "LinearCombination", - "generic": null - } - } - ], - "name": "Value of OUTPUT [OutputPort-0]", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "internal_only": false, - "require_projection_in_composition": true, - "shadow_inputs": null, - "variable": [ - [ - 0.0, - 0.0 - ] - ] - }, - "combine": null, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": [ - [ - "OUTPUT.output_ports.OutputPort-0", - null, - null, - { - "PROJECTION_TYPE": "MappingProjection" - } - ] - ], - "weight": null - }, - "shape": "(1, 2)", - "type": { - "PNL": "InputPort", - "generic": null - } - } - ], - "name": "Conflict Monitor", - "output_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - -0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-71", - "type": { - "generic": "Linear" - } - } - ], - "name": "OUTCOME", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - -0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "OutputPort", - "generic": null - } - } - ], - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "input_labels_dict": {}, - "input_port_variables": null, - "output_labels_dict": {}, - "previous_value": null, - "variable": [ - [ - 0.0, - 0.0 - ] - ] - }, - "execute_until_finished": true, - "input_ports": [ - { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - [ - 0.0, - 0.0 - ] - ] - }, - "bias": { - "source": "OUTPUT.input_ports.bias", - "type": "float", - "value": 0.0 - }, - "bounds": null, - "execute_until_finished": true, - "gain": { - "source": "OUTPUT.input_ports.gain", - "type": "float", - "value": 1.0 - }, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": { - "source": "OUTPUT.input_ports.offset", - "type": "float", - "value": 0.0 - }, - "scale": { - "source": "OUTPUT.input_ports.scale", - "type": "float", - "value": 1.0 - }, - "x_0": { - "source": "OUTPUT.input_ports.x_0", - "type": "float", - "value": 0.0 - } - }, - "name": "Logistic Function-3", - "type": { - "generic": "Logistic" - } - } - ], - "input_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - [ - 0.0, - 0.0 - ], - [ - 0.0, - 0.0 - ] - ] - }, - "execute_until_finished": true, - "exponents": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": 0.0, - "operation": "sum", - "scale": 1.0, - "weights": null - }, - "name": "LinearCombination Function-33", - "type": { - "PNL": "LinearCombination", - "generic": null - } - } - ], - "name": "InputPort-0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "internal_only": false, - "require_projection_in_composition": true, - "shadow_inputs": null, - "variable": [ - [ - 0.0, - 0.0 - ], - [ - 0.0, - 0.0 - ] - ] - }, - "combine": null, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null, - "weight": null - }, - "shape": "(2, 2)", - "type": { - "PNL": "InputPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-15", - "type": { - "generic": "Linear" - } - } - ], - "name": "scale", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-16", - "type": { - "generic": "Linear" - } - } - ], - "name": "offset", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-17", - "type": { - "generic": "Linear" - } - } - ], - "name": "x_0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-18", - "type": { - "generic": "Linear" - } - } - ], - "name": "gain", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-19", - "type": { - "generic": "Linear" - } - } - ], - "name": "bias", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - } - ], - "name": "OUTPUT", - "output_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.5, - 0.5 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-21", - "type": { - "generic": "Linear" - } - } - ], - "name": "OutputPort-0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.5, - 0.5 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(2,)", - "type": { - "PNL": "OutputPort", - "generic": null - } - } - ], - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "input_labels_dict": {}, - "input_port_variables": null, - "output_labels_dict": {}, - "previous_value": null, - "variable": [ - [ - 0.0, - 0.0 - ] - ] - }, - "execute_until_finished": true, - "input_ports": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "output_ports": null - }, - "type": { - "PNL": "ProcessingMechanism", - "generic": null - } - } - ], - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "output_ports": [ - "OUTCOME" - ] - }, - "type": { - "PNL": "ObjectiveMechanism", - "generic": null - } - }, - "DECISION": { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - [ - 0.0 - ] - ] - }, - "bias": 0.5, - "drift_rate": { - "source": "DECISION.input_ports.drift_rate", - "type": "float", - "value": 1.0 - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "noise": { - "source": "DECISION.input_ports.noise", - "type": "float", - "value": 0.5 - }, - "num_executions_before_finished": 0, - "starting_point": { - "source": "DECISION.input_ports.starting_point", - "type": "float", - "value": 0.0 - }, - "t0": 0.2, - "threshold": { - "source": "DECISION.input_ports.threshold", - "type": "float", - "value": 1.0 - } - }, - "name": "Drift Diffusion Analytical Function-10", - "type": { - "PNL": "DriftDiffusionAnalytical", - "generic": null - } - } - ], - "input_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - [ - 0.0, - 0.0 - ] - ] - }, - "execute_until_finished": true, - "exponents": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": 0.0, - "operation": "sum", - "scale": 1.0, - "weights": [ - 1, - -1 - ] - }, - "name": "Reduce Function-1", - "type": { - "PNL": "Reduce", - "generic": null - } - } - ], - "name": "ARRAY", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "internal_only": false, - "require_projection_in_composition": true, - "shadow_inputs": null, - "variable": [ - [ - 0.0, - 0.0 - ] - ] - }, - "combine": null, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null, - "weight": null - }, - "shape": "(1, 2)", - "type": { - "PNL": "InputPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-58", - "type": { - "generic": "Linear" - } - } - ], - "name": "drift_rate", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-59", - "type": { - "generic": "Linear" - } - } - ], - "name": "threshold", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-60", - "type": { - "generic": "Linear" - } - } - ], - "name": "starting_point", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.5 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-61", - "type": { - "generic": "Linear" - } - } - ], - "name": "noise", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.5 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - } - ], - "name": "DECISION", - "output_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - -1.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-65", - "type": { - "generic": "Linear" - } - } - ], - "name": "DECISION_VARIABLE", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - -1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "OutputPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 4.2 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-67", - "type": { - "generic": "Linear" - } - } - ], - "name": "RESPONSE_TIME", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 4.2 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "OutputPort", - "generic": null - } - } - ], - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "input_labels_dict": {}, - "input_port_variables": null, - "output_labels_dict": {}, - "previous_value": null, - "variable": [ - [ - 0.0 - ] - ] - }, - "execute_until_finished": false, - "initializer": [ - [ - 0 - ] - ], - "input_format": "SCALAR", - "input_ports": [ - { - "function": { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - [ - 0.0, - 0.0 - ] - ] - }, - "execute_until_finished": true, - "exponents": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": 0.0, - "operation": "sum", - "scale": 1.0, - "weights": [ - 1, - -1 - ] - }, - "name": "Reduce Function-1", - "type": { - "PNL": "Reduce", - "generic": null - } - }, - "name": "ARRAY", - "variable": [ - [ - 0.0, - 0.0 - ] - ] - } - ], - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "output_ports": [ - "DECISION_VARIABLE", - "RESPONSE_TIME" - ], - "random_state": "numpy.random.RandomState()" - }, - "type": { - "PNL": "DDM", - "generic": null - } - }, - "OUTPUT": { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - [ - 0.0, - 0.0 - ] - ] - }, - "bias": { - "source": "OUTPUT.input_ports.bias", - "type": "float", - "value": 0.0 - }, - "bounds": null, - "execute_until_finished": true, - "gain": { - "source": "OUTPUT.input_ports.gain", - "type": "float", - "value": 1.0 - }, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": { - "source": "OUTPUT.input_ports.offset", - "type": "float", - "value": 0.0 - }, - "scale": { - "source": "OUTPUT.input_ports.scale", - "type": "float", - "value": 1.0 - }, - "x_0": { - "source": "OUTPUT.input_ports.x_0", - "type": "float", - "value": 0.0 - } - }, - "name": "Logistic Function-3", - "type": { - "generic": "Logistic" - } - } - ], - "input_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - [ - 0.0, - 0.0 - ], - [ - 0.0, - 0.0 - ] - ] - }, - "execute_until_finished": true, - "exponents": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": 0.0, - "operation": "sum", - "scale": 1.0, - "weights": null - }, - "name": "LinearCombination Function-33", - "type": { - "PNL": "LinearCombination", - "generic": null - } - } - ], - "name": "InputPort-0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "internal_only": false, - "require_projection_in_composition": true, - "shadow_inputs": null, - "variable": [ - [ - 0.0, - 0.0 - ], - [ - 0.0, - 0.0 - ] - ] - }, - "combine": null, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null, - "weight": null - }, - "shape": "(2, 2)", - "type": { - "PNL": "InputPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-15", - "type": { - "generic": "Linear" - } - } - ], - "name": "scale", - "parameters": { - "PNL": { - "execution_count": 0, + "execute_until_finished": true, "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-16", - "type": { - "generic": "Linear" - } + "enable_output_type_conversion": true, + "output_type": "FunctionOutputType.NP_2D_ARRAY", + "changes_shape": false, + "max_executions_before_finished": 1000, + "bounds": [ + 0, + 1 + ], + "function_stateful_params": {} } - ], - "name": "offset", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null } }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-17", - "type": { - "generic": "Linear" - } - } - ], - "name": "x_0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null + "parameters": { + "combination_function_input_data": { + "value": "[color_hidden_input_port_MappingProjection_from_color_input_OutputPort_0__to_color_hidden_InputPort_0_, color_hidden_input_port_MappingProjection_from_TASK_RESULT__to_color_hidden_InputPort_0_]" } }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-18", - "type": { - "generic": "Linear" - } - } - ], - "name": "gain", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, + "output_ports": { + "color_hidden_OutputPort_0": { + "value": "Logistic_Function_0", + "metadata": { + "type": "OutputPort", "variable": [ - 1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-19", - "type": { - "generic": "Linear" - } - } - ], - "name": "bias", - "parameters": { - "PNL": { - "execution_count": 0, + 0.017986209962091562, + 0.017986209962091562 + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, "has_initializers": false, "require_projection_in_composition": true, - "variable": [ - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - } - ], - "name": "OUTPUT", - "output_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.5, - 0.5 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-21", - "type": { - "generic": "Linear" - } + "projections": null } - ], - "name": "OutputPort-0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.5, - 0.5 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(2,)", - "type": { - "PNL": "OutputPort", - "generic": null } } - ], - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "input_labels_dict": {}, - "input_port_variables": null, + }, + "OUTPUT": { + "metadata": { + "type": "ProcessingMechanism", "output_labels_dict": {}, - "previous_value": null, "variable": [ [ 0.0, 0.0 ] - ] + ], + "input_port_variables": null, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "input_labels_dict": {}, + "has_initializers": false, + "output_ports": null, + "input_ports": null }, - "execute_until_finished": true, - "input_ports": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "output_ports": null - }, - "type": { - "PNL": "ProcessingMechanism", - "generic": null - } - }, - "TASK": { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - [ - 0.0, - 0.0 - ] - ] - }, - "bias": { - "source": "TASK.input_ports.bias", - "type": "float", - "value": 0.0 - }, - "bounds": null, - "execute_until_finished": true, - "gain": { - "source": "TASK.input_ports.gain", - "type": "float", - "value": 1.0 - }, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": { - "source": "TASK.input_ports.offset", - "type": "float", - "value": 0.0 - }, - "scale": { - "source": "TASK.input_ports.scale", - "type": "float", - "value": 1.0 - }, - "x_0": { - "source": "TASK.input_ports.x_0", - "type": "float", - "value": 0.0 - } + "input_ports": { + "OUTPUT_input_port_MappingProjection_from_color_hidden_OutputPort_0__to_OUTPUT_InputPort_0_": { + "shape": "(2,)", + "type": "float64" }, - "name": "Logistic Function-5", - "type": { - "generic": "Logistic" + "OUTPUT_input_port_MappingProjection_from_word_hidden_OutputPort_0__to_OUTPUT_InputPort_0_": { + "shape": "(2,)", + "type": "float64" } - } - ], - "input_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - [ - 0.0, - 0.0 - ], - [ - 0.0, - 0.0 - ] - ] - }, - "execute_until_finished": true, - "exponents": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, + }, + "functions": { + "OUTPUT_input_combination_function": { + "function": { + "onnx::ReduceSum": { + "data": "combination_function_input_data", + "axes": 0 + } + }, + "args": { + "data": "combination_function_input_data", + "axes": 0 + } + }, + "OUTPUT_input_combination_function_dimreduce": { + "value": "OUTPUT_input_combination_function[0][0]", + "args": { + "variable0": "OUTPUT_input_combination_function" + } + }, + "Logistic_Function_1": { + "function": { + "logistic": { "offset": 0.0, - "operation": "sum", + "gain": 1.0, "scale": 1.0, - "weights": null - }, - "name": "LinearCombination Function-65", - "type": { - "PNL": "LinearCombination", - "generic": null + "x_0": 0, + "bias": 0.0, + "variable0": "OUTPUT_input_combination_function_dimreduce" } - } - ], - "name": "InputPort-0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "internal_only": false, - "require_projection_in_composition": true, - "shadow_inputs": null, + }, + "args": { + "offset": 0.0, + "gain": 1.0, + "scale": 1.0, + "x_0": 0, + "bias": 0.0, + "variable0": "OUTPUT_input_combination_function_dimreduce" + }, + "metadata": { + "type": "Logistic", "variable": [ - [ - 0.0, - 0.0 - ], [ 0.0, 0.0 ] - ] - }, - "combine": null, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null, - "weight": null - }, - "shape": "(2, 2)", - "type": { - "PNL": "InputPort", - "generic": null + ], + "execute_until_finished": true, + "has_initializers": false, + "enable_output_type_conversion": true, + "output_type": "FunctionOutputType.NP_2D_ARRAY", + "changes_shape": false, + "max_executions_before_finished": 1000, + "bounds": [ + 0, + 1 + ], + "function_stateful_params": {} + } } }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-39", - "type": { - "generic": "Linear" - } - } - ], - "name": "scale", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null + "parameters": { + "combination_function_input_data": { + "value": "[OUTPUT_input_port_MappingProjection_from_color_hidden_OutputPort_0__to_OUTPUT_InputPort_0_, OUTPUT_input_port_MappingProjection_from_word_hidden_OutputPort_0__to_OUTPUT_InputPort_0_]" } }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-40", - "type": { - "generic": "Linear" - } - } - ], - "name": "offset", - "parameters": { - "PNL": { - "execution_count": 0, + "output_ports": { + "OUTPUT_OutputPort_0": { + "value": "Logistic_Function_1", + "metadata": { + "type": "OutputPort", + "variable": [ + 0.5, + 0.5 + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, "has_initializers": false, "require_projection_in_composition": true, - "variable": [ - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-41", - "type": { - "generic": "Linear" - } + "projections": null } + } + } + }, + "word_input": { + "metadata": { + "type": "ProcessingMechanism", + "output_labels_dict": {}, + "variable": [ + [ + 0.0, + 0.0 + ] ], - "name": "x_0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, + "input_port_variables": null, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "input_labels_dict": {}, + "has_initializers": false, + "output_ports": null, + "input_ports": null + }, + "input_ports": { + "word_input_InputPort_0": { + "shape": "(2,)", + "type": "float64", + "metadata": { + "type": "InputPort", + "shadow_inputs": null, "variable": [ + 0.0, 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-42", - "type": { - "generic": "Linear" - } - } - ], - "name": "gain", - "parameters": { - "PNL": { - "execution_count": 0, + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, "has_initializers": false, + "internal_only": false, "require_projection_in_composition": true, - "variable": [ - 1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null + "exponent": null, + "default_input": null, + "combine": null, + "projections": null, + "weight": null + } } }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, + "functions": { + "Linear_Function_22": { + "function": { + "linear": { + "slope": 1.0, "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-43", - "type": { - "generic": "Linear" + "variable0": "word_input_InputPort_0" } - } - ], - "name": "bias", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null + "args": { + "slope": 1.0, + "intercept": 0.0, + "variable0": "word_input_InputPort_0" + }, + "metadata": { + "type": "Linear", + "output_type": "FunctionOutputType.NP_2D_ARRAY", + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "changes_shape": false, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "enable_output_type_conversion": true, + "bounds": null, + "function_stateful_params": {} + } } }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.5 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-44", - "type": { - "generic": "Linear" - } - } - ], - "name": "integration_rate", - "parameters": { - "PNL": { - "execution_count": 0, + "output_ports": { + "word_input_OutputPort_0": { + "value": "Linear_Function_22", + "metadata": { + "type": "OutputPort", + "variable": [ + 0.0, + 0.0 + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, "has_initializers": false, "require_projection_in_composition": true, - "variable": [ - 0.5 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null + "projections": null + } + } + } + }, + "word_hidden": { + "metadata": { + "type": "ProcessingMechanism", + "output_labels_dict": {}, + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "input_port_variables": null, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "input_labels_dict": {}, + "has_initializers": false, + "output_ports": null, + "input_ports": null + }, + "input_ports": { + "word_hidden_input_port_MappingProjection_from_word_input_OutputPort_0__to_word_hidden_InputPort_0_": { + "shape": "(2,)", + "type": "float64" }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null + "word_hidden_input_port_MappingProjection_from_TASK_RESULT__to_word_hidden_InputPort_0_": { + "shape": "(2,)", + "type": "float64" } }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.1 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-45", - "type": { - "generic": "Linear" + "functions": { + "word_hidden_input_combination_function": { + "function": { + "onnx::ReduceSum": { + "data": "combination_function_input_data", + "axes": 0 } - } - ], - "name": "time_step_size", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.1 - ] }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null + "args": { + "data": "combination_function_input_data", + "axes": 0 + } }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null + "word_hidden_input_combination_function_dimreduce": { + "value": "word_hidden_input_combination_function[0][0]", + "args": { + "variable0": "word_hidden_input_combination_function" + } + }, + "Logistic_Function_2": { + "function": { + "logistic": { + "offset": 0.0, + "gain": 1.0, + "scale": 1.0, + "x_0": 0, + "bias": -4.0, + "variable0": "word_hidden_input_combination_function_dimreduce" + } + }, + "args": { + "offset": 0.0, + "gain": 1.0, + "scale": 1.0, + "x_0": 0, + "bias": -4.0, + "variable0": "word_hidden_input_combination_function_dimreduce" + }, + "metadata": { + "type": "Logistic", + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "execute_until_finished": true, + "has_initializers": false, + "enable_output_type_conversion": true, + "output_type": "FunctionOutputType.NP_2D_ARRAY", + "changes_shape": false, + "max_executions_before_finished": 1000, + "bounds": [ + 0, + 1 + ], + "function_stateful_params": {} + } } }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-46", - "type": { - "generic": "Linear" - } + "parameters": { + "combination_function_input_data": { + "value": "[word_hidden_input_port_MappingProjection_from_word_input_OutputPort_0__to_word_hidden_InputPort_0_, word_hidden_input_port_MappingProjection_from_TASK_RESULT__to_word_hidden_InputPort_0_]" + } + }, + "output_ports": { + "word_hidden_OutputPort_0": { + "value": "Logistic_Function_2", + "metadata": { + "type": "OutputPort", + "variable": [ + 0.017986209962091562, + 0.017986209962091562 + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "require_projection_in_composition": true, + "projections": null } + } + } + }, + "task_input": { + "metadata": { + "type": "ProcessingMechanism", + "output_labels_dict": {}, + "variable": [ + [ + 0.0, + 0.0 + ] ], - "name": "competition", - "parameters": { - "PNL": { - "execution_count": 0, + "input_port_variables": null, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "input_labels_dict": {}, + "has_initializers": false, + "output_ports": null, + "input_ports": null + }, + "input_ports": { + "task_input_InputPort_0": { + "shape": "(2,)", + "type": "float64", + "metadata": { + "type": "InputPort", + "shadow_inputs": null, + "variable": [ + 0.0, + 0.0 + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, "has_initializers": false, + "internal_only": false, "require_projection_in_composition": true, - "variable": [ - 1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null + "exponent": null, + "default_input": null, + "combine": null, + "projections": null, + "weight": null + } } }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.5 - ] - }, - "bounds": null, - "execute_until_finished": true, + "functions": { + "Linear_Function_34": { + "function": { + "linear": { + "slope": 1.0, "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-47", - "type": { - "generic": "Linear" + "variable0": "task_input_InputPort_0" } + }, + "args": { + "slope": 1.0, + "intercept": 0.0, + "variable0": "task_input_InputPort_0" + }, + "metadata": { + "type": "Linear", + "output_type": "FunctionOutputType.NP_2D_ARRAY", + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "changes_shape": false, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "enable_output_type_conversion": true, + "bounds": null, + "function_stateful_params": {} } - ], - "name": "smoothing_factor", - "parameters": { - "PNL": { - "execution_count": 0, + } + }, + "output_ports": { + "task_input_OutputPort_0": { + "value": "Linear_Function_34", + "metadata": { + "type": "OutputPort", + "variable": [ + 0.0, + 0.0 + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, "has_initializers": false, "require_projection_in_composition": true, - "variable": [ - 0.5 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null + "projections": null + } } - }, - { - "dtype": "float64", - "functions": [ - { + } + }, + "TASK": { + "metadata": { + "type": "LCAMechanism", + "input_port_variables": null, + "output_labels_dict": {}, + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "execute_until_finished": true, + "has_initializers": false, + "termination_measure_value": 0.0, + "max_executions_before_finished": 1000, + "input_labels_dict": {}, + "input_ports": null, + "matrix": "InverseHollowMatrix", + "integrator_function": { + "LeakyCompetingIntegrator_Function_0": { + "value": "previous_value + (-rate * previous_value + variable0) * time_step_size + noise * (time_step_size ** 0.5)", "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ + "time_step_size": 0.1, + "offset": 0.0, + "rate": 0.5, + "noise": 0.0 + }, + "metadata": { + "type": "LeakyCompetingIntegrator", + "initializer": [ + [ + 0.5, 0.5 ] - }, - "bounds": null, + ], + "variable": [ + [ + 0.0, + 0.0 + ] + ], "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, + "has_initializers": true, + "enable_output_type_conversion": false, + "output_type": "FunctionOutputType.DEFAULT", + "changes_shape": false, "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-48", - "type": { - "generic": "Linear" + "function_stateful_params": { + "previous_value": { + "id": "previous_value", + "default_initial_value": [ + [ + 0.5, + 0.5 + ] + ], + "value": "LeakyCompetingIntegrator_Function_0" + } + } } } - ], - "name": "leak", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.5 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { + "combination_function": { + "LinearCombination_Function_23": { + "function": { + "linearcombination": { + "offset": 0.0, + "scale": 1.0 + } + }, "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - -1.0 + "offset": 0.0, + "scale": 1.0 + }, + "metadata": { + "type": "LinearCombination", + "variable": [ + [ + 0.0, + 0.0 ] - }, - "bounds": null, + ], "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, + "has_initializers": false, + "enable_output_type_conversion": false, + "output_type": "FunctionOutputType.DEFAULT", + "changes_shape": false, "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-49", - "type": { - "generic": "Linear" + "exponents": null, + "weights": null, + "operation": "sum", + "function_stateful_params": {} } } + }, + "integrator_mode": true, + "has_recurrent_input_port": false, + "on_resume_integrator_mode": "current_value", + "clip": null, + "output_ports": [ + "RESULTS" ], - "name": "hetero", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - -1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null + "enable_learning": false, + "integrator_function_value": [ + [ + 0 + ] + ], + "termination_comparison_op": ">=", + "termination_threshold": null, + "termination_measure": "max" + }, + "input_ports": { + "TASK_input_port_TASK_recurrent_projection": { + "shape": "(2,)", + "type": "float64" }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null + "TASK_input_port_MappingProjection_from_task_input_OutputPort_0__to_TASK_InputPort_0_": { + "shape": "(2,)", + "type": "float64" } }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-50", - "type": { - "generic": "Linear" + "functions": { + "TASK_input_combination_function": { + "function": { + "onnx::ReduceSum": { + "data": "combination_function_input_data", + "axes": 0 } + }, + "args": { + "data": "combination_function_input_data", + "axes": 0 } - ], - "name": "noise", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] + }, + "TASK_input_combination_function_dimreduce": { + "value": "TASK_input_combination_function[0][0]", + "args": { + "variable0": "TASK_input_combination_function" + } + }, + "Logistic_Function_5": { + "function": { + "logistic": { + "offset": 0.0, + "gain": 1.0, + "scale": 1.0, + "x_0": 0, + "bias": 0.0, + "variable0": "LeakyCompetingIntegrator_Function_0" + } }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null + "args": { + "offset": 0.0, + "gain": 1.0, + "scale": 1.0, + "x_0": 0, + "bias": 0.0, + "variable0": "LeakyCompetingIntegrator_Function_0" + }, + "metadata": { + "type": "Logistic", + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "execute_until_finished": true, + "has_initializers": false, + "enable_output_type_conversion": true, + "output_type": "FunctionOutputType.NP_2D_ARRAY", + "changes_shape": false, + "max_executions_before_finished": 1000, + "bounds": [ + 0, + 1 + ], + "function_stateful_params": {} + } }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-51", - "type": { - "generic": "Linear" + "LeakyCompetingIntegrator_Function_0": { + "value": "previous_value + (-0.5 * previous_value + TASK_input_combination_function_dimreduce) * 0.1 + 0.0 * (0.1 ** 0.5)", + "args": { + "time_step_size": 0.1, + "offset": 0.0, + "rate": 0.5, + "noise": 0.0, + "variable0": "TASK_input_combination_function_dimreduce" + }, + "metadata": { + "type": "LeakyCompetingIntegrator", + "initializer": [ + [ + 0.5, + 0.5 + ] + ], + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "execute_until_finished": true, + "has_initializers": true, + "enable_output_type_conversion": false, + "output_type": "FunctionOutputType.DEFAULT", + "changes_shape": false, + "max_executions_before_finished": 1000, + "function_stateful_params": { + "previous_value": { + "id": "previous_value", + "default_initial_value": [ + [ + 0.5, + 0.5 + ] + ], + "value": "LeakyCompetingIntegrator_Function_0" + } } } - ], - "name": "auto", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null + } + }, + "parameters": { + "hetero": { + "value": -1.0 + }, + "smoothing_factor": { + "value": 0.5 }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null + "auto": { + "value": 0.0 + }, + "competition": { + "value": 1.0 + }, + "combination_function_input_data": { + "value": "[TASK_input_port_TASK_recurrent_projection, TASK_input_port_MappingProjection_from_task_input_OutputPort_0__to_TASK_InputPort_0_]" + }, + "previous_value": { + "default_initial_value": [ + [ + 0.5, + 0.5 + ] + ], + "value": "LeakyCompetingIntegrator_Function_0" } - } - ], - "name": "TASK", - "output_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.6283161882953663, - 0.6283161882953663 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-54", - "type": { - "generic": "Linear" - } - } - ], - "name": "RESULT", - "parameters": { - "PNL": { - "execution_count": 0, + }, + "output_ports": { + "TASK_RESULT": { + "value": "Logistic_Function_5", + "metadata": { + "type": "OutputPort", + "variable": [ + 0.5, + 0.5 + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, "has_initializers": false, "require_projection_in_composition": true, - "variable": [ - 0.6283161882953663, - 0.6283161882953663 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(2,)", - "type": { - "PNL": "OutputPort", - "generic": null + "projections": null + } } } - ], - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "input_labels_dict": {}, + }, + "DECISION": { + "metadata": { + "type": "DDM", "input_port_variables": null, "output_labels_dict": {}, - "previous_value": null, "variable": [ [ - 0.0, 0.0 ] - ] - }, - "auto": 0.0, - "clip": null, - "combination_function": "LinearCombination", - "competition": 1.0, - "enable_learning": false, - "execute_until_finished": true, - "has_integrated": false, - "has_recurrent_input_port": false, - "hetero": -1.0, - "initial_value": [ - [ - 0.5, - 0.5 - ] - ], - "input_ports": null, - "integration_rate": 0.5, - "integrator_function": "LeakyCompetingIntegrator", - "integrator_function_value": [ - [ - 0 - ] - ], - "integrator_mode": true, - "is_finished_flag": true, - "leak": 0.5, - "learning_condition": null, - "learning_function": "Hebbian", - "learning_rate": null, - "matrix": "HollowMatrix", - "max_executions_before_finished": 1000, - "noise": 0.0, - "num_executions_before_finished": 0, - "on_resume_integrator_mode": "instantaneous_mode_value", - "output_ports": [ - "RESULT" - ], - "smoothing_factor": 0.5, - "termination_comparison_op": ">=", - "termination_measure": "max", - "termination_measure_value": 0.0, - "termination_threshold": null, - "time_step_size": 0.1 - }, - "type": { - "PNL": "LCAMechanism", - "generic": null - } - }, - "color_hidden": { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, + ], + "execute_until_finished": true, + "has_initializers": false, + "max_executions_before_finished": 1000, + "input_labels_dict": {}, + "input_ports": [ + { + "name": "ARRAY", "variable": [ [ 0.0, 0.0 ] - ] - }, - "bias": { - "source": "color_hidden.input_ports.bias", - "type": "int", - "value": -4 - }, - "bounds": null, - "execute_until_finished": true, - "gain": { - "source": "color_hidden.input_ports.gain", - "type": "float", - "value": 1.0 - }, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": { - "source": "color_hidden.input_ports.offset", - "type": "float", - "value": 0.0 - }, - "scale": { - "source": "color_hidden.input_ports.scale", - "type": "float", - "value": 1.0 - }, - "x_0": { - "source": "color_hidden.input_ports.x_0", - "type": "float", - "value": 0.0 - } - }, - "name": "Logistic Function-2", - "type": { - "generic": "Logistic" - } - } - ], - "input_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - [ - 0.0, - 0.0 + ], + "function": { + "Reduce_Function_0_2": { + "function": { + "reduce": { + "offset": 0.0, + "scale": 1.0 + } + }, + "args": { + "offset": 0.0, + "scale": 1.0 + }, + "metadata": { + "type": "Reduce", + "variable": [ + 0 ], - [ - 2.513264753181465, - 2.513264753181465 - ] - ] - }, - "execute_until_finished": true, - "exponents": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": 0.0, - "operation": "sum", - "scale": 1.0, - "weights": null - }, - "name": "LinearCombination Function-25", - "type": { - "PNL": "LinearCombination", - "generic": null + "execute_until_finished": true, + "has_initializers": false, + "enable_output_type_conversion": false, + "output_type": "FunctionOutputType.DEFAULT", + "changes_shape": true, + "max_executions_before_finished": 1000, + "exponents": null, + "weights": [ + 1, + -1 + ], + "operation": "sum", + "function_stateful_params": {} + } + } } } ], - "name": "InputPort-0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "internal_only": false, - "require_projection_in_composition": true, + "random_state": null, + "input_format": "SCALAR", + "output_ports": [ + "DECISION_VARIABLE", + "RESPONSE_TIME" + ] + }, + "input_ports": { + "DECISION_ARRAY": { + "shape": "(1, 2)", + "type": "float64", + "metadata": { + "type": "InputPort", "shadow_inputs": null, "variable": [ [ 0.0, 0.0 + ] + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "internal_only": false, + "require_projection_in_composition": true, + "exponent": null, + "default_input": null, + "combine": null, + "projections": null, + "weight": null + } + } + }, + "functions": { + "Drift_Diffusion_Analytical_Function_0_3": { + "function": { + "driftdiffusionanalytical": { + "drift_rate": 1.0, + "threshold": 1.0, + "non_decision_time": 0.2, + "starting_value": 0.0, + "bias": 0.5, + "noise": 0.5, + "shape": [ + 1, + 1 ], + "variable0": "DECISION_ARRAY" + } + }, + "args": { + "drift_rate": 1.0, + "threshold": 1.0, + "non_decision_time": 0.2, + "starting_value": 0.0, + "bias": 0.5, + "noise": 0.5, + "shape": [ + 1, + 1 + ], + "variable0": "DECISION_ARRAY" + }, + "metadata": { + "type": "DriftDiffusionAnalytical", + "variable": [ [ - 2.513264753181465, - 2.513264753181465 + 0.0 ] + ], + "execute_until_finished": true, + "has_initializers": false, + "enable_output_type_conversion": true, + "output_type": "FunctionOutputType.NP_2D_ARRAY", + "changes_shape": false, + "max_executions_before_finished": 1000, + "function_stateful_params": {} + } + } + }, + "parameters": { + "initializer": { + "value": [ + [ + 0 ] - }, - "combine": null, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null, - "weight": null + ] }, - "shape": "(2, 2)", - "type": { - "PNL": "InputPort", - "generic": null + "seed": { + "value": -1 } }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-8", - "type": { - "generic": "Linear" - } - } - ], - "name": "scale", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, + "output_ports": { + "DECISION_DECISION_VARIABLE": { + "value": "Drift_Diffusion_Analytical_Function_0_3[0]", + "metadata": { + "type": "OutputPort", "variable": [ 1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "require_projection_in_composition": true, + "projections": null + } }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null + "DECISION_RESPONSE_TIME": { + "value": "Drift_Diffusion_Analytical_Function_0_3[1]", + "metadata": { + "type": "OutputPort", + "variable": [ + 4.2 + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "require_projection_in_composition": true, + "projections": null + } } - }, - { - "dtype": "float64", - "functions": [ + } + }, + "Conflict_Monitor": { + "metadata": { + "type": "ObjectiveMechanism", + "output_labels_dict": {}, + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "input_port_variables": null, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "input_labels_dict": {}, + "has_initializers": false, + "output_ports": [ + "OUTCOME" + ], + "input_ports": [ { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, + "OUTPUT": { + "metadata": { + "type": "ProcessingMechanism", + "output_labels_dict": {}, "variable": [ - 0.0 - ] + [ + 0.0, + 0.0 + ] + ], + "input_port_variables": null, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "input_labels_dict": {}, + "has_initializers": false, + "output_ports": null, + "input_ports": null + }, + "input_ports": { + "OUTPUT_input_port_MappingProjection_from_color_hidden_OutputPort_0__to_OUTPUT_InputPort_0_": { + "shape": "(2,)", + "type": "float64" + }, + "OUTPUT_input_port_MappingProjection_from_word_hidden_OutputPort_0__to_OUTPUT_InputPort_0_": { + "shape": "(2,)", + "type": "float64" + } + }, + "functions": { + "OUTPUT_input_combination_function": { + "function": { + "onnx::ReduceSum": { + "data": "combination_function_input_data", + "axes": 0 + } + }, + "args": { + "data": "combination_function_input_data", + "axes": 0 + } + }, + "OUTPUT_input_combination_function_dimreduce": { + "value": "OUTPUT_input_combination_function[0][0]", + "args": { + "variable0": "OUTPUT_input_combination_function" + } + }, + "Logistic_Function_1": { + "function": { + "logistic": { + "offset": 0.0, + "gain": 1.0, + "scale": 1.0, + "x_0": 0, + "bias": 0.0, + "variable0": "OUTPUT_input_combination_function_dimreduce" + } + }, + "args": { + "offset": 0.0, + "gain": 1.0, + "scale": 1.0, + "x_0": 0, + "bias": 0.0, + "variable0": "OUTPUT_input_combination_function_dimreduce" + }, + "metadata": { + "type": "Logistic", + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "execute_until_finished": true, + "has_initializers": false, + "enable_output_type_conversion": true, + "output_type": "FunctionOutputType.NP_2D_ARRAY", + "changes_shape": false, + "max_executions_before_finished": 1000, + "bounds": [ + 0, + 1 + ], + "function_stateful_params": {} + } + } }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-9", - "type": { - "generic": "Linear" + "parameters": { + "combination_function_input_data": { + "value": "[OUTPUT_input_port_MappingProjection_from_color_hidden_OutputPort_0__to_OUTPUT_InputPort_0_, OUTPUT_input_port_MappingProjection_from_word_hidden_OutputPort_0__to_OUTPUT_InputPort_0_]" + } + }, + "output_ports": { + "OUTPUT_OutputPort_0": { + "value": "Logistic_Function_1", + "metadata": { + "type": "OutputPort", + "variable": [ + 0.5, + 0.5 + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "require_projection_in_composition": true, + "projections": null + } + } + } } } - ], - "name": "offset", - "parameters": { - "PNL": { - "execution_count": 0, + ] + }, + "input_ports": { + "Conflict_Monitor_Value_of_OUTPUT__OutputPort_0_": { + "shape": "(1, 2)", + "type": "float64", + "metadata": { + "type": "InputPort", + "shadow_inputs": null, + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, "has_initializers": false, + "internal_only": true, "require_projection_in_composition": true, - "variable": [ - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null + "exponent": null, + "default_input": null, + "combine": null, + "projections": [ + [ + "OUTPUT.output_ports.OutputPort-0", + null, + null, + { + "PROJECTION_TYPE": "MappingProjection" + } + ] + ], + "weight": null + } } }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-10", - "type": { - "generic": "Linear" + "functions": { + "Stability_Function_0": { + "function": { + "energy": { + "variable0": "Conflict_Monitor_Value_of_OUTPUT__OutputPort_0_" } - } - ], - "name": "x_0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 + "args": { + "variable0": "Conflict_Monitor_Value_of_OUTPUT__OutputPort_0_" + }, + "metadata": { + "type": "Energy", + "output_type": "FunctionOutputType.NP_2D_ARRAY", + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "changes_shape": false, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "enable_output_type_conversion": true, + "metric_fct": { + "Distance_Function_4": { + "function": { + "distance": {} + }, + "args": {}, + "metadata": { + "type": "Distance", + "output_type": "FunctionOutputType.DEFAULT", + "variable": [ + [ + [ + 0.0, + 0.0 + ] + ], + [ + [ + 0.0, + 0.0 + ] + ] + ], + "changes_shape": false, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "enable_output_type_conversion": false, + "metric": "energy", + "normalize": false, + "function_stateful_params": {} + } + } }, - "name": "Linear Function-11", - "type": { - "generic": "Linear" - } + "metric": "energy", + "matrix": [ + [ + 0, + -2.5 + ], + [ + -2.5, + 0 + ] + ], + "transfer_fct": null, + "normalize": false, + "function_stateful_params": {} } - ], - "name": "gain", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null } }, - { - "dtype": "int64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - -4 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-12", - "type": { - "generic": "Linear" - } - } - ], - "name": "bias", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, + "output_ports": { + "Conflict_Monitor_OUTCOME": { + "value": "Stability_Function_0", + "metadata": { + "type": "OutputPort", "variable": [ - -4 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - } - ], - "name": "color_hidden", - "output_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.017986209962091562, - 0.017986209962091562 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-14", - "type": { - "generic": "Linear" - } - } - ], - "name": "OutputPort-0", - "parameters": { - "PNL": { - "execution_count": 0, + -0.0 + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, "has_initializers": false, "require_projection_in_composition": true, - "variable": [ - 0.017986209962091562, - 0.017986209962091562 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(2,)", - "type": { - "PNL": "OutputPort", - "generic": null + "projections": null + } } } - ], - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "input_labels_dict": {}, + }, + "CONTROL": { + "metadata": { + "type": "ControlMechanism", "input_port_variables": null, "output_labels_dict": {}, - "previous_value": null, "variable": [ [ - 0.0, - 0.0 + 1.0 ] - ] - }, - "execute_until_finished": true, - "input_ports": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "output_ports": null - }, - "type": { - "PNL": "ProcessingMechanism", - "generic": null - } - }, - "color_input": { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - [ - 0.0, - 0.0 + ], + "execute_until_finished": true, + "has_initializers": false, + "outcome": null, + "modulation": "multiplicative_param", + "simulation_ids": [], + "max_executions_before_finished": 1000, + "input_labels_dict": {}, + "net_outcome": null, + "control_signal_costs": null, + "input_ports": [ + "OUTCOME" + ], + "outcome_input_ports": "[(InputPort OUTCOME)]", + "costs": null, + "compute_net_outcome": "gANjZGlsbC5fZGlsbApfY3JlYXRlX2Z1bmN0aW9uCnEAKGNkaWxsLl9kaWxsCl9jcmVhdGVfY29k\nZQpxAShLAksASwJLAktDQwh8AHwBGABTAHECToVxAylYBwAAAG91dGNvbWVxBFgEAAAAY29zdHEF\nhnEGWGwAAAAvaG9tZS9rYXRoZXJpbmUvY29kZS9Qc3lOZXVMaW5rL3BzeW5ldWxpbmsvY29yZS9j\nb21wb25lbnRzL21lY2hhbmlzbXMvbW9kdWxhdG9yeS9jb250cm9sL2NvbnRyb2xtZWNoYW5pc20u\ncHlxB1gIAAAAPGxhbWJkYT5xCE2cBEMAcQkpKXRxClJxC2Nwc3luZXVsaW5rLmNvcmUuY29tcG9u\nZW50cy5tZWNoYW5pc21zLm1vZHVsYXRvcnkuY29udHJvbC5jb250cm9sbWVjaGFuaXNtCl9fZGlj\ndF9fCmgITk59cQxOdHENUnEOLg==\n", + "objective_mechanism": { + "Conflict_Monitor": { + "metadata": { + "type": "ObjectiveMechanism", + "output_labels_dict": {}, + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "input_port_variables": null, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "input_labels_dict": {}, + "has_initializers": false, + "output_ports": [ + "OUTCOME" + ], + "input_ports": [ + { + "OUTPUT": { + "metadata": { + "type": "ProcessingMechanism", + "output_labels_dict": {}, + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "input_port_variables": null, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "input_labels_dict": {}, + "has_initializers": false, + "output_ports": null, + "input_ports": null + }, + "input_ports": { + "OUTPUT_input_port_MappingProjection_from_color_hidden_OutputPort_0__to_OUTPUT_InputPort_0_": { + "shape": "(2,)", + "type": "float64" + }, + "OUTPUT_input_port_MappingProjection_from_word_hidden_OutputPort_0__to_OUTPUT_InputPort_0_": { + "shape": "(2,)", + "type": "float64" + } + }, + "functions": { + "OUTPUT_input_combination_function": { + "function": { + "onnx::ReduceSum": { + "data": "combination_function_input_data", + "axes": 0 + } + }, + "args": { + "data": "combination_function_input_data", + "axes": 0 + } + }, + "OUTPUT_input_combination_function_dimreduce": { + "value": "OUTPUT_input_combination_function[0][0]", + "args": { + "variable0": "OUTPUT_input_combination_function" + } + }, + "Logistic_Function_1": { + "function": { + "logistic": { + "offset": 0.0, + "gain": 1.0, + "scale": 1.0, + "x_0": 0, + "bias": 0.0, + "variable0": "OUTPUT_input_combination_function_dimreduce" + } + }, + "args": { + "offset": 0.0, + "gain": 1.0, + "scale": 1.0, + "x_0": 0, + "bias": 0.0, + "variable0": "OUTPUT_input_combination_function_dimreduce" + }, + "metadata": { + "type": "Logistic", + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "execute_until_finished": true, + "has_initializers": false, + "enable_output_type_conversion": true, + "output_type": "FunctionOutputType.NP_2D_ARRAY", + "changes_shape": false, + "max_executions_before_finished": 1000, + "bounds": [ + 0, + 1 + ], + "function_stateful_params": {} + } + } + }, + "parameters": { + "combination_function_input_data": { + "value": "[OUTPUT_input_port_MappingProjection_from_color_hidden_OutputPort_0__to_OUTPUT_InputPort_0_, OUTPUT_input_port_MappingProjection_from_word_hidden_OutputPort_0__to_OUTPUT_InputPort_0_]" + } + }, + "output_ports": { + "OUTPUT_OutputPort_0": { + "value": "Logistic_Function_1", + "metadata": { + "type": "OutputPort", + "variable": [ + 0.5, + 0.5 + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "require_projection_in_composition": true, + "projections": null + } + } + } + } + } ] - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": { - "source": "color_input.input_ports.intercept", - "type": "float", - "value": 0.0 - }, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": { - "source": "color_input.input_ports.slope", - "type": "float", - "value": 1.0 - } - }, - "name": "Linear Function-5", - "type": { - "generic": "Linear" - } - } - ], - "input_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0, - 0.0 - ] - }, - "execute_until_finished": true, - "exponents": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": 0.0, - "operation": "sum", - "scale": 1.0, - "weights": null }, - "name": "LinearCombination Function-17", - "type": { - "PNL": "LinearCombination", - "generic": null + "input_ports": { + "Conflict_Monitor_Value_of_OUTPUT__OutputPort_0_": { + "shape": "(1, 2)", + "type": "float64", + "metadata": { + "type": "InputPort", + "shadow_inputs": null, + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "internal_only": true, + "require_projection_in_composition": true, + "exponent": null, + "default_input": null, + "combine": null, + "projections": [ + [ + "OUTPUT.output_ports.OutputPort-0", + null, + null, + { + "PROJECTION_TYPE": "MappingProjection" + } + ] + ], + "weight": null + } + } + }, + "functions": { + "Stability_Function_0": { + "function": { + "energy": { + "variable0": "Conflict_Monitor_Value_of_OUTPUT__OutputPort_0_" + } + }, + "args": { + "variable0": "Conflict_Monitor_Value_of_OUTPUT__OutputPort_0_" + }, + "metadata": { + "type": "Energy", + "output_type": "FunctionOutputType.NP_2D_ARRAY", + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "changes_shape": false, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "enable_output_type_conversion": true, + "metric_fct": { + "Distance_Function_4": { + "function": { + "distance": {} + }, + "args": {}, + "metadata": { + "type": "Distance", + "output_type": "FunctionOutputType.DEFAULT", + "variable": [ + [ + [ + 0.0, + 0.0 + ] + ], + [ + [ + 0.0, + 0.0 + ] + ] + ], + "changes_shape": false, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "enable_output_type_conversion": false, + "metric": "energy", + "normalize": false, + "function_stateful_params": {} + } + } + }, + "metric": "energy", + "matrix": [ + [ + 0, + -2.5 + ], + [ + -2.5, + 0 + ] + ], + "transfer_fct": null, + "normalize": false, + "function_stateful_params": {} + } + } + }, + "output_ports": { + "Conflict_Monitor_OUTCOME": { + "value": "Stability_Function_0", + "metadata": { + "type": "OutputPort", + "variable": [ + -0.0 + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "require_projection_in_composition": true, + "projections": null + } + } } } - ], - "name": "InputPort-0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "internal_only": false, - "require_projection_in_composition": true, - "shadow_inputs": null, - "variable": [ - 0.0, - 0.0 - ] - }, - "combine": null, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null, - "weight": null }, - "shape": "(2,)", - "type": { - "PNL": "InputPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ + "output_ports": [ { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-3", - "type": { - "generic": "Linear" + "name": "gain", + "MECHANISM": { + "TASK": { + "metadata": { + "type": "LCAMechanism", + "input_port_variables": null, + "output_labels_dict": {}, + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "execute_until_finished": true, + "has_initializers": false, + "termination_measure_value": 0.0, + "max_executions_before_finished": 1000, + "input_labels_dict": {}, + "input_ports": null, + "matrix": "InverseHollowMatrix", + "integrator_function": { + "LeakyCompetingIntegrator_Function_0": { + "value": "previous_value + (-rate * previous_value + variable0) * time_step_size + noise * (time_step_size ** 0.5)", + "args": { + "time_step_size": 0.1, + "offset": 0.0, + "rate": 0.5, + "noise": 0.0 + }, + "metadata": { + "type": "LeakyCompetingIntegrator", + "initializer": [ + [ + 0.5, + 0.5 + ] + ], + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "execute_until_finished": true, + "has_initializers": true, + "enable_output_type_conversion": false, + "output_type": "FunctionOutputType.DEFAULT", + "changes_shape": false, + "max_executions_before_finished": 1000, + "function_stateful_params": { + "previous_value": { + "id": "previous_value", + "default_initial_value": [ + [ + 0.5, + 0.5 + ] + ], + "value": "LeakyCompetingIntegrator_Function_0" + } + } + } + } + }, + "combination_function": { + "LinearCombination_Function_23": { + "function": { + "linearcombination": { + "offset": 0.0, + "scale": 1.0 + } + }, + "args": { + "offset": 0.0, + "scale": 1.0 + }, + "metadata": { + "type": "LinearCombination", + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "execute_until_finished": true, + "has_initializers": false, + "enable_output_type_conversion": false, + "output_type": "FunctionOutputType.DEFAULT", + "changes_shape": false, + "max_executions_before_finished": 1000, + "exponents": null, + "weights": null, + "operation": "sum", + "function_stateful_params": {} + } + } + }, + "integrator_mode": true, + "has_recurrent_input_port": false, + "on_resume_integrator_mode": "current_value", + "clip": null, + "output_ports": [ + "RESULTS" + ], + "enable_learning": false, + "integrator_function_value": [ + [ + 0 + ] + ], + "termination_comparison_op": ">=", + "termination_threshold": null, + "termination_measure": "max" + }, + "input_ports": { + "TASK_input_port_TASK_recurrent_projection": { + "shape": "(2,)", + "type": "float64" + }, + "TASK_input_port_MappingProjection_from_task_input_OutputPort_0__to_TASK_InputPort_0_": { + "shape": "(2,)", + "type": "float64" + } + }, + "functions": { + "TASK_input_combination_function": { + "function": { + "onnx::ReduceSum": { + "data": "combination_function_input_data", + "axes": 0 + } + }, + "args": { + "data": "combination_function_input_data", + "axes": 0 + } + }, + "TASK_input_combination_function_dimreduce": { + "value": "TASK_input_combination_function[0][0]", + "args": { + "variable0": "TASK_input_combination_function" + } + }, + "Logistic_Function_5": { + "function": { + "logistic": { + "offset": 0.0, + "gain": 1.0, + "scale": 1.0, + "x_0": 0, + "bias": 0.0, + "variable0": "LeakyCompetingIntegrator_Function_0" + } + }, + "args": { + "offset": 0.0, + "gain": 1.0, + "scale": 1.0, + "x_0": 0, + "bias": 0.0, + "variable0": "LeakyCompetingIntegrator_Function_0" + }, + "metadata": { + "type": "Logistic", + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "execute_until_finished": true, + "has_initializers": false, + "enable_output_type_conversion": true, + "output_type": "FunctionOutputType.NP_2D_ARRAY", + "changes_shape": false, + "max_executions_before_finished": 1000, + "bounds": [ + 0, + 1 + ], + "function_stateful_params": {} + } + }, + "LeakyCompetingIntegrator_Function_0": { + "value": "previous_value + (-0.5 * previous_value + TASK_input_combination_function_dimreduce) * 0.1 + 0.0 * (0.1 ** 0.5)", + "args": { + "time_step_size": 0.1, + "offset": 0.0, + "rate": 0.5, + "noise": 0.0, + "variable0": "TASK_input_combination_function_dimreduce" + }, + "metadata": { + "type": "LeakyCompetingIntegrator", + "initializer": [ + [ + 0.5, + 0.5 + ] + ], + "variable": [ + [ + 0.0, + 0.0 + ] + ], + "execute_until_finished": true, + "has_initializers": true, + "enable_output_type_conversion": false, + "output_type": "FunctionOutputType.DEFAULT", + "changes_shape": false, + "max_executions_before_finished": 1000, + "function_stateful_params": { + "previous_value": { + "id": "previous_value", + "default_initial_value": [ + [ + 0.5, + 0.5 + ] + ], + "value": "LeakyCompetingIntegrator_Function_0" + } + } + } + } + }, + "parameters": { + "hetero": { + "value": -1.0 + }, + "smoothing_factor": { + "value": 0.5 + }, + "auto": { + "value": 0.0 + }, + "competition": { + "value": 1.0 + }, + "combination_function_input_data": { + "value": "[TASK_input_port_TASK_recurrent_projection, TASK_input_port_MappingProjection_from_task_input_OutputPort_0__to_TASK_InputPort_0_]" + }, + "previous_value": { + "default_initial_value": [ + [ + 0.5, + 0.5 + ] + ], + "value": "LeakyCompetingIntegrator_Function_0" + } + }, + "output_ports": { + "TASK_RESULT": { + "value": "Logistic_Function_5", + "metadata": { + "type": "OutputPort", + "variable": [ + 0.5, + 0.5 + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "require_projection_in_composition": true, + "projections": null + } + } + } + } } } ], - "name": "intercept", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, + "default_allocation": [ + 0.5 + ], + "reconfiguration_cost": null, + "outcome_input_ports_option": "separate", + "combine_costs": "gANjbnVtcHkKc3VtCnEALg==\n", + "compute_reconfiguration_cost": null, + "monitor_for_control": [] + }, + "input_ports": { + "CONTROL_OUTCOME": { + "shape": "(1,)", + "type": "float64", + "metadata": { + "type": "InputPort", + "shadow_inputs": null, "variable": [ 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-4", - "type": { - "generic": "Linear" - } - } - ], - "name": "slope", - "parameters": { - "PNL": { - "execution_count": 0, + ], + "execute_until_finished": true, + "max_executions_before_finished": 1000, "has_initializers": false, + "internal_only": true, "require_projection_in_composition": true, - "variable": [ - 1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - } - ], - "name": "color_input", - "output_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0, - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-7", - "type": { - "generic": "Linear" - } + "exponent": null, + "default_input": null, + "combine": null, + "projections": null, + "weight": null } - ], - "name": "OutputPort-0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0, - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(2,)", - "type": { - "PNL": "OutputPort", - "generic": null } - } - ], - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "input_labels_dict": {}, - "input_port_variables": null, - "output_labels_dict": {}, - "previous_value": null, - "variable": [ - [ - 0.0, - 0.0 - ] - ] }, - "execute_until_finished": true, - "input_ports": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "output_ports": null - }, - "type": { - "PNL": "ProcessingMechanism", - "generic": null - } - }, - "task_input": { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, + "functions": { + "Default_Control_Function_0": { + "function": { + "defaultallocationfunction": { + "num_control_signals": 1, + "variable0": "CONTROL_OUTCOME" + } + }, + "args": { + "num_control_signals": 1, + "variable0": "CONTROL_OUTCOME" + }, + "metadata": { + "type": "DefaultAllocationFunction", + "output_type": "FunctionOutputType.NP_2D_ARRAY", "variable": [ [ - 0.0, - 0.0 + 1.0 ] - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": { - "source": "task_input.input_ports.intercept", - "type": "float", - "value": 0.0 - }, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": { - "source": "task_input.input_ports.slope", - "type": "float", - "value": 1.0 - } - }, - "name": "Linear Function-36", - "type": { - "generic": "Linear" - } - } - ], - "input_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0, - 0.0 - ] - }, - "execute_until_finished": true, - "exponents": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": 0.0, - "operation": "sum", - "scale": 1.0, - "weights": null - }, - "name": "LinearCombination Function-57", - "type": { - "PNL": "LinearCombination", - "generic": null - } - } - ], - "name": "InputPort-0", - "parameters": { - "PNL": { - "execution_count": 0, + ], + "changes_shape": false, + "execute_until_finished": true, + "max_executions_before_finished": 1000, "has_initializers": false, - "internal_only": false, - "require_projection_in_composition": true, - "shadow_inputs": null, - "variable": [ - 0.0, - 0.0 - ] - }, - "combine": null, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null, - "weight": null - }, - "shape": "(2,)", - "type": { - "PNL": "InputPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-34", - "type": { - "generic": "Linear" - } + "enable_output_type_conversion": true, + "function_stateful_params": {} } - ], - "name": "intercept", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null } }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-35", - "type": { - "generic": "Linear" - } - } - ], - "name": "slope", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - } - ], - "name": "task_input", - "output_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0, - 0.0 - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-38", - "type": { - "generic": "Linear" - } - } - ], - "name": "OutputPort-0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, + "output_ports": { + "CONTROL_TASK_gain__ControlSignal": { + "value": "Default_Control_Function_0", + "metadata": { + "type": "ControlSignal", "require_projection_in_composition": true, "variable": [ - 0.0, - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(2,)", - "type": { - "PNL": "OutputPort", - "generic": null - } - } - ], - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "input_labels_dict": {}, - "input_port_variables": null, - "output_labels_dict": {}, - "previous_value": null, - "variable": [ - [ - 0.0, - 0.0 - ] - ] - }, - "execute_until_finished": true, - "input_ports": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "output_ports": null - }, - "type": { - "PNL": "ProcessingMechanism", - "generic": null - } - }, - "word_hidden": { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, + 0.5 + ], + "execute_until_finished": true, "has_initializers": false, - "output_type": 3, - "variable": [ - [ - 0.0, - 0.0 - ] - ] - }, - "bias": { - "source": "word_hidden.input_ports.bias", - "type": "int", - "value": -4 - }, - "bounds": null, - "execute_until_finished": true, - "gain": { - "source": "word_hidden.input_ports.gain", - "type": "float", - "value": 1.0 - }, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": { - "source": "word_hidden.input_ports.offset", - "type": "float", - "value": 0.0 - }, - "scale": { - "source": "word_hidden.input_ports.scale", - "type": "float", - "value": 1.0 - }, - "x_0": { - "source": "word_hidden.input_ports.x_0", - "type": "float", - "value": 0.0 + "max_executions_before_finished": 1000, + "projections": [ + [ + "TASK.input_ports.gain", + null, + null, + { + "PROJECTION_TYPE": "ControlProjection" + } + ] + ], + "modulation": "multiplicative_param", + "allocation_samples": null } - }, - "name": "Logistic Function-4", - "type": { - "generic": "Logistic" } } - ], - "input_ports": [ - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ + } + }, + "edges": { + "MappingProjection_from_color_input_OutputPort_0__to_color_hidden_InputPort_0_": { + "parameters": { + "weight": 1 + }, + "sender": "color_input", + "receiver": "color_hidden", + "sender_port": "color_input_OutputPort_0", + "receiver_port": "color_hidden_input_port_MappingProjection_from_color_input_OutputPort_0__to_color_hidden_InputPort_0_", + "metadata": { + "type": "MappingProjection", + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "exponent": null, + "weight": null, + "functions": { + "LinearMatrix_Function_3": { + "function": { + "onnx::MatMul": { + "B": [ [ - 0.0, - 0.0 + 2.0, + -2.0 ], [ - 2.513264753181465, - 2.513264753181465 + -2.0, + 2.0 ] ] - }, - "execute_until_finished": true, - "exponents": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": 0.0, - "operation": "sum", - "scale": 1.0, - "weights": null + } }, - "name": "LinearCombination Function-49", - "type": { - "PNL": "LinearCombination", - "generic": null - } - } - ], - "name": "InputPort-0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "internal_only": false, - "require_projection_in_composition": true, - "shadow_inputs": null, - "variable": [ - [ + "args": { + "B": [ + [ + 2.0, + -2.0 + ], + [ + -2.0, + 2.0 + ] + ] + }, + "metadata": { + "type": "LinearMatrix", + "output_type": "FunctionOutputType.DEFAULT", + "A": [ 0.0, 0.0 ], - [ - 2.513264753181465, - 2.513264753181465 - ] - ] - }, - "combine": null, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null, - "weight": null - }, - "shape": "(2, 2)", - "type": { - "PNL": "InputPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 - ] - }, - "bounds": null, + "changes_shape": false, "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-27", - "type": { - "generic": "Linear" + "has_initializers": false, + "enable_output_type_conversion": false, + "bounds": null, + "function_stateful_params": {} } } - ], - "name": "scale", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null } + } + }, + "MappingProjection_from_color_hidden_OutputPort_0__to_OUTPUT_InputPort_0_": { + "parameters": { + "weight": 1 }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 + "sender": "color_hidden", + "receiver": "OUTPUT", + "sender_port": "color_hidden_OutputPort_0", + "receiver_port": "OUTPUT_input_port_MappingProjection_from_color_hidden_OutputPort_0__to_OUTPUT_InputPort_0_", + "metadata": { + "type": "MappingProjection", + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "exponent": null, + "weight": null, + "functions": { + "LinearMatrix_Function_4": { + "function": { + "onnx::MatMul": { + "B": [ + [ + 2.0, + -2.0 + ], + [ + -2.0, + 2.0 + ] ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 + } }, - "name": "Linear Function-28", - "type": { - "generic": "Linear" - } - } - ], - "name": "offset", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "float64", - "functions": [ - { "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0 + "B": [ + [ + 2.0, + -2.0 + ], + [ + -2.0, + 2.0 ] - }, - "bounds": null, + ] + }, + "metadata": { + "type": "LinearMatrix", + "output_type": "FunctionOutputType.DEFAULT", + "A": [ + 0.017986209962091562, + 0.017986209962091562 + ], + "changes_shape": false, "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-29", - "type": { - "generic": "Linear" + "has_initializers": false, + "enable_output_type_conversion": false, + "bounds": null, + "function_stateful_params": {} } } - ], - "name": "x_0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null } + } + }, + "MappingProjection_from_word_input_OutputPort_0__to_word_hidden_InputPort_0_": { + "parameters": { + "weight": 1 }, - { - "dtype": "float64", - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 1.0 + "sender": "word_input", + "receiver": "word_hidden", + "sender_port": "word_input_OutputPort_0", + "receiver_port": "word_hidden_input_port_MappingProjection_from_word_input_OutputPort_0__to_word_hidden_InputPort_0_", + "metadata": { + "type": "MappingProjection", + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "exponent": null, + "weight": null, + "functions": { + "LinearMatrix_Function_7": { + "function": { + "onnx::MatMul": { + "B": [ + [ + 3.0, + -3.0 + ], + [ + -3.0, + 3.0 + ] ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 + } }, - "name": "Linear Function-30", - "type": { - "generic": "Linear" - } - } - ], - "name": "gain", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null - } - }, - { - "dtype": "int64", - "functions": [ - { "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - -4 + "B": [ + [ + 3.0, + -3.0 + ], + [ + -3.0, + 3.0 ] - }, - "bounds": null, + ] + }, + "metadata": { + "type": "LinearMatrix", + "output_type": "FunctionOutputType.DEFAULT", + "A": [ + 0.0, + 0.0 + ], + "changes_shape": false, "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-31", - "type": { - "generic": "Linear" + "has_initializers": false, + "enable_output_type_conversion": false, + "bounds": null, + "function_stateful_params": {} } } - ], - "name": "bias", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - -4 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null } } - ], - "name": "word_hidden", - "output_ports": [ - { - "dtype": "float64", - "functions": [ - { + }, + "MappingProjection_from_word_hidden_OutputPort_0__to_OUTPUT_InputPort_0_": { + "parameters": { + "weight": 1 + }, + "sender": "word_hidden", + "receiver": "OUTPUT", + "sender_port": "word_hidden_OutputPort_0", + "receiver_port": "OUTPUT_input_port_MappingProjection_from_word_hidden_OutputPort_0__to_OUTPUT_InputPort_0_", + "metadata": { + "type": "MappingProjection", + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "exponent": null, + "weight": null, + "functions": { + "LinearMatrix_Function_8": { + "function": { + "onnx::MatMul": { + "B": [ + [ + 3.0, + -3.0 + ], + [ + -3.0, + 3.0 + ] + ] + } + }, "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.017986209962091562, - 0.017986209962091562 + "B": [ + [ + 3.0, + -3.0 + ], + [ + -3.0, + 3.0 ] - }, - "bounds": null, + ] + }, + "metadata": { + "type": "LinearMatrix", + "output_type": "FunctionOutputType.DEFAULT", + "A": [ + 0.017986209962091562, + 0.017986209962091562 + ], + "changes_shape": false, "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-33", - "type": { - "generic": "Linear" + "has_initializers": false, + "enable_output_type_conversion": false, + "bounds": null, + "function_stateful_params": {} } } - ], - "name": "OutputPort-0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.017986209962091562, - 0.017986209962091562 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(2,)", - "type": { - "PNL": "OutputPort", - "generic": null } } - ], - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "input_labels_dict": {}, - "input_port_variables": null, - "output_labels_dict": {}, - "previous_value": null, - "variable": [ - [ - 0.0, - 0.0 - ] - ] - }, - "execute_until_finished": true, - "input_ports": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "output_ports": null }, - "type": { - "PNL": "ProcessingMechanism", - "generic": null - } - }, - "word_input": { - "functions": [ - { - "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - [ + "MappingProjection_from_task_input_OutputPort_0__to_TASK_InputPort_0_": { + "parameters": { + "weight": 1 + }, + "sender": "task_input", + "receiver": "TASK", + "sender_port": "task_input_OutputPort_0", + "receiver_port": "TASK_input_port_MappingProjection_from_task_input_OutputPort_0__to_TASK_InputPort_0_", + "metadata": { + "type": "MappingProjection", + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "exponent": null, + "weight": null, + "functions": { + "LinearMatrix_Function_10": { + "function": { + "onnx::MatMul": { + "B": [ + [ + 1.0, + 0.0 + ], + [ + 0.0, + 1.0 + ] + ] + } + }, + "args": { + "B": [ + [ + 1.0, + 0.0 + ], + [ + 0.0, + 1.0 + ] + ] + }, + "metadata": { + "type": "LinearMatrix", + "output_type": "FunctionOutputType.DEFAULT", + "A": [ 0.0, 0.0 - ] - ] - }, - "bounds": null, - "execute_until_finished": true, - "intercept": { - "source": "word_input.input_ports.intercept", - "type": "float", - "value": 0.0 - }, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": { - "source": "word_input.input_ports.slope", - "type": "float", - "value": 1.0 + ], + "changes_shape": false, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "enable_output_type_conversion": false, + "bounds": null, + "function_stateful_params": {} + } } - }, - "name": "Linear Function-24", - "type": { - "generic": "Linear" } } - ], - "input_ports": [ - { - "dtype": "float64", - "functions": [ - { + }, + "MappingProjection_from_TASK_RESULT__to_color_hidden_InputPort_0_": { + "parameters": { + "weight": 1 + }, + "sender": "TASK", + "receiver": "color_hidden", + "sender_port": "TASK_RESULT", + "receiver_port": "color_hidden_input_port_MappingProjection_from_TASK_RESULT__to_color_hidden_InputPort_0_", + "metadata": { + "type": "MappingProjection", + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "exponent": null, + "weight": null, + "functions": { + "LinearMatrix_Function_11": { + "function": { + "onnx::MatMul": { + "B": [ + [ + 4.0, + 4.0 + ], + [ + 0.0, + 0.0 + ] + ] + } + }, "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ + "B": [ + [ + 4.0, + 4.0 + ], + [ 0.0, 0.0 ] - }, + ] + }, + "metadata": { + "type": "LinearMatrix", + "output_type": "FunctionOutputType.DEFAULT", + "A": [ + 0.5, + 0.5 + ], + "changes_shape": false, "execute_until_finished": true, - "exponents": null, - "is_finished_flag": true, "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "offset": 0.0, - "operation": "sum", - "scale": 1.0, - "weights": null - }, - "name": "LinearCombination Function-41", - "type": { - "PNL": "LinearCombination", - "generic": null + "has_initializers": false, + "enable_output_type_conversion": false, + "bounds": null, + "function_stateful_params": {} } } - ], - "name": "InputPort-0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "internal_only": false, - "require_projection_in_composition": true, - "shadow_inputs": null, - "variable": [ - 0.0, - 0.0 - ] - }, - "combine": null, - "execute_until_finished": true, - "exponent": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null, - "weight": null - }, - "shape": "(2,)", - "type": { - "PNL": "InputPort", - "generic": null } + } + }, + "MappingProjection_from_TASK_RESULT__to_word_hidden_InputPort_0_": { + "parameters": { + "weight": 1 }, - { - "dtype": "float64", - "functions": [ - { + "sender": "TASK", + "receiver": "word_hidden", + "sender_port": "TASK_RESULT", + "receiver_port": "word_hidden_input_port_MappingProjection_from_TASK_RESULT__to_word_hidden_InputPort_0_", + "metadata": { + "type": "MappingProjection", + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "exponent": null, + "weight": null, + "functions": { + "LinearMatrix_Function_13": { + "function": { + "onnx::MatMul": { + "B": [ + [ + 0.0, + 0.0 + ], + [ + 4.0, + 4.0 + ] + ] + } + }, "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ + "B": [ + [ + 0.0, 0.0 + ], + [ + 4.0, + 4.0 ] - }, - "bounds": null, + ] + }, + "metadata": { + "type": "LinearMatrix", + "output_type": "FunctionOutputType.DEFAULT", + "A": [ + 0.5, + 0.5 + ], + "changes_shape": false, "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-22", - "type": { - "generic": "Linear" + "has_initializers": false, + "enable_output_type_conversion": false, + "bounds": null, + "function_stateful_params": {} } } - ], - "name": "intercept", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null } + } + }, + "MappingProjection_from_OUTPUT_OutputPort_0__to_DECISION_ARRAY_": { + "parameters": { + "weight": 1 }, - { - "dtype": "float64", - "functions": [ - { + "sender": "OUTPUT", + "receiver": "DECISION", + "sender_port": "OUTPUT_OutputPort_0", + "receiver_port": "DECISION_ARRAY", + "metadata": { + "type": "MappingProjection", + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "exponent": null, + "weight": null, + "functions": { + "LinearMatrix_Function_14": { + "function": { + "onnx::MatMul": { + "B": [ + [ + 1.0, + 0.0 + ], + [ + 0.0, + 1.0 + ] + ] + } + }, "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ + "B": [ + [ + 1.0, + 0.0 + ], + [ + 0.0, 1.0 ] - }, - "bounds": null, + ] + }, + "metadata": { + "type": "LinearMatrix", + "output_type": "FunctionOutputType.DEFAULT", + "A": [ + 0.5, + 0.5 + ], + "changes_shape": false, "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-23", - "type": { - "generic": "Linear" + "has_initializers": false, + "enable_output_type_conversion": false, + "bounds": null, + "function_stateful_params": {} } } - ], - "name": "slope", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 1.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(1,)", - "type": { - "PNL": "ParameterPort", - "generic": null } } - ], - "name": "word_input", - "output_ports": [ - { - "dtype": "float64", - "functions": [ - { + }, + "MappingProjection_from_OUTPUT_OutputPort_0__to_Conflict_Monitor_InputPort_0_": { + "parameters": { + "weight": 1 + }, + "sender": "OUTPUT", + "receiver": "Conflict_Monitor", + "sender_port": "OUTPUT_OutputPort_0", + "receiver_port": "Conflict_Monitor_Value_of_OUTPUT__OutputPort_0_", + "metadata": { + "type": "MappingProjection", + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "exponent": null, + "weight": null, + "functions": { + "LinearMatrix_Function_1": { + "function": { + "onnx::MatMul": { + "B": [ + [ + 1.0, + 0.0 + ], + [ + 0.0, + 1.0 + ] + ] + } + }, "args": { - "PNL": { - "enable_output_type_conversion": false, - "execution_count": 0, - "has_initializers": false, - "output_type": 3, - "variable": [ - 0.0, + "B": [ + [ + 1.0, 0.0 + ], + [ + 0.0, + 1.0 ] - }, - "bounds": null, + ] + }, + "metadata": { + "type": "LinearMatrix", + "output_type": "FunctionOutputType.DEFAULT", + "A": [ + 0.5, + 0.5 + ], + "changes_shape": false, "execute_until_finished": true, - "intercept": 0.0, - "is_finished_flag": true, "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "slope": 1.0 - }, - "name": "Linear Function-26", - "type": { - "generic": "Linear" + "has_initializers": false, + "enable_output_type_conversion": false, + "bounds": null, + "function_stateful_params": {} } } - ], - "name": "OutputPort-0", - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "require_projection_in_composition": true, - "variable": [ - 0.0, - 0.0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "projections": null - }, - "shape": "(2,)", - "type": { - "PNL": "OutputPort", - "generic": null } } - ], - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "input_labels_dict": {}, - "input_port_variables": null, - "output_labels_dict": {}, - "previous_value": null, - "variable": [ - [ - 0.0, - 0.0 - ] - ] - }, - "execute_until_finished": true, - "input_ports": null, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "output_ports": null }, - "type": { - "PNL": "ProcessingMechanism", - "generic": null - } - } - }, - "parameters": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "node_ordering": [ - "color_input", - "color_hidden", - "OUTPUT", - "word_input", - "word_hidden", - "task_input", - "TASK", - "DECISION", - "CONTROL", - "Conflict Monitor" - ], - "required_node_roles": [], - "results": [], - "schedulers": { - "ContextFlags.PROCESSING": { - "conditions": { - "node": { - "DECISION": { - "args": [ - "OUTPUT", - 1 - ], - "function": null, - "kwargs": {}, - "type": "EveryNCalls" - }, - "OUTPUT": { - "args": [ - { - "args": [ - "color_hidden", - 1 - ], - "function": null, - "kwargs": {}, - "type": "EveryNCalls" - }, - { - "args": [ - "word_hidden", - 1 - ], - "function": null, - "kwargs": {}, - "type": "EveryNCalls" - } - ], - "function": null, - "kwargs": {}, - "type": "All" + "MappingProjection_from_Conflict_Monitor_OUTCOME__to_CONTROL_OUTCOME_": { + "parameters": { + "weight": 1 + }, + "sender": "Conflict_Monitor", + "receiver": "CONTROL", + "sender_port": "Conflict_Monitor_OUTCOME", + "receiver_port": "CONTROL_OUTCOME", + "metadata": { + "type": "MappingProjection", + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "exponent": null, + "weight": null, + "functions": { + "LinearMatrix_Function_2": { + "function": { + "onnx::MatMul": { + "B": [ + [ + 1.0 + ] + ] + } }, - "color_hidden": { - "args": [ - "TASK", - 10 - ], - "function": null, - "kwargs": {}, - "type": "EveryNCalls" + "args": { + "B": [ + [ + 1.0 + ] + ] }, - "word_hidden": { - "args": [ - "TASK", - 10 + "metadata": { + "type": "LinearMatrix", + "output_type": "FunctionOutputType.DEFAULT", + "A": [ + 0.0 ], - "function": null, - "kwargs": {}, - "type": "EveryNCalls" - } - }, - "termination": { - "TimeScale.RUN": { - "args": [], - "function": null, - "kwargs": {}, - "type": "Never" - }, - "TimeScale.TRIAL": { - "args": [], - "function": null, - "kwargs": {}, - "type": "AllHaveRun" + "changes_shape": false, + "execute_until_finished": true, + "max_executions_before_finished": 1000, + "has_initializers": false, + "enable_output_type_conversion": false, + "bounds": null, + "function_stateful_params": {} } } } } - }, - "simulation_results": [], - "variable": [ - 0 - ] - }, - "execute_until_finished": true, - "is_finished_flag": true, - "max_executions_before_finished": 1000, - "num_executions_before_finished": 0, - "retain_old_simulation_data": false - }, - "type": { - "PNL": "Composition", - "generic": "graph" + } + } } } - ] + } } diff --git a/docs/source/conf.py b/docs/source/conf.py index db59aec563f..eb2a9596d60 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -372,6 +372,8 @@ def setup(app): #skip typehints autodoc_typehints = 'none' +# autodoc_typehints = 'signature' +# typehints_defaults = 'comma' default_role = 'any' diff --git a/docs/source/index.rst b/docs/source/index.rst index c02d7a7ddd6..70e1e0ba79b 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -3,6 +3,11 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. +.. ***************************************************************************************** +.. ****** NOTE: UPDATES TO THIS PAGE SHOULD ALSO BE MADE TO README.rst ******************** +.. ***************************************************************************************** + + :tocdepth: 5 .. |logo| image:: _static/PsyNeuLink_logo_no_text.svg diff --git a/docs/source/json.rst b/docs/source/mdf.rst similarity index 91% rename from docs/source/json.rst rename to docs/source/mdf.rst index cd95ba8bf26..5f1fd9cad69 100644 --- a/docs/source/json.rst +++ b/docs/source/mdf.rst @@ -1,5 +1,5 @@ -JSON -==== +MDF +=== .. automodule:: psyneulink.core.globals.json :members: diff --git a/psyneulink/core/components/component.py b/psyneulink/core/components/component.py index 548fe2cfdd8..bbe4c760afe 100644 --- a/psyneulink/core/components/component.py +++ b/psyneulink/core/components/component.py @@ -397,7 +397,7 @@ .. note:: - `Mechanisms` ` are the only type of Component that reset when the `reset_stateful_function_when + `Mechanisms ` are the only type of Component that reset when the `reset_stateful_function_when ` `Condition` is satisfied. Other Component types do not reset, although `Composition` has a `reset ` method that can be used to reset all of its eligible Mechanisms (see `Composition_Reset`) @@ -518,8 +518,9 @@ CONTEXT, CONTROL_PROJECTION, DEFERRED_INITIALIZATION, EXECUTE_UNTIL_FINISHED, \ FUNCTION, FUNCTION_PARAMS, INIT_FULL_EXECUTE_METHOD, INPUT_PORTS, \ LEARNING, LEARNING_PROJECTION, MATRIX, MAX_EXECUTIONS_BEFORE_FINISHED, \ - MODEL_SPEC_ID_PSYNEULINK, MODEL_SPEC_ID_GENERIC, MODEL_SPEC_ID_TYPE, MODEL_SPEC_ID_PARAMETER_SOURCE, \ - MODEL_SPEC_ID_PARAMETER_VALUE, MODEL_SPEC_ID_INPUT_PORTS, MODEL_SPEC_ID_OUTPUT_PORTS, \ + MODEL_SPEC_ID_PSYNEULINK, MODEL_SPEC_ID_METADATA, \ + MODEL_SPEC_ID_INPUT_PORTS, MODEL_SPEC_ID_OUTPUT_PORTS, \ + MODEL_SPEC_ID_MDF_VARIABLE, \ MODULATORY_SPEC_KEYWORDS, NAME, OUTPUT_PORTS, OWNER, PARAMS, PREFS_ARG, \ RESET_STATEFUL_FUNCTION_WHEN, VALUE, VARIABLE from psyneulink.core.globals.log import LogCondition @@ -533,7 +534,7 @@ from psyneulink.core.globals.utilities import \ ContentAddressableList, convert_all_elements_to_np_array, convert_to_np_array, get_deepcopy_with_shared, \ is_instance_or_subclass, is_matrix, iscompatible, kwCompatibilityLength, prune_unused_args, \ - get_all_explicit_arguments, call_with_pruned_args, safe_equals, safe_len + get_all_explicit_arguments, call_with_pruned_args, safe_equals, safe_len, parse_valid_identifier from psyneulink.core.scheduling.condition import Never from psyneulink.core.scheduling.time import Time, TimeScale @@ -789,7 +790,8 @@ class Component(JSONDumpable, metaclass=ComponentsMeta): --------- default_variable : scalar, list or array : default [[0]] - specifies template for the input to the Component's `function `. + specifies template for the input to the Component's `function `, and the value used as the + input to the Component if none is provided on execution (see `Component_Variable` for additional information). size : int, list or np.ndarray of ints : default None specifies default_variable as array(s) of zeros if **default_variable** is not passed as an argument; @@ -909,6 +911,7 @@ class Component(JSONDumpable, metaclass=ComponentsMeta): # helper attributes for JSON model spec _model_spec_id_parameters = 'parameters' + _model_spec_id_stateful_parameters = 'stateful_parameters' _model_spec_generic_type_name = NotImplemented """ @@ -1008,10 +1011,10 @@ class Parameters(ParametersBase): fallback_default=True, pnl_internal=True) is_finished_flag = Parameter(True, loggable=False, stateful=True) - execute_until_finished = True - num_executions = Parameter(Time(), read_only=True, modulable=False, loggable=False) - num_executions_before_finished = Parameter(0, read_only=True, modulable=False) - max_executions_before_finished = Parameter(1000, modulable=False) + execute_until_finished = Parameter(True, pnl_internal=True) + num_executions = Parameter(Time(), read_only=True, modulable=False, loggable=False, pnl_internal=True) + num_executions_before_finished = Parameter(0, read_only=True, modulable=False, pnl_internal=True) + max_executions_before_finished = Parameter(1000, modulable=False, pnl_internal=True) def _parse_variable(self, variable): if variable is None: @@ -1312,14 +1315,22 @@ def __deepcopy__(self, memo): def _get_compilation_state(self): # FIXME: MAGIC LIST, Use stateful tag for this whitelist = {"previous_time", "previous_value", "previous_v", - "previous_w", "random_state", "is_finished_flag", - "num_executions_before_finished", "num_executions", - "execution_count", "value", "input_ports", "output_ports"} - blacklist = { # References to other components - "objective_mechanism", "agent_rep", "projections"} - # Only mechanisms use "value" state - if not hasattr(self, 'ports'): - blacklist.add("value") + "previous_w", "random_state", + "input_ports", "output_ports"} + # Prune subcomponents (which are enabled by type rather than a list) + # that should be omitted + blacklist = { "objective_mechanism", "agent_rep", "projections"} + + # Only mechanisms use "value" state, can execute 'until finished', + # and need to track executions + if hasattr(self, 'ports'): + whitelist.update({"value", "num_executions_before_finished", + "num_executions", "is_finished_flag"}) + + # Only mechanisms and compositions need 'num_executions' + if hasattr(self, 'nodes'): + whitelist.add("num_executions") + def _is_compilation_state(p): #FIXME: This should use defaults instead of 'p.get' return p.name not in blacklist and \ @@ -1370,24 +1381,48 @@ def _get_compilation_params(self): "previous_w", "random_state", "is_finished_flag", "num_executions_before_finished", "num_executions", "variable", "value", "saved_values", "saved_samples", + "integrator_function_value", "termination_measure_value", + "execution_count", # Invalid types "input_port_variables", "results", "simulation_results", "monitor_for_control", "state_feature_values", "simulation_ids", "input_labels_dict", "output_labels_dict", "num_estimates", "modulated_mechanisms", "grid", "control_signal_params", "activation_derivative_fct", "input_specification", + "state_feature_specs", # Reference to other components "objective_mechanism", "agent_rep", "projections", - # Shape mismatch - "auto", "hetero", "cost", "costs", "combined_costs", - "control_signal", + "outcome_input_ports", "state_input_ports", # autodiff specific types - "pytorch_representation", "optimizer"} + "pytorch_representation", "optimizer", + # duplicate + "allocation_samples", "control_allocation_search_space", + # not used in computation + "auto", "hetero", "cost", "costs", "combined_costs", + "control_signal", "intensity", "competition", + "has_recurrent_input_port", "enable_learning", + "enable_output_type_conversion", "changes_shape", + "output_type", "bounds", "internal_only", + "require_projection_in_composition", "default_input", + "shadow_inputs", "compute_reconfiguration_cost", + "reconfiguration_cost", "net_outcome", "outcome", + "adjustment_cost", "intensity_cost", "duration_cost", + "enabled_cost_functions", "control_signal_costs", + "default_allocation", "same_seed_for_all_allocations", + "search_statefulness", "initial_seed", "combine", + "smoothing_factor", + } # Mechanism's need few extra entires: # * matrix -- is never used directly, and is flatened below # * integration rate -- shape mismatch with param port input if hasattr(self, 'ports'): blacklist.update(["matrix", "integration_rate"]) + else: + # Execute until finished is only used by mechanisms + blacklist.update(["execute_until_finished", "max_executions_before_finished"]) + # "has_initializers" is only used by RTM + blacklist.update(["has_initializers"]) + def _is_compilation_param(p): if p.name not in blacklist and not isinstance(p, (ParameterAlias, SharedParameter)): #FIXME: this should use defaults @@ -2057,7 +2092,7 @@ def _is_user_specified(parameter): for p in filter(lambda x: not isinstance(x, (ParameterAlias, SharedParameter)), self.parameters._in_dependency_order): # copy spec so it is not overwritten later # TODO: check if this is necessary - p.spec = copy_parameter_value(p.spec) + p.spec = copy_parameter_value(p.spec, shared_types=shared_types) # set default to None context to ensure it exists if ( @@ -3085,7 +3120,7 @@ def _execute(self, variable=None, context=None, runtime_params=None, **kwargs): self._update_current_execution_time(context=context) self._increment_num_executions( context, - [TimeScale.TIME_STEP, TimeScale.PASS, TimeScale.TRIAL, TimeScale.RUN] + [TimeScale.TIME_STEP, TimeScale.PASS, TimeScale.TRIAL, TimeScale.RUN, TimeScale.LIFE] ) value = None @@ -3614,26 +3649,41 @@ def _all_dependent_parameters(obj, filter_name, filter_regex, visited): return _all_dependent_parameters(self, filter_name, filter_regex, set()) - @property - def _dict_summary(self): + def _get_mdf_parameters(self): + import modeci_mdf.mdf as mdf + from psyneulink.core.compositions.composition import Composition from psyneulink.core.components.ports.port import Port from psyneulink.core.components.ports.outputport import OutputPort - from psyneulink.core.components.ports.parameterport import ParameterPortError from psyneulink.core.components.functions.nonstateful.transferfunctions import LinearMatrix - def parse_parameter_value(value): + def parse_parameter_value(value, no_expand_components=False, functions_as_dill=False): if isinstance(value, (list, tuple)): + try: + # treat as a collections.namedtuple + type(value)._fields + except AttributeError: + pass + else: + # cannot expect MDF/neuromllite to handle our namedtuples + value = tuple(value) + new_item = [] for item in value: - new_item.append(parse_parameter_value(item)) + new_item.append( + parse_parameter_value( + item, + no_expand_components, + functions_as_dill + ) + ) try: value = type(value)(new_item) except TypeError: value = type(value)(*new_item) elif isinstance(value, dict): value = { - parse_parameter_value(k): parse_parameter_value(v) + parse_parameter_value(k, no_expand_components, functions_as_dill): parse_parameter_value(v, no_expand_components, functions_as_dill) for k, v in value.items() } elif isinstance(value, Composition): @@ -3657,14 +3707,57 @@ def parse_parameter_value(value): # is necessary. # in fact this would happen unless the parser specifically # handles it like ours does - value = value._dict_summary - elif isinstance(value, (types.FunctionType)): - value = base64.encodebytes(dill.dumps(value)).decode('utf-8') + if no_expand_components: + value = parse_valid_identifier(value.name) + else: + try: + value = value.as_mdf_model(simple_edge_format=False) + except TypeError: + value = value.as_mdf_model() + elif isinstance(value, ComponentsMeta): + value = value.__name__ + elif isinstance(value, (type, types.BuiltinFunctionType)): + if value.__module__ == 'builtins': + # just give standard type, like float or int + value = f'{value.__name__}' + elif value is np.ndarray: + value = f'{value.__module__}.array' + else: + # some builtin modules are internally "_module" + # but are imported with "module" + value = f"{value.__module__.lstrip('_')}.{value.__name__}" + elif isinstance(value, types.MethodType): + if isinstance(value.__self__, Component): + # assume reference to a method on a Component is + # automatically assigned (may not be totally + # accurate but is in current known cases) + value = None + else: + value = value.__qualname__ + elif isinstance(value, types.FunctionType): + if functions_as_dill: + value = base64.encodebytes(dill.dumps(value)).decode('utf-8') + elif '.' in value.__qualname__: + value = value.__qualname__ + else: + try: + if value is getattr(eval(value.__module__.replace('numpy', 'np')), value.__qualname__): + return f'{value.__module__}.{value.__qualname__}' + except (AttributeError, NameError, TypeError): + pass - return value + value = str(value) + elif isinstance(value, SampleIterator): + value = f'{value.__class__.__name__}({repr(value.specification)})' + elif value is NotImplemented: + value = None + # IntEnum gets treated as int + elif isinstance(value, (Enum, types.SimpleNamespace)): + value = str(value) + elif not isinstance(value, (float, int, str, bool, mdf.Base, type(None), np.ndarray)): + value = str(value) - # attributes (and their values) included in top-level dict - basic_attributes = ['name'] + return value # attributes that aren't Parameters but are psyneulink-specific # and are stored in the PNL parameters section @@ -3687,7 +3780,7 @@ def parse_parameter_value(value): for p in self.parameters: if ( p.name not in self._model_spec_parameter_blacklist - and not isinstance(p, ParameterAlias) + and not isinstance(p, (ParameterAlias, SharedParameter)) ): if self.initialization_status is ContextFlags.DEFERRED_INIT: try: @@ -3707,69 +3800,98 @@ def parse_parameter_value(value): elif p.spec is not None: val = p.spec else: - val = p.default_value - - val = parse_parameter_value(val) + val = None + if not p.stateful and not p.structural: + val = p.get(None) + if val is None: + val = p.default_value - try: - matching_parameter_port = self.owner.parameter_ports[p.name] - - if matching_parameter_port.source._owner._owner is self: - val = { - MODEL_SPEC_ID_PARAMETER_SOURCE: '{0}.{1}.{2}'.format( - self.owner.name, - MODEL_SPEC_ID_INPUT_PORTS, - p.name - ), - MODEL_SPEC_ID_PARAMETER_VALUE: val, - MODEL_SPEC_ID_TYPE: type(val) - } - # ContentAddressableList uses TypeError when key not found - except (AttributeError, TypeError, ParameterPortError): - pass + val = parse_parameter_value(val, functions_as_dill=True) # split parameters designated as PsyNeuLink-specific and # parameters that are universal if p.pnl_internal: - pnl_specific_parameters[p.name] = val + target_param_dict = pnl_specific_parameters + else: + target_param_dict = parameters_dict + + if p.mdf_name is not None: + target_param_dict[p.mdf_name] = val else: - parameters_dict[p.name] = val + target_param_dict[p.name] = val for attr in implicit_parameter_attributes: try: - pnl_specific_parameters[attr] = getattr(self, attr) + pnl_specific_parameters[attr] = parse_parameter_value(getattr(self, attr), no_expand_components=True, functions_as_dill=True) except AttributeError: pass if len(pnl_specific_parameters) > 0: parameters_dict[MODEL_SPEC_ID_PSYNEULINK] = pnl_specific_parameters - function_dict = {} + return {self._model_spec_id_parameters: {k: v for k, v in parameters_dict.items()}} + + @property + def _mdf_model_parameters(self): + params = self._get_mdf_parameters() try: - if isinstance(self.function, Component): - function_dict['functions'] = [self.function._dict_summary] - except AttributeError: + del params[self._model_spec_id_parameters][MODEL_SPEC_ID_PSYNEULINK] + except KeyError: pass - type_dict = {} + params[self._model_spec_id_parameters] = { + k: v for k, v in params[self._model_spec_id_parameters].items() + if ( + k == MODEL_SPEC_ID_MDF_VARIABLE + or ( + isinstance(v, (numbers.Number, np.ndarray)) + and not isinstance(v, bool) + ) + ) + } - if self._model_spec_class_name_is_generic: - type_dict[MODEL_SPEC_ID_GENERIC] = self.__class__.__name__ - else: - if self._model_spec_generic_type_name is not NotImplemented: - type_dict[MODEL_SPEC_ID_GENERIC] = self._model_spec_generic_type_name - else: - type_dict[MODEL_SPEC_ID_GENERIC] = None + return params - type_dict[MODEL_SPEC_ID_PSYNEULINK] = self.__class__.__name__ + @property + def _mdf_metadata(self): + all_parameters = self._get_mdf_parameters() + try: + params = all_parameters[self._model_spec_id_parameters][MODEL_SPEC_ID_PSYNEULINK] + except KeyError: + params = {} + + params = { + **params, + **{ + k: v for k, v in all_parameters[self._model_spec_id_parameters].items() + if ( + k not in {MODEL_SPEC_ID_MDF_VARIABLE, MODEL_SPEC_ID_PSYNEULINK} + and ( + not isinstance(v, (numbers.Number, np.ndarray)) + or isinstance(v, bool) + ) + ) + } + } return { - **{attr: getattr(self, attr) for attr in basic_attributes}, - **{self._model_spec_id_parameters: parameters_dict}, - **function_dict, - **{MODEL_SPEC_ID_TYPE: type_dict} + MODEL_SPEC_ID_METADATA: { + 'type': type(self).__name__, + **params + } } + def _set_mdf_arg(self, model, arg, value): + # must set both args attr and args in function because otherwise + # mdf dependency tracking doesn't work + try: + if model.function is not None: + model.function[list(model.function.keys())[0]][arg] = value + except AttributeError: + pass + + model.args[arg] = value + @property def logged_items(self): """Dictionary of all items that have entries in the log, and their currently assigned `ContextFlags`\\s @@ -3893,7 +4015,7 @@ def _model_spec_parameter_blacklist(self): A set of Parameter names that should not be added to the generated constructor string """ - return {'function', 'value'} + return {'function', 'value', 'execution_count', 'is_finished_flag', 'num_executions', 'num_executions_before_finished'} COMPONENT_BASE_CLASS = Component diff --git a/psyneulink/core/components/functions/fitfunctions.py b/psyneulink/core/components/functions/fitfunctions.py new file mode 100644 index 00000000000..14711f14569 --- /dev/null +++ b/psyneulink/core/components/functions/fitfunctions.py @@ -0,0 +1,514 @@ +from fastkde import fastKDE +from scipy.interpolate import interpn +from scipy.optimize import differential_evolution + +from psyneulink.core.globals.context import Context +from psyneulink.core.globals.parameters import Parameter +from psyneulink.core.scheduling.condition import AtTrialStart +from psyneulink.core.globals.parameters import Parameter +from psyneulink.core.llvm import ExecutionMode +from psyneulink.core.components.functions.nonstateful.optimizationfunctions import OptimizationFunction + + +import typing +import time +import numpy as np +import collections +import pandas as pd +from rich.progress import Progress, BarColumn, TimeRemainingColumn + +import warnings +import logging + +logger = logging.getLogger(__name__) + + +def get_param_str(params): + """ + A simple function to turn a dict into a string with commas separating key=value pairs. + + Parameters + ---------- + params: The parameters to print. + + Returns + ------- + The string version of the parameter dict + + """ + return ", ".join(f"{name}={value:.5f}" for name, value in params.items()) + + +class BadLikelihoodWarning(UserWarning): + """ + A custom warning that is used to signal when the likelihood could not be evaluated for some reason. + This is usually caused when parameter values cause degenerate simulation results (no variance in values). + It can also be caused when experimental data is not matching any of the simulation results. + """ + + pass + + +def simulation_likelihood( + sim_data, exp_data=None, categorical_dims=None, combine_trials=False +): + """ + Compute the likelihood of a simulation dataset (or the parameters that generated it) conditional + on a set of experimental data. This function essentially just computes the kernel density estimate (KDE) + of the simulation data at the experimental data points. If no experimental data is provided just return + the KDE evaluated at default points provided by the fastkde library. + + Some related work: + + Steven Miletić, Brandon M. Turner, Birte U. Forstmann, Leendert van Maanen, + Parameter recovery for the Leaky Competing Accumulator model, + Journal of Mathematical Psychology, + Volume 76, Part A, + 2017, + Pages 25-50, + ISSN 0022-2496, + https://doi.org/10.1016/j.jmp.2016.12.001. + (http://www.sciencedirect.com/science/article/pii/S0022249616301663) + + This function uses the wonderful fastKDE package: + + O’Brien, T. A., Kashinath, K., Cavanaugh, N. R., Collins, W. D. & O’Brien, J. P. + A fast and objective multidimensional kernel density estimation method: fastKDE. + Comput. Stat. Data Anal. 101, 148–160 (2016). + __ + + O’Brien, T. A., Collins, W. D., Rauscher, S. A. & Ringler, T. D. + Reducing the computational cost of the ECF using a nuFFT: A fast and objective probability density estimation method. + Comput. Stat. Data Anal. 79, 222–234 (2014). __ + + Parameters + ---------- + sim_data: Data collected over many simulations. This must be either a 2D or 3D numpy array. + If 2D, the first dimension is the simulation number and the second dimension is data points. That is, + each row is a simulation. If 3D, the first dimension is the trial, the second dimension is the + simulation number, and the final dimension is data points. + + exp_data: This must be a numpy array with identical format as the simulation data, with the exception + that there is no simulation dimension. + + categorical_dims: a list of indices that indicate categorical dimensions of a data point. Length must be + the same length as last dimension of sim_data and exp_data. + + combine_trials: Combine data across all trials into a single likelihood estimate, this assumes + that the parameters of the simulations are identical across trials. + + Returns + ------- + The pdf of simulation data (or in other words, the generating parameters) conditioned on the + experimental data. + + """ + + # Add a singleton dimension for trials if needed. + if sim_data.ndim == 2: + sim_data = sim_data[None, :, :] + + if combine_trials and sim_data.shape[0] > 1: + sim_data = np.vstack(sim_data)[None, :, :] + + if type(categorical_dims) != np.ndarray: + categorical_dims = np.array(categorical_dims) + + con_sim_data = sim_data[:, :, ~categorical_dims] + cat_sim_data = sim_data[:, :, categorical_dims] + + categories = np.unique(cat_sim_data) + kdes = [] + for trial in range(len(con_sim_data)): + s = con_sim_data[trial] + + # Compute a separate KDE for each combination of categorical variables. + dens_u = {} + for category in categories: + + # Get the subset of simulations that correspond to this category + dsub = s[cat_sim_data[trial] == category] + + # If we didn't get enough simulation results for this category, don't do + # a KDE + if len(dsub) < 100: + dens_u[category] = (None, None) + continue + + # If any dimension of the data has a 0 range (all are same value) then + # this will cause problems doing the KDE, skip. + data_range = ( + np.max(dsub) - np.min(dsub) + if dsub.ndim == 1 + else np.amax(dsub, 1) - np.amin(dsub, 1) + ) + if np.any(data_range == 0): + dens_u[category] = (None, None) + warnings.warn( + BadLikelihoodWarning( + f"Could not perform kernel density estimate. Range of simulation data was 0 for at least " + f"one dimension. Range={data_range}" + ) + ) + continue + + # Do KDE + fKDE = fastKDE.fastKDE(dsub, doSaveMarginals=False) + pdf = fKDE.pdf + axes = fKDE.axes + + # Scale the pdf by the fraction of simulations that fall within this category + pdf = pdf * (len(dsub) / len(s)) + + # Save the KDE values and axes for this category + dens_u[category] = (pdf, axes) + + kdes.append(dens_u) + + # If we are passed experimental data, evaluate the KDE at the experimental data points + if exp_data is not None: + + # For numerical reasons, make zero probability a really small value. This is because we are taking logs + # of the probabilities at the end. + ZERO_PROB = 1e-10 + + kdes_eval = np.zeros((len(exp_data),)) + for trial in range(len(exp_data)): + + # Extract the categorical values for this experimental trial + exp_trial_cat = exp_data[trial, categorical_dims] + + if len(exp_trial_cat) == 1: + exp_trial_cat = exp_trial_cat[0] + + # Get the right KDE for this trial, if all simulation trials have been combined + # use that KDE for all trials of experimental data. + if len(kdes) == 1: + kde, axes = kdes[0].get(exp_trial_cat, (None, None)) + else: + kde, axes = kdes[trial].get(exp_trial_cat, (None, None)) + + # Linear interpolation using the grid we computed the KDE + # on. + if kde is not None: + kdes_eval[trial] = interpn( + axes, + kde, + exp_data[trial, ~categorical_dims], + method="linear", + bounds_error=False, + fill_value=ZERO_PROB, + ) + else: + kdes_eval[trial] = ZERO_PROB + + # Check to see if any of the trials have non-zero likelihood, if not, something is probably wrong + # and we should warn the user. + if np.alltrue(kdes_eval == ZERO_PROB): + warnings.warn( + BadLikelihoodWarning( + "Evaluating likelihood generated by simulation data resulted in zero values for all trials " + "of experimental data. This means the model is not generating data similar to your " + "experimental data. If you have categorical dimensions, make sure values match exactly to " + "output values of the composition. Also make sure parameter ranges you are searching over " + "are reasonable for your data." + ) + ) + + return kdes_eval + + else: + return kdes + + +def make_likelihood_function( + composition: "psyneulink.core.composition.Composition", + fit_params: typing.List[Parameter], + inputs: typing.Union[np.ndarray, typing.List], + data_to_fit: typing.Union[np.ndarray, pd.DataFrame], + categorical_dims: typing.Union[np.ndarray, None] = None, + num_sims_per_trial: int = 1000, + fixed_params: typing.Optional[typing.Dict[Parameter, typing.Any]] = None, + combine_trials=True, +): + """ + Construct and return a Python function that returns the log likelihood of experimental + data being generated by a PsyNeuLink composition. The likelihood function is parameterized + by fit_params + + Parameters + ---------- + composition: A PsyNeuLink composition. This function returns a function that runs + many simulations of this composition to generate a kernel density estimate of the likelihood + of a dataset under different parameter settings. The output (composition.results) should match + the columns of data_to_fit exactly. + fit_params: A list of PsyNeuLink parameters to fit. Each on of these parameters will map to + an argument of the likelihood function that is returned. Values passed via these arguments + will be assigned to the composition before simulation. + fixed_params: A dict of PsyNeuLink parameters and their corresponding fixed values. These + parameters will be applied to the composition before simulation but will not be exposed as + arguments to the likelihood function. + inputs: A set of inputs to pass to the composition on each simulation of the likelihood. These + inputs are passed directly to the composition run method as is. + categorical_dims: If data_to_fit is a pandas DataFrame, this parameter is ignored and any Categorical column + is considered categorical. If data_to_fit is a ndarray, categorical_dims should be a 1D logical array, where + each element corresponds to a column of data_to_fit. If the element is True, the dimension should be considered + categorical, if False, it should be treated as continuous. Categorical is suitable for outputs that will only + take on a handful of unique values, such as the decision value of a DDM or LCA. + data_to_fit: Either 2D numpy array or Pandas DataFrame, where the rows are trials and the columns are + in the same format as outputs of the PsyNeuLink composition. This data essentially describes at + what values the KDE of the likelihood should be evaluated. + num_sims_per_trial: The number of simulations per trial to run to construct the KDE likelihood. + combine_trials: Whether we can combine simulations across trials for one estimate of the likelihood. + This can dramatically increase the speed of fitting by allowing a smaller number + of total simulations to run per trial. However, this cannot be done if the likelihood will change across + trials. + + Returns + ------- + A tuple containing: + - the likelihood function + - A dict which maps elements of fit_params to their keyword argument names in the likelihood function. + """ + + # We need to parse the inputs like composition does to get the number of trials + _, num_inputs_sets = composition._parse_run_inputs(inputs) + num_trials = num_inputs_sets + + # Check to see if any parameters (fittable or fixed) have the same name, + # this will cause problems, if so, we need to create a unique numbering. + # If we have multiple parameters with this name already, assign it the + # next available number + all_param_names = [p.name for p in fit_params] + dupe_counts = [ + all_param_names[:i].count(all_param_names[i]) + 1 + for i in range(len(all_param_names)) + ] + all_param_names = [ + name if count == 1 else f"{name}_{count}" + for name, count in zip(all_param_names, dupe_counts) + ] + param_name_map = dict(zip(fit_params, all_param_names)) + + if type(data_to_fit) == np.ndarray: + if data_to_fit.ndim != 2: + raise ValueError("data_to_fit must be a 2D") + + # Assume all dimensions are continuous if this wasn't specified by the user and their data is a numpy array + if categorical_dims is None: + categorical_dims = [False for i in range(data_to_fit.shape[1])] + + elif type(data_to_fit) == pd.DataFrame: + categorical_dims = [ + data_to_fit[c].dtype.name == "category" for c in data_to_fit.columns + ] + + else: + raise ValueError("data_to_fit must be a 2D numpy array or a Pandas DataFrame") + + def log_likelihood(**kwargs): + context = Context() + + # Assign parameter values to composition, eventually this should be done + # via the OptimizationControlMechanism and its control allocations stuff. + # However, currently the Python code for that creates a fresh context + # per simulation with considerable overhead. Instead, we create one context + # and use reset_stateful_functions_when=AtTrialStart(). Additionally, all simulations + # are computed in one call to compiled run via setting num_trials to + # num_simulations * len(input). + for param in fit_params: + try: + value = kwargs[param_name_map[param]] + except KeyError: + raise ValueError( + f"No argument {param_name_map[param]} passed to likelihood function for Parameter: \n{param}" + ) + + # FIXME: DDM requires that starting_value is an array in compiled mode for some reason. Ugly hack! + if param.name == "starting_value" and type(value) != np.ndarray: + value = np.array([value]) + + # Apply the parameter value under a fresh context + param.set(value, context) + + # Also apply the fixed parameters + if fixed_params is not None: + for param, value in fixed_params.items(): + param.set(value, context) + + # FIXME: Multiple calls to run retain results, we need to clear them. Is this OK? + composition.results.clear() + + # Run the composition for all simulations, this corresponds to looping over the input + # num_simulations times. + composition.run( + inputs=inputs, + num_trials=num_sims_per_trial * num_trials, + execution_mode=ExecutionMode.LLVMRun, + context=context, + ) + + results = np.squeeze(np.array(composition.results)) + + # Split results into (trials, simulations, data) + sim_data = np.array(np.vsplit(results, num_trials)) + + # Compute the likelihood given the data + like = simulation_likelihood( + sim_data=sim_data, + exp_data=data_to_fit.to_numpy().astype(float), + categorical_dims=categorical_dims, + combine_trials=combine_trials, + ) + + # Make 0 densities very small so log doesn't explode + like[like == 0.0] = 1.0e-10 + + return np.sum(np.log(like)) + + return log_likelihood, param_name_map + + +class MaxLikelihoodEstimatorFunction(OptimizationFunction): + pass + +class MaxLikelihoodEstimator: + """ + Implements a maximum likelihood estimation given a likelihood function + """ + + def __init__( + self, + log_likelihood_function: typing.Callable, + fit_params_bounds: typing.Dict[str, typing.Tuple], + ): + self.log_likelihood_function = log_likelihood_function + self.fit_params_bounds = fit_params_bounds + + # Setup a named tuple to store records for each iteration if the user requests it + self.IterRecord = collections.namedtuple( + "IterRecord", + f"{' '.join(self.fit_params_bounds.keys())} neg_log_likelihood likelihood_eval_time", + ) + + def fit(self, display_iter: bool = False, save_iterations: bool = False): + + bounds = list(self.fit_params_bounds.values()) + + # If the user has rich installed, make a nice progress bar + from rich.progress import Progress + + iterations = [] + + with Progress( + "[progress.description]{task.description}", + BarColumn(), + "Convergence: [progress.percentage]{task.percentage:>3.0f}%", + TimeRemainingColumn(), + ) as progress: + opt_task = progress.add_task( + "Maximum likelihood optimization ...", total=100, start=False + ) + + warns_with_params = [] + with warnings.catch_warnings(record=True) as warns: + + # Create a wrapper function for the objective. + def neg_log_like(x): + params = dict(zip(self.fit_params_bounds.keys(), x)) + t0 = time.time() + p = -self.log_likelihood_function(**params) + elapsed = time.time() - t0 + + # Keep a log of warnings and the parameters that caused them + if len(warns) > 0 and warns[-1].category == BadLikelihoodWarning: + warns_with_params.append((warns[-1], params)) + + # Are we displaying each iteration + if display_iter: + + # If we got a warning generating the likelihood, report it + if ( + len(warns) > 0 + and warns[-1].category == BadLikelihoodWarning + ): + progress.console.print(f"Warning: ", style="bold red") + progress.console.print( + f"{warns[-1].message}", style="bold red" + ) + progress.console.print( + f"{get_param_str(params)}, Neg-Log-Likelihood: {p}, " + f"Likelihood-Eval-Time: {elapsed} (seconds)", + style="bold red", + ) + # Clear the warnings + warns.clear() + else: + progress.console.print( + f"{get_param_str(params)}, Neg-Log-Likelihood: {p}, " + f"Likelihood-Eval-Time: {elapsed} (seconds)" + ) + + # Are we saving each iteration + if save_iterations: + iterations.append( + self.IterRecord( + **params, + neg_log_likelihood=p, + likelihood_eval_time=elapsed, + ) + ) + + return p + + def progress_callback(x, convergence): + progress.start_task(opt_task) + params = dict(zip(self.fit_params_bounds.keys(), x)) + convergence_pct = 100.0 * convergence + progress.console.print( + f"[green]Current Best Parameters: {get_param_str(params)}, Neg-Log-Likelihood: {neg_log_like(x)}" + ) + + # If we encounter any BadLikelihoodWarnings. Summarize them for the user + if len(warns_with_params) > 0: + progress.console.print( + "Warning: degenerate likelihood for the following parameter values ", + style="bold red", + ) + for w in warns_with_params: + progress.console.print( + f"\t{get_param_str(w[1])}", style="bold red" + ) + progress.console.print( + "If these warnings are intermittent, check to see if search " + "space is appropriately bounded. If they are constant, make sure " + "experimental data and output of your composition are similar.", + style="bold red", + ) + + progress.update(opt_task, completed=convergence_pct) + + r = differential_evolution( + neg_log_like, + bounds, + callback=progress_callback, + maxiter=500, + polish=False, + ) + + # Bind the fitted parameters to their names + fitted_params = dict(zip(list(self.fit_params_bounds.keys()), r.x)) + + # Save all the results + output_dict = { + "fitted_params": fitted_params, + "neg-log-likelihood": r.fun, + } + + # Return a record for each iteration if we were supposed to. + if save_iterations: + output_dict["iterations"] = pd.DataFrame.from_records( + iterations, columns=self.IterRecord._fields + ) + + return output_dict diff --git a/psyneulink/core/components/functions/function.py b/psyneulink/core/components/functions/function.py index 5b8cbb10ca7..cda41d037bf 100644 --- a/psyneulink/core/components/functions/function.py +++ b/psyneulink/core/components/functions/function.py @@ -141,6 +141,7 @@ """ import abc +import inspect import numbers import types import warnings @@ -149,21 +150,22 @@ import numpy as np import typecheck as tc -from psyneulink.core.components.component import ComponentError, DefaultsFlexibility +from psyneulink.core.components.component import Component, ComponentError, DefaultsFlexibility from psyneulink.core.components.shellclasses import Function, Mechanism from psyneulink.core.globals.context import ContextFlags, handle_external_context from psyneulink.core.globals.keywords import ( ARGUMENT_THERAPY_FUNCTION, AUTO_ASSIGN_MATRIX, EXAMPLE_FUNCTION_TYPE, FULL_CONNECTIVITY_MATRIX, FUNCTION_COMPONENT_CATEGORY, FUNCTION_OUTPUT_TYPE, FUNCTION_OUTPUT_TYPE_CONVERSION, HOLLOW_MATRIX, - IDENTITY_MATRIX, INVERSE_HOLLOW_MATRIX, NAME, PREFERENCE_SET_NAME, RANDOM_CONNECTIVITY_MATRIX + IDENTITY_MATRIX, INVERSE_HOLLOW_MATRIX, NAME, PREFERENCE_SET_NAME, RANDOM_CONNECTIVITY_MATRIX, VALUE, VARIABLE, + MODEL_SPEC_ID_METADATA, MODEL_SPEC_ID_MDF_VARIABLE ) from psyneulink.core.globals.parameters import Parameter from psyneulink.core.globals.preferences.basepreferenceset import REPORT_OUTPUT_PREF, is_pref_set from psyneulink.core.globals.preferences.preferenceset import PreferenceEntry, PreferenceLevel from psyneulink.core.globals.registry import register_category from psyneulink.core.globals.utilities import ( - convert_to_np_array, get_global_seed, object_has_single_value, parameter_spec, safe_len, - SeededRandomState + convert_to_np_array, get_global_seed, is_instance_or_subclass, object_has_single_value, parameter_spec, parse_valid_identifier, safe_len, + SeededRandomState, contains_type ) __all__ = [ @@ -368,6 +370,39 @@ def _random_state_getter(self, owning_component, context): return current_state +def _noise_setter(value, owning_component, context): + def has_function(x): + return ( + is_instance_or_subclass(x, (Function_Base, types.FunctionType)) + or contains_type(x, (Function_Base, types.FunctionType)) + ) + + noise_param = owning_component.parameters.noise + value_has_function = has_function(value) + # initial set + if owning_component.is_initializing: + if value_has_function: + # is changing a parameter attribute like this ok? + noise_param.stateful = False + else: + default_value_has_function = has_function(noise_param.default_value) + + if default_value_has_function and not value_has_function: + warnings.warn( + 'Setting noise to a numeric value after instantiation' + ' with a value containing functions will not remove the' + ' noise ParameterPort or make noise stateful.' + ) + elif not default_value_has_function and value_has_function: + warnings.warn( + 'Setting noise to a value containing functions after' + ' instantiation with a numeric value will not create a' + ' noise ParameterPort or make noise stateless.' + ) + + return value + + class Function_Base(Function): """ Function_Base( \ @@ -486,9 +521,12 @@ class Function_Base(Function): specifies whether `function output type conversion ` is enabled. output_type : FunctionOutputType : None - used to specify the return type for the `function `; `functionOuputTypeConversion` + used to determine the return type for the `function `; `functionOuputTypeConversion` must be enabled and implemented for the class (see `FunctionOutputType ` for details). + + changes_shape : bool : False + specifies whether the return value of the function is different than the shape of its `variable . Used to determine whether the shape of the inputs to the `Component` to which the function is assigned should be based on the `variable ` of the function or its `value `. COMMENT owner : Component @@ -535,11 +573,18 @@ class Parameters(Function.Parameters): :default value: False :type: ``bool`` + changes_shape + see `changes_shape ` + + :default value: False + :type: bool + output_type see `output_type ` :default value: FunctionOutputType.DEFAULT :type: `FunctionOutputType` + """ variable = Parameter(np.array([0]), read_only=True, pnl_internal=True, constructor_argument='default_variable') @@ -552,6 +597,11 @@ class Parameters(Function.Parameters): ) enable_output_type_conversion = Parameter(False, stateful=False, loggable=False, pnl_internal=True) + changes_shape = Parameter(False, stateful=False, loggable=False, pnl_internal=True) + def _validate_changes_shape(self, param): + if not isinstance(param, bool): + return f'must be a bool.' + # Note: the following enforce encoding as 1D np.ndarrays (one array per variable) variableEncodingDim = 1 @@ -637,7 +687,7 @@ def function(self, **kwargs) except ValueError as err: err_msg = f"Problem with '{self}' in '{self.owner.name if self.owner else self.__class__.__name__}': {err}" - raise FunctionError(err_msg) + raise FunctionError(err_msg) from err self.most_recent_context = context self.parameters.value._set(value, context=context) self._reset_runtime_parameters(context) @@ -766,6 +816,91 @@ def _model_spec_parameter_blacklist(self): 'multiplicative_param', 'additive_param', }) + def _get_mdf_noise_function(self): + import modeci_mdf.mdf as mdf + + extra_noise_functions = [] + + def handle_noise(noise): + if is_instance_or_subclass(noise, Component): + if inspect.isclass(noise) and issubclass(noise, Component): + noise = noise() + noise_func_model = noise.as_mdf_model() + extra_noise_functions.append(noise_func_model) + return noise_func_model.id + elif isinstance(noise, (list, np.ndarray)): + return type(noise)(handle_noise(item) for item in noise) + else: + return None + + noise = handle_noise(self.defaults.noise) + + if noise is not None: + return mdf.Function( + id=f'{parse_valid_identifier(self.name)}_noise', + value=MODEL_SPEC_ID_MDF_VARIABLE, + args={MODEL_SPEC_ID_MDF_VARIABLE: noise}, + ), extra_noise_functions + + def as_mdf_model(self): + import modeci_mdf.mdf as mdf + import modeci_mdf.functions.standard as mdf_functions + + parameters = self._mdf_model_parameters + metadata = self._mdf_metadata + metadata[MODEL_SPEC_ID_METADATA]['function_stateful_params'] = {} + stateful_params = set() + + # add stateful parameters into metadata for mechanism to get + for name in parameters[self._model_spec_id_parameters]: + try: + param = getattr(self.parameters, name) + except AttributeError: + continue + + if param.initializer is not None: + # in this case, parameter gets updated to its function's final value + try: + initializer_value = parameters[self._model_spec_id_parameters][param.initializer] + except KeyError: + initializer_value = metadata[MODEL_SPEC_ID_METADATA]['initializer'] + + metadata[MODEL_SPEC_ID_METADATA]['function_stateful_params'][name] = { + 'id': name, + 'default_initial_value': initializer_value, + 'value': parse_valid_identifier(self.name) + } + stateful_params.add(name) + + # stateful parameters cannot show up as args or they will not be + # treated statefully in mdf + for sp in stateful_params: + del parameters[self._model_spec_id_parameters][sp] + + model = mdf.Function( + id=parse_valid_identifier(self.name), + **parameters, + **metadata, + ) + + try: + model.value = self.as_expression() + except AttributeError: + if self._model_spec_generic_type_name is not NotImplemented: + typ = self._model_spec_generic_type_name + else: + try: + typ = self.custom_function.__name__ + except AttributeError: + typ = type(self).__name__.lower() + + if typ not in mdf_functions.mdf_functions: + warnings.warn(f'{typ} is not an MDF standard function, this is likely to produce an incompatible model.') + + model.function = {typ: parameters[self._model_spec_id_parameters]} + + return model + # ***************************************** EXAMPLE FUNCTION ******************************************************* PROPENSITY = "PROPENSITY" diff --git a/psyneulink/core/components/functions/nonstateful/combinationfunctions.py b/psyneulink/core/components/functions/nonstateful/combinationfunctions.py index 3556e2b054c..e91fd02a118 100644 --- a/psyneulink/core/components/functions/nonstateful/combinationfunctions.py +++ b/psyneulink/core/components/functions/nonstateful/combinationfunctions.py @@ -42,7 +42,7 @@ ADDITIVE_PARAM, ARRANGEMENT, COMBINATION_FUNCTION_TYPE, COMBINE_MEANS_FUNCTION, CONCATENATE_FUNCTION, \ DEFAULT_VARIABLE, EXPONENTS, LINEAR_COMBINATION_FUNCTION, MULTIPLICATIVE_PARAM, OFFSET, OPERATION, \ PREDICTION_ERROR_DELTA_FUNCTION, PRODUCT, REARRANGE_FUNCTION, REDUCE_FUNCTION, SCALE, SUM, WEIGHTS, \ - PREFERENCE_SET_NAME + PREFERENCE_SET_NAME, VARIABLE from psyneulink.core.globals.utilities import convert_to_np_array, is_numeric, np_array_less_than_2d, parameter_spec from psyneulink.core.globals.context import ContextFlags from psyneulink.core.globals.parameters import Parameter @@ -179,6 +179,12 @@ class Parameters(CombinationFunction.Parameters): Attributes ---------- + changes_shape + see `changes_shape ` + + :default value: True + :type: bool + offset see `offset ` @@ -193,6 +199,7 @@ class Parameters(CombinationFunction.Parameters): """ scale = Parameter(1.0, modulable=True, aliases=[MULTIPLICATIVE_PARAM]) offset = Parameter(0.0, modulable=True, aliases=[ADDITIVE_PARAM]) + changes_shape = Parameter(True, stateful=False, loggable=False, pnl_internal=True) @tc.typecheck def __init__(self, @@ -679,6 +686,12 @@ class Parameters(CombinationFunction.Parameters): :default value: None :type: + changes_shape + see `changes_shape ` + + :default value: True + :type: bool + offset see `offset ` @@ -708,6 +721,7 @@ class Parameters(CombinationFunction.Parameters): operation = SUM scale = Parameter(1.0, modulable=True, aliases=[MULTIPLICATIVE_PARAM]) offset = Parameter(0.0, modulable=True, aliases=[ADDITIVE_PARAM]) + changes_shape = Parameter(True, stateful=False, loggable=False, pnl_internal=True) @tc.typecheck def __init__(self, @@ -880,7 +894,7 @@ def _gen_llvm_combine(self, builder, index, ctx, vi, vo, params): else: assert False, "Unknown operation: {}".format(operation) - val_p = builder.alloca(val.type) + val_p = builder.alloca(val.type, name="reduced_result") builder.store(val, val_p) pow_f = ctx.get_builtin("pow", [ctx.float_ty]) @@ -1178,7 +1192,7 @@ def __init__(self, ) def _validate_variable(self, variable, context=None): - """Insure that all items of list or np.ndarray in variable are of the same length + """Insure that all items of list or np.array in variable are of the same length Args: variable: @@ -1414,7 +1428,7 @@ def _gen_llvm_combine(self, builder, index, ctx, vi, vo, params): else: assert False, "Unknown operation: {}".format(operation) - val_p = builder.alloca(val.type) + val_p = builder.alloca(val.type, name="combined_result") builder.store(val, val_p) pow_f = ctx.get_builtin("pow", [ctx.float_ty]) diff --git a/psyneulink/core/components/functions/nonstateful/distributionfunctions.py b/psyneulink/core/components/functions/nonstateful/distributionfunctions.py index aa6e6ef9ba1..91b255b14d4 100644 --- a/psyneulink/core/components/functions/nonstateful/distributionfunctions.py +++ b/psyneulink/core/components/functions/nonstateful/distributionfunctions.py @@ -30,7 +30,7 @@ from psyneulink.core import llvm as pnlvm from psyneulink.core.components.functions.function import ( DEFAULT_SEED, Function_Base, FunctionError, - _random_state_getter, _seed_setter, + _random_state_getter, _seed_setter, _noise_setter ) from psyneulink.core.globals.keywords import \ ADDITIVE_PARAM, DIST_FUNCTION_TYPE, BETA, DIST_MEAN, DIST_SHAPE, DRIFT_DIFFUSION_ANALYTICAL_FUNCTION, \ @@ -43,7 +43,7 @@ __all__ = [ 'DistributionFunction', 'DRIFT_RATE', 'DRIFT_RATE_VARIABILITY', 'DriftDiffusionAnalytical', 'ExponentialDist', - 'GammaDist', 'NON_DECISION_TIME', 'NormalDist', 'STARTING_POINT', 'STARTING_POINT_VARIABILITY', + 'GammaDist', 'NON_DECISION_TIME', 'NormalDist', 'STARTING_VALUE', 'STARTING_VALUE_VARIABILITY', 'THRESHOLD_VARIABILITY', 'UniformDist', 'UniformToNormalDist', 'WaldDist', ] @@ -51,6 +51,11 @@ class DistributionFunction(Function_Base): componentType = DIST_FUNCTION_TYPE + def as_mdf_model(self): + model = super().as_mdf_model() + self._set_mdf_arg(model, 'shape', self.defaults.variable.shape) + return model + class NormalDist(DistributionFunction): """ @@ -124,6 +129,7 @@ class NormalDist(DistributionFunction): """ componentName = NORMAL_DIST_FUNCTION + _model_spec_generic_type_name = 'onnx::RandomNormal' class Parameters(DistributionFunction.Parameters): """ @@ -149,7 +155,7 @@ class Parameters(DistributionFunction.Parameters): :type: ``numpy.random.RandomState`` """ mean = Parameter(0.0, modulable=True, aliases=[ADDITIVE_PARAM]) - standard_deviation = Parameter(1.0, modulable=True, aliases=[MULTIPLICATIVE_PARAM]) + standard_deviation = Parameter(1.0, modulable=True, aliases=[MULTIPLICATIVE_PARAM], mdf_name='scale') random_state = Parameter(None, loggable=False, getter=_random_state_getter, dependencies='seed') seed = Parameter(DEFAULT_SEED, modulable=True, fallback_default=True, setter=_seed_setter) @@ -557,6 +563,7 @@ class UniformDist(DistributionFunction): """ componentName = UNIFORM_DIST_FUNCTION + _model_spec_generic_type_name = 'onnx::RandomUniform' class Parameters(DistributionFunction.Parameters): """ @@ -916,16 +923,16 @@ def _function(self, DRIFT_RATE = 'drift_rate' DRIFT_RATE_VARIABILITY = 'DDM_DriftRateVariability' THRESHOLD_VARIABILITY = 'DDM_ThresholdRateVariability' -STARTING_POINT = 'starting_point' -STARTING_POINT_VARIABILITY = "DDM_StartingPointVariability" -NON_DECISION_TIME = 't0' +STARTING_VALUE = 'starting_value' +STARTING_VALUE_VARIABILITY = "DDM_StartingPointVariability" +NON_DECISION_TIME = 'non_decision_time' def _DriftDiffusionAnalytical_bias_getter(owning_component=None, context=None): - starting_point = owning_component.parameters.starting_point._get(context) + starting_value = owning_component.parameters.starting_value._get(context) threshold = owning_component.parameters.threshold._get(context) try: - return (starting_point + threshold) / (2 * threshold) + return (starting_value + threshold) / (2 * threshold) except TypeError: return None @@ -937,8 +944,8 @@ class DriftDiffusionAnalytical(DistributionFunction): # ----------------------- default_variable=None, \ drift_rate=1.0, \ threshold=1.0, \ - starting_point=0.0, \ - t0=0.2 \ + starting_value=0.0, \ + non_decision_time=0.2 \ noise=0.5, \ params=None, \ owner=None, \ @@ -953,7 +960,7 @@ class DriftDiffusionAnalytical(DistributionFunction): # ----------------------- *Modulatory Parameters:* | *MULTIPLICATIVE_PARAM:* `drift_rate ` - | *ADDITIVE_PARAM:* `starting_point ` + | *ADDITIVE_PARAM:* `starting_value ` | Arguments @@ -965,24 +972,24 @@ class DriftDiffusionAnalytical(DistributionFunction): # ----------------------- drift_rate : float, list or 1d array : default 1.0 specifies the drift_rate of the drift diffusion process. If it is a list or array, - it must be the same length as `default_variable `. + it must be the same length as `default_variable `. threshold : float, list or 1d array : default 1.0 specifies the threshold (boundary) of the drift diffusion process. If it is a list or array, - it must be the same length as `default_variable `. + it must be the same length as `default_variable `. - starting_point : float, list or 1d array : default 1.0 + starting_value : float, list or 1d array : default 1.0 specifies the initial value of the decision variable for the drift diffusion process. If it is a list or - array, it must be the same length as `default_variable `. + array, it must be the same length as `default_variable `. noise : float, list or 1d array : default 0.0 specifies the noise term (corresponding to the diffusion component) of the drift diffusion process. If it is a float, it must be a number from 0 to 1. If it is a list or array, it must be the same length as - `default_variable ` and all elements must be floats from 0 to 1. + `default_variable ` and all elements must be floats from 0 to 1. - t0 : float, list or 1d array : default 0.2 + non_decision_time : float, list or 1d array : default 0.2 specifies the non-decision time for solution. If it is a float, it must be a number from 0 to 1. If it is a - list or array, it must be the same length as `default_variable ` and all + list or array, it must be the same length as `default_variable ` and all elements must be floats from 0 to 1. params : Dict[param keyword: param value] : default None @@ -1017,19 +1024,19 @@ class DriftDiffusionAnalytical(DistributionFunction): # ----------------------- determines the threshold (boundary) of the drift diffusion process (i.e., at which the integration process is assumed to terminate). - starting_point : float or 1d array + starting_value : float or 1d array determines the initial value of the decision variable for the drift diffusion process. noise : float or 1d array determines the diffusion component of the drift diffusion process (used to specify the variance of a Gaussian random process). - t0 : float or 1d array + non_decision_time : float or 1d array determines the assumed non-decision time to determine the response time returned by the solution. bias : float or 1d array normalized starting point: - (`starting_point ` + `threshold `) / + (`starting_value ` + `threshold `) / (2 * `threshold `) owner : Component @@ -1079,14 +1086,14 @@ class Parameters(DistributionFunction.Parameters): :default value: 0.5 :type: ``float`` - starting_point - see `starting_point ` + starting_value + see `starting_value ` :default value: 0.0 :type: ``float`` - t0 - see `t0 ` + non_decision_time + see `non_decision_time ` :default value: 0.2 :type: ``float`` @@ -1098,10 +1105,10 @@ class Parameters(DistributionFunction.Parameters): :type: ``float`` """ drift_rate = Parameter(1.0, modulable=True, aliases=[MULTIPLICATIVE_PARAM]) - starting_point = Parameter(0.0, modulable=True, aliases=[ADDITIVE_PARAM]) + starting_value = Parameter(0.0, modulable=True, aliases=[ADDITIVE_PARAM]) threshold = Parameter(1.0, modulable=True) - noise = Parameter(0.5, modulable=True) - t0 = Parameter(.200, modulable=True) + noise = Parameter(0.5, modulable=True, setter=_noise_setter) + non_decision_time = Parameter(.200, modulable=True) bias = Parameter(0.5, read_only=True, getter=_DriftDiffusionAnalytical_bias_getter) # this is read only because conversion is disabled for this function # this occurs in other places as well @@ -1117,10 +1124,10 @@ class Parameters(DistributionFunction.Parameters): def __init__(self, default_variable=None, drift_rate: tc.optional(parameter_spec) = None, - starting_point: tc.optional(parameter_spec) = None, + starting_value: tc.optional(parameter_spec) = None, threshold: tc.optional(parameter_spec) = None, noise: tc.optional(parameter_spec) = None, - t0: tc.optional(parameter_spec) = None, + non_decision_time: tc.optional(parameter_spec) = None, params=None, owner=None, prefs: tc.optional(is_pref_set) = None, @@ -1131,10 +1138,10 @@ def __init__(self, super().__init__( default_variable=default_variable, drift_rate=drift_rate, - starting_point=starting_point, + starting_value=starting_value, threshold=threshold, noise=noise, - t0=t0, + non_decision_time=non_decision_time, params=params, owner=owner, prefs=prefs, @@ -1212,17 +1219,17 @@ def _function(self, stimulus_drift_rate = float(variable) drift_rate = attentional_drift_rate * stimulus_drift_rate threshold = self._get_current_parameter_value(THRESHOLD, context) - starting_point = float(self._get_current_parameter_value(STARTING_POINT, context)) + starting_value = float(self._get_current_parameter_value(STARTING_VALUE, context)) noise = float(self._get_current_parameter_value(NOISE, context)) - t0 = float(self._get_current_parameter_value(NON_DECISION_TIME, context)) + non_decision_time = float(self._get_current_parameter_value(NON_DECISION_TIME, context)) # drift_rate = float(self.drift_rate) * float(variable) # threshold = float(self.threshold) - # starting_point = float(self.starting_point) + # starting_value = float(self.starting_value) # noise = float(self.noise) - # t0 = float(self.t0) + # non_decision_time = float(self.non_decision_time) - bias = (starting_point + threshold) / (2 * threshold) + bias = (starting_value + threshold) / (2 * threshold) # Prevents div by 0 issue below: if bias <= 0: @@ -1235,7 +1242,7 @@ def _function(self, # back to absolute bias in order to apply limit bias_abs = bias * 2 * threshold - threshold # use expression for limit a->0 from Srivastava et al. 2016 - rt = t0 + (threshold ** 2 - bias_abs ** 2) / (noise ** 2) + rt = non_decision_time + (threshold ** 2 - bias_abs ** 2) / (noise ** 2) er = (threshold - bias_abs) / (2 * threshold) else: drift_rate_normed = np.abs(drift_rate) @@ -1289,7 +1296,7 @@ def _function(self, if rt < 0: rt = 0 - rt = rt + t0 + rt = rt + non_decision_time except FloatingPointError: # Per Mike Shvartsman: @@ -1298,7 +1305,7 @@ def _function(self, # depending on the sign of the drift, and so decision time goes to a point mass on z/a – x0, and # generates a "RuntimeWarning: overflow encountered in exp" er = 0 - rt = ztilde / atilde - x0tilde + t0 + rt = ztilde / atilde - x0tilde + non_decision_time # This last line makes it report back in terms of a fixed reference point # (i.e., closer to 1 always means higher p(upper boundary)) @@ -1307,14 +1314,14 @@ def _function(self, er = (is_neg_drift == 1) * (1 - er) + (is_neg_drift == 0) * (er) # Compute moments (mean, variance, skew) of condiational response time distributions - moments = DriftDiffusionAnalytical._compute_conditional_rt_moments(drift_rate, noise, threshold, bias, t0) + moments = DriftDiffusionAnalytical._compute_conditional_rt_moments(drift_rate, noise, threshold, bias, non_decision_time) return rt, er, \ moments['mean_rt_plus'], moments['var_rt_plus'], moments['skew_rt_plus'], \ moments['mean_rt_minus'], moments['var_rt_minus'], moments['skew_rt_minus'] @staticmethod - def _compute_conditional_rt_moments(drift_rate, noise, threshold, starting_point, t0): + def _compute_conditional_rt_moments(drift_rate, noise, threshold, starting_value, non_decision_time): """ This is a helper function for computing the conditional decison time moments for the DDM. It is based completely off of Matlab\\DDMFunctions\\ddm_metrics_cond_Mat.m. @@ -1322,8 +1329,8 @@ def _compute_conditional_rt_moments(drift_rate, noise, threshold, starting_point :param drift_rate: The drift rate of the DDM :param noise: The diffusion rate. :param threshold: The symmetric threshold of the DDM - :param starting_point: The initial condition. - :param t0: The non decision time. + :param starting_value: The initial condition. + :param non_decision_time: The non decision time. :return: A dictionary containing the following key value pairs: mean_rt_plus: The mean RT of positive responses. mean_rt_minus: The mean RT of negative responses. @@ -1334,12 +1341,12 @@ def _compute_conditional_rt_moments(drift_rate, noise, threshold, starting_point """ # transform starting point to be centered at 0 - starting_point = (starting_point - 0.5) * 2.0 * threshold + starting_value = (starting_value - 0.5) * 2.0 * threshold if abs(drift_rate) < 0.01: drift_rate = 0.01 - X = drift_rate * starting_point / noise**2 + X = drift_rate * starting_value / noise**2 Z = drift_rate * threshold / noise**2 X = max(-100, min(100, X)) @@ -1384,8 +1391,8 @@ def csch(x): moments['skew_rt_minus'] /= moments['var_rt_minus']**1.5 # Add the non-decision time to the mean RTs - moments['mean_rt_plus'] += t0 - moments['mean_rt_minus'] += t0 + moments['mean_rt_plus'] += non_decision_time + moments['mean_rt_minus'] += non_decision_time return moments @@ -1398,9 +1405,9 @@ def load_scalar_param(name): attentional_drift_rate = load_scalar_param(DRIFT_RATE) threshold = load_scalar_param(THRESHOLD) - starting_point = load_scalar_param(STARTING_POINT) + starting_value = load_scalar_param(STARTING_VALUE) noise = load_scalar_param(NOISE) - t0 = load_scalar_param(NON_DECISION_TIME) + non_decision_time = load_scalar_param(NON_DECISION_TIME) noise_sqr = builder.fmul(noise, noise) @@ -1411,7 +1418,7 @@ def load_scalar_param(name): drift_rate = builder.fmul(attentional_drift_rate, stimulus_drift_rate) threshold_2 = builder.fmul(threshold, threshold.type(2)) - bias = builder.fadd(starting_point, threshold) + bias = builder.fadd(starting_value, threshold) bias = builder.fdiv(bias, threshold_2) bias = pnlvm.helpers.fclamp(builder, bias, 1e-8, 1 - 1e-8) @@ -1441,7 +1448,7 @@ def _get_arg_out_ptr(idx): threshold_sqr = builder.fmul(threshold, threshold) rt = builder.fsub(threshold_sqr, bias_abs_sqr) rt = builder.fdiv(rt, noise_sqr) - rt = builder.fadd(t0, rt) + rt = builder.fadd(non_decision_time, rt) builder.store(rt, rt_ptr) er = builder.fsub(threshold, bias_abs) @@ -1521,7 +1528,7 @@ def _get_arg_out_ptr(idx): rt = builder.fdiv(rt_tmp1, rt_tmp2) rt = builder.fsub(rt, x0tilde) rt = builder.fadd(rt_tmp0, rt) - rt = builder.fadd(rt, t0) + rt = builder.fadd(rt, non_decision_time) builder.store(rt, rt_ptr) # Calculate moments @@ -1533,16 +1540,16 @@ def _get_arg_out_ptr(idx): skew_rt_minus_ptr = _get_arg_out_ptr(7) # Transform starting point to be centered at 0 - starting_point = bias - starting_point = builder.fsub(starting_point, starting_point.type(0.5)) - starting_point = builder.fmul(starting_point, starting_point.type(2)) - starting_point = builder.fmul(starting_point, threshold) + starting_value = bias + starting_value = builder.fsub(starting_value, starting_value.type(0.5)) + starting_value = builder.fmul(starting_value, starting_value.type(2)) + starting_value = builder.fmul(starting_value, threshold) drift_rate_limit = abs_drift_rate.type(0.01) small_drift = builder.fcmp_ordered("<", abs_drift_rate, drift_rate_limit) drift_rate = builder.select(small_drift, drift_rate_limit, drift_rate) - X = builder.fmul(drift_rate, starting_point) + X = builder.fmul(drift_rate, starting_value) X = builder.fdiv(X, noise_sqr) X = pnlvm.helpers.fclamp(builder, X, X.type(-100), X.type(100)) @@ -1570,14 +1577,14 @@ def _get_arg_out_ptr(idx): mrtp_tmp = builder.fsub(Z2_coth_Z2, ZpX_coth_ZpX) m_rt_p = builder.fdiv(noise_sqr, drift_rate_sqr) m_rt_p = builder.fmul(m_rt_p, mrtp_tmp) - m_rt_p = builder.fadd(m_rt_p, t0) + m_rt_p = builder.fadd(m_rt_p, non_decision_time) builder.store(m_rt_p, mean_rt_plus_ptr) # Mean minus mrtm_tmp = builder.fsub(Z2_coth_Z2, ZmX_coth_ZmX) m_rt_m = builder.fdiv(noise_sqr, drift_rate_sqr) m_rt_m = builder.fmul(m_rt_m, mrtm_tmp) - m_rt_m = builder.fadd(m_rt_m, t0) + m_rt_m = builder.fadd(m_rt_m, non_decision_time) builder.store(m_rt_m, mean_rt_minus_ptr) # Variance helpers diff --git a/psyneulink/core/components/functions/nonstateful/optimizationfunctions.py b/psyneulink/core/components/functions/nonstateful/optimizationfunctions.py index 15bae402ebb..1f70a337c64 100644 --- a/psyneulink/core/components/functions/nonstateful/optimizationfunctions.py +++ b/psyneulink/core/components/functions/nonstateful/optimizationfunctions.py @@ -383,10 +383,10 @@ class Parameters(Function_Base.Parameters): :default value: lambda x, y, z: True :type: ``types.FunctionType`` """ - variable = Parameter(np.array([0, 0, 0]), read_only=True, pnl_internal=True, constructor_argument='default_variable') + variable = Parameter(np.array([0.0, 0.0, 0.0]), read_only=True, pnl_internal=True, constructor_argument='default_variable') - objective_function = Parameter(lambda x: 0, stateful=False, loggable=False) - aggregation_function = Parameter(lambda x,n: sum(x) / n, stateful=False, loggable=False) + objective_function = Parameter(lambda x: 0.0, stateful=False, loggable=False) + aggregation_function = Parameter(lambda x: np.mean(x, axis=1), stateful=False, loggable=False) search_function = Parameter(lambda x: x, stateful=False, loggable=False) search_termination_function = Parameter(lambda x, y, z: True, stateful=False, loggable=False) search_space = Parameter([SampleIterator([0])], stateful=False, loggable=False) @@ -439,6 +439,10 @@ def __init__( self._unspecified_args.append(SEARCH_TERMINATION_FUNCTION) self.randomization_dimension = randomization_dimension + if self.search_space: + # Make randomization dimension of search_space last for standardization of treatment + self.search_space.append(self.search_space.pop(self.search_space.index(self.randomization_dimension))) + self.randomization_dimension = len(self.search_space) super().__init__( default_variable=default_variable, @@ -588,24 +592,99 @@ def _function(self, second list contains the values returned by `objective_function ` for all the samples in the order they were evaluated; otherwise it is empty. """ + + raise NotImplementedError("OptimizationFunction._function is not implemented and " + "should be overridden by subclasses.") + + def _evaluate(self, variable=None, context=None, params=None): + """ + Evaluate all the sample in a `search_space ` with the agent_rep. The + evaluation is done either serially (_sequential_evaluate) or in parallel (_grid_evaluate). This method should + be invoked by subclasses in their `_function` method to evaluate the samples before searching for the optimal + value. + + Returns + ------- + + optimal sample, optimal value, saved_samples, saved_values : array, array, list, list + first array contains sample that yields the optimal value of the `optimization process + `, and second array contains the value of `objective_function + ` for that sample. If `save_samples + ` is `True`, first list contains all the values sampled in the order + they were evaluated; otherwise it is empty. If `save_values ` is `True`, + second list contains the values returned by `objective_function ` + for all the samples in the order they were evaluated; otherwise it is empty. + + """ + if self._unspecified_args and self.initialization_status == ContextFlags.INITIALIZED: warnings.warn("The following arg(s) were not specified for {}: {} -- using default(s)". format(self.name, ', '.join(self._unspecified_args))) assert all([not getattr(self.parameters, x)._user_specified for x in self._unspecified_args]) self._unspecified_args = [] - current_sample = self._check_args(variable=variable, context=context, params=params) - + # Get initial sample in case it is needed by _search_space_evaluate (e.g., for gradient initialization) + initial_sample = self._check_args(variable=variable, context=context, params=params) try: - current_value = self.owner.objective_mechanism.parameters.value._get(context) + initial_value = self.owner.objective_mechanism.parameters.value._get(context) except AttributeError: - current_value = 0 + initial_value = 0 + + # EVALUATE ALL SAMPLES IN SEARCH SPACE + # Evaluate all estimates of all samples in search_space + + # If execution mode is not Python and search_space is static, use parallelized evaluation: + if (self.owner and self.owner.parameters.comp_execution_mode._get(context) != 'Python' and + all(isinstance(sample_iterator.start, Number) and isinstance(sample_iterator.stop, Number) + for sample_iterator in self.search_space)): + # FIX: NEED TO FIX THIS ONCE _grid_evaluate RETURNS all_samples + all_samples = [] + all_values, num_evals = self._grid_evaluate(self.owner, context) + last_sample = last_value = None + # Otherwise, default sequential sampling + else: + last_sample, last_value, all_samples, all_values = self._sequential_evaluate(initial_sample, + initial_value, + context) + + # If aggregation_function is specified and there is a randomization dimension specified + # in the control signals; use the aggregation function aggregate over the samples generated + # for different randomized values of the control signal + if self.aggregation_function and \ + self.parameters.randomization_dimension._get(context) and \ + self.parameters.num_estimates._get(context) is not None: + + # Reshape all the values we encountered to group those that correspond to the same parameter values + # can be aggregated. + all_values = np.reshape(all_values, (-1, self.parameters.num_estimates._get(context))) + + # Since we are aggregating over the randomized value of the control allocation, we also need to drop the + # randomized dimension from the samples. That is, we don't want to return num_estimates samples for each + # control allocation. This line below just grabs the first one (seed == 1) for each control allocation. + all_samples = all_samples[:, all_samples[1, :] == all_samples[1, 0]] + + # If num_estimates is not None, then one of the control signals is modulating the random seed. We will + # groupby this signal and average the values to compute the estimated value. + aggregated_values = np.atleast_2d(self.aggregation_function(all_values)) + returned_values = aggregated_values + + else: + returned_values = all_values - samples = [] - values = [] + # Return list of unique samples and aggregated values over them + return last_sample, last_value, all_samples, returned_values + + def _sequential_evaluate(self, initial_sample, initial_value, context): + """Sequentially evaluate every sample in search_space. + Return arrays with all samples evaluated, and array with all values of those samples. + """ # Initialize variables used in while loop iteration = 0 + current_sample = initial_sample + current_value = initial_value + all_samples = [] + all_values = [] # Set up progress bar _show_progress = False @@ -620,8 +699,10 @@ def _function(self, print("\n{} executing optimization process (one {} for each {}of {} samples): ". format(self.owner.name, repr(_progress_bar_char), _progress_bar_rate_str, _search_space_size)) _progress_bar_count = 0 - # Iterate optimization process + # Iterate over samples until search_termination_function returns True + evaluated_samples = [] + estimated_values = [] while not call_with_pruned_args(self.search_termination_function, current_sample, current_value, iteration, @@ -632,45 +713,45 @@ def _function(self, print(_progress_bar_char, end='', flush=True) _progress_bar_count +=1 - # Get next sample of sample - new_sample = call_with_pruned_args(self.search_function, current_sample, iteration, context=context) - - # Generate num_estimates of sample, then apply aggregation_function and return result - estimates = [] - num_estimates = self.num_estimates - for i in range(num_estimates): - estimate = call_with_pruned_args(self.objective_function, new_sample, context=context) - estimates.append(estimate) - new_value = self.aggregation_function(estimates, num_estimates) if self.aggregation_function else estimates - self._report_value(new_value) + # Get next sample + current_sample = call_with_pruned_args(self.search_function, current_sample, iteration, context=context) + # Get value of sample + current_value = call_with_pruned_args(self.objective_function, current_sample, context=context) + + # Convert the sample and values to numpy arrays even if they are scalars + current_sample = np.atleast_1d(current_sample) + current_value = np.atleast_1d(current_value) + + evaluated_samples.append(current_sample) + estimated_values.append(current_value) + + self._report_value(current_value) iteration += 1 max_iterations = self.parameters.max_iterations._get(context) if max_iterations and iteration > max_iterations: - warnings.warn("{} failed to converge after {} iterations".format(self.name, max_iterations)) + warnings.warn(f"{self.name} of {self.owner.name} exceeded max iterations {max_iterations}.") break - current_sample = new_sample - current_value = new_value - - if self.parameters.save_samples._get(context): - samples.append(new_sample) - self.parameters.saved_samples._set(samples, context) - if self.parameters.save_values._get(context): - values.append(current_value) - self.parameters.saved_values._set(values, context) + # Change randomization for next sample if specified (relies on randomization being last dimension) + if self.owner and self.owner.parameters.same_seed_for_all_allocations is False: + self.search_space[self.parameters.randomization_dimension._get(context)].start += 1 + self.search_space[self.parameters.randomization_dimension._get(context)].stop += 1 - return new_sample, new_value, samples, values - - def _report_value(self, new_value): - """Report value returned by `objective_function ` for sample.""" - pass + if self.parameters.save_samples._get(context): + self.parameters.saved_samples._set(all_samples, context) + if self.parameters.save_values._get(context): + self.parameters.saved_values._set(all_values, context) + # Convert evaluated_samples and estimated_values to numpy arrays, stack along the last dimension + estimated_values = np.stack(estimated_values, axis=-1) + evaluated_samples = np.stack(evaluated_samples, axis=-1) -class GridBasedOptimizationFunction(OptimizationFunction): - """Implement helper method for parallelizing instantiation for evaluating samples from search space.""" + # FIX: 11/3/21: ??MODIFY TO RETURN SAME AS _grid_evaluate + # return current_sample, current_value, evaluated_samples, estimated_values + return current_sample, current_value, evaluated_samples, estimated_values def _grid_evaluate(self, ocm, context): - + """Helper method for evaluation of a grid of samples from search space via LLVM backends.""" assert ocm is ocm.agent_rep.controller # Compiled evaluate expects the same variable as mech function variable = [input_port.parameters.value.get(context) for input_port in ocm.input_ports] @@ -686,8 +767,20 @@ def _grid_evaluate(self, ocm, context): else: assert False, f"Unknown execution mode for {ocm.name}: {execution_mode}." + # FIX: RETURN SHOULD BE: outcomes, all_samples (THEN FIX CALL IN _function) return outcomes, num_evals + def _report_value(self, new_value): + """Report value returned by `objective_function ` for sample.""" + pass + + @property + def num_estimates(self): + if self.randomization_dimension is None: + return 1 + else: + return self.search_space[self.randomization_dimension].num + ASCENT = 'ascent' DESCENT = 'descent' @@ -759,7 +852,7 @@ class GradientOptimization(OptimizationFunction): :math:`\\frac{d(objective\\_function(variable))}{d(variable)}`. If the **gradient_function* argument of the constructor is not specified, then an attempt is made to use `Autograd's `_ `grad ` method to generate `gradient_function `. If that fails, - an erorr occurs. The **search_space** argument can be used to specify lower and/or upper bounds for each dimension + an error occurs. The **search_space** argument can be used to specify lower and/or upper bounds for each dimension of the sample; if the gradient causes a value of the sample to exceed a bound along a dimenson, the value of the bound is used for that dimension, unless/until the gradient shifts and causes it to return back within the bound. @@ -973,7 +1066,7 @@ class Parameters(OptimizationFunction.Parameters): # these should be removed and use switched to .get_previous() previous_variable = Parameter([[0], [0]], read_only=True, pnl_internal=True, constructor_argument='default_variable') - previous_value = Parameter([[0], [0]], read_only=True, initializer='initializer', pnl_internal=True) + previous_value = Parameter([[0], [0]], read_only=True, initializer='initializer') gradient_function = Parameter(None, stateful=False, loggable=False) step_size = Parameter(1.0, modulable=True) @@ -1164,7 +1257,7 @@ def _function(self, evaluated; otherwise it is empty. """ - optimal_sample, optimal_value, all_samples, all_values = super()._function(variable=variable, + optimal_sample, optimal_value, all_samples, all_values = super()._evaluate(variable=variable, context=context, params=params, ) @@ -1232,7 +1325,7 @@ def _convergence_condition(self, variable, value, iteration, context=None): MINIMIZE = 'minimize' -class GridSearch(GridBasedOptimizationFunction): +class GridSearch(OptimizationFunction): """ GridSearch( \ default_variable=None, \ @@ -1383,8 +1476,8 @@ class Parameters(OptimizationFunction.Parameters): :type: ``bool`` """ grid = Parameter(None) - save_samples = Parameter(True, pnl_internal=True) - save_values = Parameter(True, pnl_internal=True) + save_samples = Parameter(False, pnl_internal=True) + save_values = Parameter(False, pnl_internal=True) random_state = Parameter(None, loggable=False, getter=_random_state_getter, dependencies='seed') seed = Parameter(DEFAULT_SEED, modulable=True, fallback_default=True, setter=_seed_setter) select_randomly_from_optimal_values = Parameter(False) @@ -1399,6 +1492,7 @@ def __init__(self, objective_function:tc.optional(is_function_type)=None, search_space=None, direction:tc.optional(tc.enum(MAXIMIZE, MINIMIZE))=None, + save_samples:tc.optional(bool)=None, save_values:tc.optional(bool)=None, # tolerance=0., select_randomly_from_optimal_values=None, @@ -1427,7 +1521,7 @@ def __init__(self, search_termination_function=search_termination_function, search_space=search_space, select_randomly_from_optimal_values=select_randomly_from_optimal_values, - save_samples=True, + save_samples=save_samples, save_values=save_values, seed=seed, direction=direction, @@ -1623,7 +1717,7 @@ def _gen_llvm_select_min_function(self, *, ctx:pnlvm.LLVMBuilderContext, tags:fr with b_true: search_space = pnlvm.helpers.get_param_ptr(builder, self, params, self.parameters.search_space.name) - pnlvm.helpers.create_allocation(b, min_sample_ptr, search_space, min_idx) + pnlvm.helpers.create_sample(b, min_sample_ptr, search_space, min_idx) with b_false: sample_ptr = builder.gep(samples_ptr, [min_idx]) builder.store(b.load(sample_ptr), min_sample_ptr) @@ -1849,9 +1943,9 @@ def _function(self, return_optimal_sample = max_value_of_max_tuples[0] return_optimal_value = max_value_of_max_tuples[1] - if self._return_samples: + if self.parameters.save_samples._get(context): return_all_samples = np.concatenate(Comm.allgather(samples), axis=0) - if self._return_values: + if self.parameters.save_values._get(context): return_all_values = np.concatenate(Comm.allgather(values), axis=0) else: @@ -1859,7 +1953,6 @@ def _function(self, "PROGRAM ERROR: bad value for {} arg of {}: {}, {}". \ format(repr(DIRECTION), self.name, direction) - ocm = self._get_optimized_controller() # Compiled version @@ -1880,14 +1973,23 @@ def _function(self, # Python version else: - last_sample, last_value, all_samples, all_values = super()._function( + + # Evaluate objective_function for each sample + last_sample, last_value, all_samples, all_values = self._evaluate( variable=variable, context=context, params=params, ) + if all_values.size != all_samples.shape[-1]: + raise ValueError(f"OptimizationFunction Error: {self}._evaluate returned mismatched sizes for " + f"samples and values. This is likely due to a bug in the implementation of " + f"{self.__class__} _evaluate method.") + + # Find the optimal value(s) optimal_value_count = 1 - value_sample_pairs = zip(all_values, all_samples) + value_sample_pairs = zip(all_values.flatten(), + [all_samples[:,i] for i in range(all_samples.shape[1])]) value_optimal, sample_optimal = next(value_sample_pairs) select_randomly = self.parameters.select_randomly_from_optimal_values._get(context) @@ -1909,9 +2011,11 @@ def _function(self, value_optimal, sample_optimal = value, sample optimal_value_count = 1 - if self._return_samples: + if self.parameters.save_samples._get(context): + self.parameters.saved_samples._set(all_samples, context) return_all_samples = all_samples - if self._return_values: + if self.parameters.save_values._get(context): + self.parameters.saved_values._set(all_values, context) return_all_values = all_values return sample_optimal, value_optimal, return_all_samples, return_all_values diff --git a/psyneulink/core/components/functions/nonstateful/selectionfunctions.py b/psyneulink/core/components/functions/nonstateful/selectionfunctions.py index 56d95e09ac2..aff4dc5764f 100644 --- a/psyneulink/core/components/functions/nonstateful/selectionfunctions.py +++ b/psyneulink/core/components/functions/nonstateful/selectionfunctions.py @@ -288,7 +288,7 @@ def _gen_llvm_function_body(self, ctx, builder, params, state, arg_in, arg_out, cmp_op = ">=" cmp_prev = b1.call(fabs, [prev]) cmp_curr = b1.call(fabs, [current]) - val = current + val = b1.call(fabs, [current]) elif self.mode == MAX_INDICATOR: cmp_op = ">=" cmp_prev = prev diff --git a/psyneulink/core/components/functions/nonstateful/transferfunctions.py b/psyneulink/core/components/functions/nonstateful/transferfunctions.py index e04beea9d19..5bce6445bba 100644 --- a/psyneulink/core/components/functions/nonstateful/transferfunctions.py +++ b/psyneulink/core/components/functions/nonstateful/transferfunctions.py @@ -761,15 +761,19 @@ class Logistic(TransferFunction): # ------------------------------------------- `function ` returns logistic transform of `variable `: .. math:: - \\frac{1}{1 + e^{ - gain ( variable + bias - x_{0}) + offset}} + scale * \\frac{1}{1 + e^{ - gain ( variable + bias - x_{0} ) + offset}} - (this is an offset and scaled version of the `Tanh`, which is centered on origin). + (this is a vertically offset and scaled version of `Tanh`, which is centered on origin). + + .. _Logistic_Note: .. note:: - The **bias** and **x_0** arguments are identical, apart from opposite signs: **bias** is included to - accomodate the convention in the machine learning community; **x_0** is included to match the `standard + The **bias** and **x_0** arguments are identical, apart from having opposite signs: **bias** is included to + accommodate the convention in the machine learning community; **x_0** is included to match the `standard form of the Logistic Function `_ (in which **gain** - corresponds to the *k* parameter and **scale** corresponds to the *L* parameter). + corresponds to the *k* parameter and **scale** corresponds to the *L* parameter); **offset** implements a + form of bias that is not modulated by gain (i.e., it produces an offset of the function along the horizontal + axis). `derivative ` returns the derivative of the Logistic using its **output**: @@ -783,22 +787,26 @@ class Logistic(TransferFunction): # ------------------------------------------- specifies a template for the value to be transformed. gain : float : default 1.0 - specifies value by which to multiply `variable ` before logistic transformation + specifies value by which to multiply each element of `variable ` after it is adjusted by + `bias ` and/or `x_0 `, but before adjustment by `offset ` and + logistic transformation (see `note ` above). bias : float : default 0.0 - specifies value to add to each element of `variable ` before applying `gain ` - and before logistic transformation. This argument is identical to x_0, with the opposite sign. + specifies value to add to each element of `variable ` before applying `gain `; + this argument has an effect identical to x_0, but with the opposite sign (see `note ` above). x_0 : float : default 0.0 - specifies value to subtract from each element of `variable ` before applying `gain ` - and before logistic transformation. This argument is identical to bias, with the opposite sign. + specifies value to add to each element of `variable ` before applying `gain `; + this argument has an effect identical to bias, but with the opposite sign (see `note ` above). offset : float : default 0.0 - specifies value to add to each element of `variable ` after applying `gain ` - but before logistic transformation. + specifies value to add to each element of `variable ` after adjusting by `bias + ` and/or `x_0 ` and applying `gain `, but before logistic + transformation (see `note ` above). scale : float : default 0.0 - specifies value by which each element is multiplied after applying the logistic transformation. + specifies value by which to multiply each element of `variable ` after all other parameters + and logistic transformation have been applied (see `note ` above). params : Dict[param keyword: param value] : default None a `parameter dictionary ` that specifies the parameters for the @@ -820,26 +828,33 @@ class Logistic(TransferFunction): # ------------------------------------------- variable : number or array contains value to be transformed. - gain : float : default 1.0 - value by which each element of `variable ` is multiplied before applying the - `bias ` (if it is specified). + gain : float + value by which to multiply each element of `variable ` after it is adjusted by `bias + ` and/or `x_0 `, but before adjustment by `offset ` and + logistic transformation (see `note ` above). - bias : float : default 0.0 - value added to each element of `variable ` before applying the `gain ` - (if it is specified). This attribute is identical to x_0, with the opposite sign. + bias : float + value to add to each element of `variable ` before applying `gain `; + this argument has an effect identical to x_0, but with the opposite sign (see `note ` above). - x_0 : float : default 0.0 - value subtracted from each element of `variable ` before applying the `gain ` - (if it is specified). This attribute is identical to bias, with the opposite sign. + x_0 : float + value to add to each element of `variable ` before applying `gain `; + this argument has an effect identical to bias, but with the opposite sign (see `note ` above). - offset : float : default 0.0 - value to added to each element of `variable ` after applying `gain ` - but before logistic transformation. + offset : float + value to add to each element of `variable ` after adjusting by `bias ` + and/or `x_0 ` and applying `gain `, but before logistic transformation + (see `note ` above). - scale : float : default 0.0 - value by which each element is multiplied after applying the Logistic transform. + scale : float + value by which to multiply each element of `variable ` after all other parameters and + logistic transformation have been applied (see `note ` above). bounds : (0,1) + COMMENT: + the lower and upper limits of the result which, in the case of the `Logistic`, is determined by the function + itself. + COMMENT owner : Component `component ` to which the Function has been assigned. @@ -1042,6 +1057,20 @@ def derivative(self, input=None, output=None, context=None): return gain * scale * output * (1 - output) + def as_mdf_model(self): + model = super().as_mdf_model() + + # x_0 is included in bias in MDF logistic + self._set_mdf_arg(model, 'bias', model.args['bias'] - model.args['x_0']) + self._set_mdf_arg(model, 'x_0', 0) + + if model.args['scale'] != 1.0: + warnings.warn( + f"Scale (set to {model.args['scale']} is not a supported" + ' parameter for MDF logistic' + ) + return model + # ********************************************************************************************************************** # Tanh @@ -2252,7 +2281,7 @@ def _gen_llvm_transfer(self, builder, index, ctx, vi, vo, params, state, *, tags scale = pnlvm.helpers.load_extract_scalar_array_one(builder, scale_ptr) offset = pnlvm.helpers.load_extract_scalar_array_one(builder, offset_ptr) - rvalp = builder.alloca(ptri.type.pointee) + rvalp = builder.alloca(ptri.type.pointee, name="random_out") rand_state_ptr = ctx.get_random_state_ptr(builder, self, state, params) normal_f = ctx.get_normal_dist_function_by_state(rand_state_ptr) builder.call(normal_f, [rand_state_ptr, rvalp]) @@ -2870,6 +2899,8 @@ class LinearMatrix(TransferFunction): # --------------------------------------- DEFAULT_FILLER_VALUE = 0 + _model_spec_generic_type_name = 'onnx::MatMul' + class Parameters(TransferFunction.Parameters): """ Attributes @@ -2881,7 +2912,8 @@ class Parameters(TransferFunction.Parameters): :default value: None :type: """ - matrix = Parameter(None, modulable=True) + variable = Parameter(np.array([0]), read_only=True, pnl_internal=True, constructor_argument='default_variable', mdf_name='A') + matrix = Parameter(None, modulable=True, mdf_name='B') bounds = None # def is_matrix_spec(m): diff --git a/psyneulink/core/components/functions/stateful/integratorfunctions.py b/psyneulink/core/components/functions/stateful/integratorfunctions.py index 80144c6897e..dd344d3b9f0 100644 --- a/psyneulink/core/components/functions/stateful/integratorfunctions.py +++ b/psyneulink/core/components/functions/stateful/integratorfunctions.py @@ -36,7 +36,7 @@ from psyneulink.core.components.functions.nonstateful.distributionfunctions import DistributionFunction from psyneulink.core.components.functions.function import ( DEFAULT_SEED, FunctionError, _random_state_getter, - _seed_setter, + _seed_setter, _noise_setter ) from psyneulink.core.components.functions.stateful.statefulfunction import StatefulFunction from psyneulink.core.globals.context import ContextFlags, handle_external_context @@ -47,7 +47,7 @@ INCREMENT, INITIALIZER, INPUT_PORTS, INTEGRATOR_FUNCTION, INTEGRATOR_FUNCTION_TYPE, \ INTERACTIVE_ACTIVATION_INTEGRATOR_FUNCTION, LEAKY_COMPETING_INTEGRATOR_FUNCTION, \ MULTIPLICATIVE_PARAM, NOISE, OFFSET, OPERATION, ORNSTEIN_UHLENBECK_INTEGRATOR_FUNCTION, OUTPUT_PORTS, PRODUCT, \ - RATE, REST, SIMPLE_INTEGRATOR_FUNCTION, SUM, TIME_STEP_SIZE, THRESHOLD, VARIABLE + RATE, REST, SIMPLE_INTEGRATOR_FUNCTION, SUM, TIME_STEP_SIZE, THRESHOLD, VARIABLE, MODEL_SPEC_ID_MDF_VARIABLE from psyneulink.core.globals.parameters import Parameter from psyneulink.core.globals.preferences.basepreferenceset import is_pref_set from psyneulink.core.globals.utilities import parameter_spec, all_within_range, \ @@ -214,8 +214,10 @@ class Parameters(StatefulFunction.Parameters): :type: ``float`` """ rate = Parameter(1.0, modulable=True, function_arg=True) - noise = Parameter(0.0, modulable=True, function_arg=True) - previous_value = Parameter(np.array([0]), initializer='initializer', pnl_internal=True) + noise = Parameter( + 0.0, modulable=True, function_arg=True, setter=_noise_setter + ) + previous_value = Parameter(np.array([0]), initializer='initializer') initializer = Parameter(np.array([0]), pnl_internal=True) @tc.typecheck @@ -460,8 +462,7 @@ class AccumulatorIntegrator(IntegratorFunction): # ---------------------------- initializer : float, list or 1d array : default 0.0 specifies starting value(s) for integration. If it is a list or array, it must be the same length as - `default_variable ` (see `initializer - ` for details). + `variable ` (see `initializer ` for details). params : Dict[param keyword: param value] : default None a `parameter dictionary ` that specifies the parameters for the @@ -664,6 +665,33 @@ def _function(self, return self.convert_output_type(value) + def _gen_llvm_integrate(self, builder, index, ctx, vi, vo, params, state): + rate = self._gen_llvm_load_param(ctx, builder, params, index, RATE) + increment = self._gen_llvm_load_param(ctx, builder, params, index, INCREMENT) + noise = self._gen_llvm_load_param(ctx, builder, params, index, NOISE, + state=state) + + # Get the only context member -- previous value + prev_ptr = pnlvm.helpers.get_state_ptr(builder, self, state, "previous_value") + # Get rid of 2d array. When part of a Mechanism the input, + # (and output, and context) are 2d arrays. + prev_ptr = pnlvm.helpers.unwrap_2d_array(builder, prev_ptr) + assert len(prev_ptr.type.pointee) == len(vi.type.pointee) + + prev_ptr = builder.gep(prev_ptr, [ctx.int32_ty(0), index]) + prev_val = builder.load(prev_ptr) + + res = builder.fmul(prev_val, rate) + res = builder.fadd(res, noise) + res = builder.fadd(res, increment) + + vo_ptr = builder.gep(vo, [ctx.int32_ty(0), index]) + builder.store(res, vo_ptr) + builder.store(res, prev_ptr) + + def as_expression(self): + return 'previous_value * rate + noise + increment' + class SimpleIntegrator(IntegratorFunction): # ------------------------------------------------------------------------- """ @@ -715,8 +743,7 @@ class SimpleIntegrator(IntegratorFunction): # --------------------------------- initializer : float, list or 1d array : default 0.0 specifies starting value(s) for integration; if it is a list or array, it must be the same length as - `default_variable ` (see `initializer ` - for details). + `variable ` (see `initializer ` for details). params : Dict[param keyword: param value] : default None a `parameter dictionary ` that specifies the parameters for the @@ -893,6 +920,10 @@ def _gen_llvm_integrate(self, builder, index, ctx, vi, vo, params, state): builder.store(res, vo_ptr) builder.store(res, prev_ptr) + def as_expression(self): + return f'previous_value + ({MODEL_SPEC_ID_MDF_VARIABLE} * rate) + noise + offset' + + class AdaptiveIntegrator(IntegratorFunction): # ----------------------------------------------------------------------- """ AdaptiveIntegrator( \ @@ -944,8 +975,7 @@ class AdaptiveIntegrator(IntegratorFunction): # ------------------------------- initializer : float, list or 1d array : default 0.0 specifies starting value(s) for integration. If it is a list or array, it must be the same length as - `default_variable ` (see `initializer ` - for details). + `variable ` (see `initializer ` for details). params : Dict[param keyword: param value] : default None a `parameter dictionary ` that specifies the parameters for the @@ -1213,6 +1243,9 @@ def _function(self, return self.convert_output_type(adjusted_value, variable) # MODIFIED 6/21/19 END + def as_expression(self): + return f'(1 - rate) * previous_value + rate * {MODEL_SPEC_ID_MDF_VARIABLE} + noise + offset' + S_MINUS_L = 's-l' L_MINUS_S = 'l-s' @@ -1854,9 +1887,8 @@ class InteractiveActivationIntegrator(IntegratorFunction): # ------------------ ` (see `noise ` for details). initializer : float, list or 1d array : default 0.0 - specifies starting value(s) for integration. If it is a list or array, it must be the same length as - `default_variable ` - (see `initializer ` for details). + specifies starting value(s) for integration. If it is a list or array, it must be the same length as `variable + ` (see `initializer ` for details). params : Dict[param keyword: param value] : default None a `parameter dictionary ` that specifies the parameters for the @@ -2125,9 +2157,9 @@ class DriftDiffusionIntegrator(IntegratorFunction): # ------------------------- rate=1.0, \ noise=0.0, \ offset= 0.0, \ - starting_point=0.0, \ + non_decision_time=0.0, \ threshold=1.0 \ - time_step_size=1.0, \ + time_step_size=0.01, \ initializer=None, \ params=None, \ owner=None, \ @@ -2182,10 +2214,10 @@ class DriftDiffusionIntegrator(IntegratorFunction): # ------------------------- if it is a list or array, it must be the same length as `variable ` (see `offset ` for details). - starting_point : float, list or 1d array: default 0.0 + starting_value : float, list or 1d array: default 0.0 specifies the starting value for the integration process; if it is a list or array, it must be the - same length as `variable ` (see `starting_point - ` for details). + same length as `variable ` (see `starting_value + ` for details). threshold : float : default 0.0 specifies the threshold (boundaries) of the drift diffusion process -- i.e., at which the @@ -2196,9 +2228,8 @@ class DriftDiffusionIntegrator(IntegratorFunction): # ------------------------- ` for details. initializer : float, list or 1d array : default 0.0 - specifies starting value(s) for integration. If it is a list or array, it must be the same length as - `default_variable ` (see `initializer ` - for details). + specifies starting value(s) for integration. If it is a list or array, it must be the same length as `variable + ` (see `initializer ` for details). params : Dict[param keyword: param value] : default None a `parameter dictionary ` that specifies the parameters for the @@ -2248,13 +2279,17 @@ class DriftDiffusionIntegrator(IntegratorFunction): # ------------------------- the corresponding elements of the integral (i.e., Hadamard addition). Serves as *ADDITIVE_PARAM* for `modulation ` of `function `. - starting_point : float or 1d array + starting_value : float or 1d array determines the starting value for the integration process; if it is a list or array, it must be the same length as `variable `. If `variable ` - is an array and starting_point is a float, starting_point is used for each element of the integral; if - starting_point is a list or array, each of its elements is used as the starting point for each element of the + is an array and starting_value is a float, starting_value is used for each element of the integral; if + starting_value is a list or array, each of its elements is used as the starting point for each element of the integral. + non_decision_time : float : default 0.0 + specifies the starting time of the model and is used to compute `previous_time + ` + threshold : float determines the boundaries of the drift diffusion process: the integration process can be scheduled to terminate when the result of `function ` equals or exceeds either the @@ -2342,8 +2377,8 @@ class Parameters(IntegratorFunction.Parameters): :type: :read only: True - starting_point - see `starting_point ` + non_decision_time + see `non_decision_time ` :default value: 0.0 :type: ``float`` @@ -2362,10 +2397,11 @@ class Parameters(IntegratorFunction.Parameters): """ rate = Parameter(1.0, modulable=True, aliases=[MULTIPLICATIVE_PARAM]) offset = Parameter(0.0, modulable=True, aliases=[ADDITIVE_PARAM]) - starting_point = 0.0 + initializer = Parameter(np.array([0]), aliases=['starting_value']) + non_decision_time = Parameter(0.0, modulable=True) threshold = Parameter(100.0, modulable=True) time_step_size = Parameter(1.0, modulable=True) - previous_time = Parameter(None, initializer='starting_point', pnl_internal=True) + previous_time = Parameter(None, initializer='non_decision_time', pnl_internal=True) random_state = Parameter(None, loggable=False, getter=_random_state_getter, dependencies='seed') seed = Parameter(DEFAULT_SEED, modulable=True, fallback_default=True, setter=_seed_setter) enable_output_type_conversion = Parameter( @@ -2383,27 +2419,30 @@ def _parse_initializer(self, initializer): return initializer @tc.typecheck - def __init__(self, - default_variable=None, - rate: tc.optional(parameter_spec) = None, - noise=None, - offset: tc.optional(parameter_spec) = None, - starting_point=None, - threshold=None, - time_step_size=None, - initializer=None, - seed=None, - params: tc.optional(tc.optional(dict)) = None, - owner=None, - prefs: tc.optional(is_pref_set) = None): + def __init__( + self, + default_variable=None, + rate: tc.optional(parameter_spec) = None, + noise=None, + offset: tc.optional(parameter_spec) = None, + starting_value=None, + non_decision_time=None, + threshold=None, + time_step_size=None, + seed=None, + params: tc.optional(tc.optional(dict)) = None, + owner=None, + prefs: tc.optional(is_pref_set) = None, + **kwargs + ): # Assign here as default, for use in initialization of function super().__init__( default_variable=default_variable, rate=rate, time_step_size=time_step_size, - starting_point=starting_point, - initializer=initializer, + starting_value=starting_value, + non_decision_time=non_decision_time, threshold=threshold, noise=noise, offset=offset, @@ -2411,6 +2450,7 @@ def __init__(self, params=params, owner=owner, prefs=prefs, + **kwargs ) def _validate_noise(self, noise): @@ -2459,7 +2499,7 @@ def _function(self, random_draw = np.array([random_state.normal() for _ in list(variable)]) value = previous_value + rate * variable * time_step_size \ - + np.sqrt(time_step_size * noise) * random_draw + + noise * np.sqrt(time_step_size) * random_draw adjusted_value = np.clip(value + offset, -threshold, threshold) @@ -2486,7 +2526,7 @@ def _gen_llvm_integrate(self, builder, index, ctx, vi, vo, params, state): time_step_size = self._gen_llvm_load_param(ctx, builder, params, index, TIME_STEP_SIZE) random_state = ctx.get_random_state_ptr(builder, self, state, params) - rand_val_ptr = builder.alloca(ctx.float_ty) + rand_val_ptr = builder.alloca(ctx.float_ty, name="random_out") rand_f = ctx.get_normal_dist_function_by_state(random_state) builder.call(rand_f, [random_state, rand_val_ptr]) rand_val = builder.load(rand_val_ptr) @@ -2511,10 +2551,9 @@ def _gen_llvm_integrate(self, builder, index, ctx, vi, vo, params, state): val = builder.fmul(val, time_step_size) val = builder.fadd(val, prev_val) - factor = builder.fmul(noise, time_step_size) sqrt_f = ctx.get_builtin("sqrt", [ctx.float_ty]) - factor = builder.call(sqrt_f, [factor]) - + factor = builder.call(sqrt_f, [time_step_size]) + factor = builder.fmul(noise, factor) factor = builder.fmul(rand_val, factor) val = builder.fadd(val, factor) @@ -3160,7 +3199,7 @@ class OrnsteinUhlenbeckIntegrator(IntegratorFunction): # ---------------------- decay=1.0, \ noise=0.0, \ offset= 0.0, \ - starting_point=0.0, \ + non_decision_time=0.0, \ time_step_size=1.0, \ initializer=0.0, \ params=None, \ @@ -3220,7 +3259,7 @@ class OrnsteinUhlenbeckIntegrator(IntegratorFunction): # ---------------------- if it is a list or array, it must be the same length as `variable ` (see `offset ` for details) - starting_point : float : default 0.0 + non_decision_time : float : default 0.0 specifies the starting time of the model and is used to compute `previous_time ` @@ -3229,9 +3268,8 @@ class OrnsteinUhlenbeckIntegrator(IntegratorFunction): # ---------------------- ` for details. initializer : float, list or 1d array : default 0.0 - specifies starting value(s) for integration. If it is a list or array, it must be the same length as - `default_variable ` (see `initializer ` - for details). + specifies starting value(s) for integration. If it is a list or array, it must be the same length as `variable + ` (see `initializer ` for details). params : Dict[param keyword: param value] : default None a `parameter dictionary ` that specifies the parameters for the @@ -3292,7 +3330,7 @@ class OrnsteinUhlenbeckIntegrator(IntegratorFunction): # ---------------------- the corresponding elements of the integral (i.e., Hadamard addition). Serves as *ADDITIVE_PARAM* for `modulation ` of `function `. - starting_point : float + non_decision_time : float determines the start time of the integration process. time_step_size : float @@ -3371,8 +3409,8 @@ class Parameters(IntegratorFunction.Parameters): :default value: 1.0 :type: ``float`` - starting_point - see `starting_point ` + non_decision_time + see `non_decision_time ` :default value: 0.0 :type: ``float`` @@ -3388,8 +3426,9 @@ class Parameters(IntegratorFunction.Parameters): decay = Parameter(1.0, modulable=True) offset = Parameter(0.0, modulable=True, aliases=[ADDITIVE_PARAM]) time_step_size = Parameter(1.0, modulable=True) - starting_point = 0.0 - previous_time = Parameter(0.0, initializer='starting_point', pnl_internal=True) + initializer = Parameter(np.array([0]), aliases=['starting_value']) + non_decision_time = Parameter(0.0, modulable=True) + previous_time = Parameter(0.0, initializer='non_decision_time', pnl_internal=True) random_state = Parameter(None, loggable=False, getter=_random_state_getter, dependencies='seed') seed = Parameter(DEFAULT_SEED, modulable=True, fallback_default=True, setter=_seed_setter) enable_output_type_conversion = Parameter( @@ -3401,19 +3440,22 @@ class Parameters(IntegratorFunction.Parameters): ) @tc.typecheck - def __init__(self, - default_variable=None, - rate: tc.optional(parameter_spec) = None, - decay=None, - noise=None, - offset: tc.optional(parameter_spec) = None, - starting_point=None, - time_step_size=None, - initializer=None, - params: tc.optional(tc.optional(dict)) = None, - seed=None, - owner=None, - prefs: tc.optional(is_pref_set) = None): + def __init__( + self, + default_variable=None, + rate: tc.optional(parameter_spec) = None, + decay=None, + noise=None, + offset: tc.optional(parameter_spec) = None, + non_decision_time=None, + time_step_size=None, + starting_value=None, + params: tc.optional(tc.optional(dict)) = None, + seed=None, + owner=None, + prefs: tc.optional(is_pref_set) = None, + **kwargs + ): super().__init__( default_variable=default_variable, @@ -3421,15 +3463,16 @@ def __init__(self, decay=decay, noise=noise, offset=offset, - starting_point=starting_point, + non_decision_time=non_decision_time, time_step_size=time_step_size, - initializer=initializer, - previous_value=initializer, - previous_time=starting_point, + starting_value=starting_value, + previous_value=starting_value, + previous_time=non_decision_time, params=params, seed=seed, owner=owner, prefs=prefs, + **kwargs ) def _validate_noise(self, noise): @@ -3585,9 +3628,8 @@ class LeakyCompetingIntegrator(IntegratorFunction): # ------------------------- ` for details. initializer : float, list or 1d array : default 0.0 - specifies starting value(s) for integration. If it is a list or array, it must be the same length as - `default_variable ` (see `initializer - ` for details). + specifies starting value(s) for integration. If it is a list or array, it must be the same length as `variable + ` (see `initializer ` for details). params : Dict[param keyword: param value] : default None a `parameter dictionary ` that specifies the parameters for the @@ -3804,6 +3846,9 @@ def _gen_llvm_integrate(self, builder, index, ctx, vi, vo, params, state): builder.store(ret, out_ptr) builder.store(ret, prev_ptr) + def as_expression(self): + return f'previous_value + (-rate * previous_value + {MODEL_SPEC_ID_MDF_VARIABLE}) * time_step_size + noise * (time_step_size ** 0.5)' + class FitzHughNagumoIntegrator(IntegratorFunction): # ---------------------------------------------------------------------------- """ @@ -4011,11 +4056,11 @@ class FitzHughNagumoIntegrator(IntegratorFunction): # ------------------------- initial_w : float, list or 1d array : default 0.0 specifies starting value for integration of dw/dt. If it is a list or array, it must be the same length as - `default_variable ` + `variable `. initial_v : float, list or 1d array : default 0.0 specifies starting value for integration of dv/dt. If it is a list or array, it must be the same length as - `default_variable ` + `variable ` time_step_size : float : default 0.1 specifies the time step size of numerical integration @@ -4105,11 +4150,11 @@ class FitzHughNagumoIntegrator(IntegratorFunction): # ------------------------- initial_w : float, list or 1d array : default 0.0 specifies starting value for integration of dw/dt. If it is a list or array, it must be the same length as - `default_variable ` + `variable ` initial_v : float, list or 1d array : default 0.0 specifies starting value for integration of dv/dt. If it is a list or array, it must be the same length as - `default_variable ` + `variable ` time_step_size : float : default 0.1 specifies the time step size of numerical integration @@ -4359,7 +4404,7 @@ class Parameters(IntegratorFunction.Parameters): # this should be removed because it's unused, but this will # require a larger refactoring on previous_value/value - previous_value = Parameter(None, initializer='initializer', pnl_internal=True) + previous_value = Parameter(None, initializer='initializer') enable_output_type_conversion = Parameter( False, diff --git a/psyneulink/core/components/functions/stateful/memoryfunctions.py b/psyneulink/core/components/functions/stateful/memoryfunctions.py index 910e49545ba..abade02079c 100644 --- a/psyneulink/core/components/functions/stateful/memoryfunctions.py +++ b/psyneulink/core/components/functions/stateful/memoryfunctions.py @@ -35,7 +35,7 @@ from psyneulink.core import llvm as pnlvm from psyneulink.core.components.functions.function import ( - DEFAULT_SEED, FunctionError, _random_state_getter, _seed_setter, is_function_type, EPSILON, + DEFAULT_SEED, FunctionError, _random_state_getter, _seed_setter, is_function_type, EPSILON, _noise_setter ) from psyneulink.core.components.functions.nonstateful.objectivefunctions import Distance from psyneulink.core.components.functions.nonstateful.selectionfunctions import OneHot @@ -44,7 +44,7 @@ from psyneulink.core.globals.keywords import \ ADDITIVE_PARAM, BUFFER_FUNCTION, MEMORY_FUNCTION, COSINE, \ ContentAddressableMemory_FUNCTION, DictionaryMemory_FUNCTION, \ - MIN_INDICATOR, MULTIPLICATIVE_PARAM, NEWEST, NOISE, OLDEST, OVERWRITE, RATE, RANDOM + MIN_INDICATOR, MULTIPLICATIVE_PARAM, NEWEST, NOISE, OLDEST, OVERWRITE, RATE, RANDOM, VARIABLE from psyneulink.core.globals.parameters import Parameter from psyneulink.core.globals.preferences.basepreferenceset import is_pref_set from psyneulink.core.globals.utilities import \ @@ -187,6 +187,12 @@ class Parameters(StatefulFunction.Parameters): :default value: numpy.array([], dtype=float64) :type: ``numpy.ndarray`` + changes_shape + see `changes_shape ` + + :default value: True + :type: bool + noise see `noise ` @@ -201,9 +207,12 @@ class Parameters(StatefulFunction.Parameters): """ variable = Parameter([], pnl_internal=True, constructor_argument='default_variable') rate = Parameter(1.0, modulable=True, aliases=[MULTIPLICATIVE_PARAM]) - noise = Parameter(0.0, modulable=True, aliases=[ADDITIVE_PARAM]) + noise = Parameter( + 0.0, modulable=True, aliases=[ADDITIVE_PARAM], setter=_noise_setter + ) history = None initializer = Parameter(np.array([]), pnl_internal=True) + changes_shape = Parameter(True, stateful=False, loggable=False, pnl_internal=True) @tc.typecheck @@ -1079,7 +1088,7 @@ class Parameters(StatefulFunction.Parameters): """ variable = Parameter([[0],[0]], pnl_internal=True, constructor_argument='default_variable') initializer = Parameter(None, pnl_internal=True) - previous_value = Parameter(None, initializer='initializer', pnl_internal=True) + previous_value = Parameter(None, initializer='initializer') retrieval_prob = Parameter(1.0, modulable=True) storage_prob = Parameter(1.0, modulable=True, aliases=[MULTIPLICATIVE_PARAM]) # FIX: MAKE THESE ATTRIBUTES RATHER THAN PARAMETERS: @@ -1091,7 +1100,9 @@ class Parameters(StatefulFunction.Parameters): duplicate_threshold = Parameter(EPSILON, stateful=False, modulable=True) equidistant_entries_select = Parameter(RANDOM) rate = Parameter(1.0, modulable=True) - noise = Parameter(0.0, modulable=True, aliases=[ADDITIVE_PARAM]) + noise = Parameter( + 0.0, modulable=True, aliases=[ADDITIVE_PARAM], setter=_noise_setter + ) max_entries = Parameter(1000) random_state = Parameter(None, loggable=False, getter=_random_state_getter, dependencies='seed') seed = Parameter(DEFAULT_SEED, modulable=True, fallback_default=True, setter=_seed_setter) @@ -2151,7 +2162,9 @@ class Parameters(StatefulFunction.Parameters): duplicate_keys = Parameter(False) equidistant_keys_select = Parameter(RANDOM) rate = Parameter(1.0, modulable=True) - noise = Parameter(0.0, modulable=True, aliases=[ADDITIVE_PARAM]) + noise = Parameter( + 0.0, modulable=True, aliases=[ADDITIVE_PARAM], setter=_noise_setter + ) max_entries = Parameter(1000) random_state = Parameter(None, loggable=False, getter=_random_state_getter, dependencies='seed') seed = Parameter(DEFAULT_SEED, modulable=True, fallback_default=True, setter=_seed_setter) diff --git a/psyneulink/core/components/functions/stateful/statefulfunction.py b/psyneulink/core/components/functions/stateful/statefulfunction.py index e8b8213e619..1a365aca476 100644 --- a/psyneulink/core/components/functions/stateful/statefulfunction.py +++ b/psyneulink/core/components/functions/stateful/statefulfunction.py @@ -27,7 +27,7 @@ from psyneulink.core import llvm as pnlvm from psyneulink.core.components.component import DefaultsFlexibility, _has_initializers_setter, ComponentsMeta from psyneulink.core.components.functions.nonstateful.distributionfunctions import DistributionFunction -from psyneulink.core.components.functions.function import Function_Base, FunctionError +from psyneulink.core.components.functions.function import Function_Base, FunctionError, _noise_setter from psyneulink.core.globals.context import handle_external_context from psyneulink.core.globals.keywords import STATEFUL_FUNCTION_TYPE, STATEFUL_FUNCTION, NOISE, RATE from psyneulink.core.globals.parameters import Parameter @@ -146,6 +146,12 @@ class StatefulFunction(Function_Base): # -------------------------------------- output, or a list or array of either of these, then noise is simply an offset that remains the same across all executions. + .. note:: + A ParameterPort for noise will only be generated, and the + noise Parameter itself will only be stateful, if the value + of noise is entirely numeric (contains no functions) at the + time of Mechanism construction. + owner : Component `component ` to which the Function has been assigned. @@ -191,9 +197,9 @@ class Parameters(Function_Base.Parameters): :default value: 1.0 :type: ``float`` """ - noise = Parameter(0.0, modulable=True) + noise = Parameter(0.0, modulable=True, setter=_noise_setter) rate = Parameter(1.0, modulable=True) - previous_value = Parameter(np.array([0]), initializer='initializer', pnl_internal=True) + previous_value = Parameter(np.array([0]), initializer='initializer') initializer = Parameter(np.array([0]), pnl_internal=True) has_initializers = Parameter(True, setter=_has_initializers_setter, pnl_internal=True) diff --git a/psyneulink/core/components/functions/userdefinedfunction.py b/psyneulink/core/components/functions/userdefinedfunction.py index bb8b6ecc5b3..176eff725c7 100644 --- a/psyneulink/core/components/functions/userdefinedfunction.py +++ b/psyneulink/core/components/functions/userdefinedfunction.py @@ -11,7 +11,7 @@ import numpy as np import typecheck as tc -from inspect import signature, _empty, getsourcelines +from inspect import signature, _empty, getsourcelines, getsourcefile, getclosurevars import ast from psyneulink.core.components.functions.function import FunctionError, Function_Base @@ -20,7 +20,7 @@ SELF, USER_DEFINED_FUNCTION, USER_DEFINED_FUNCTION_TYPE from psyneulink.core.globals.parameters import Parameter from psyneulink.core.globals.preferences import is_pref_set -from psyneulink.core.globals.utilities import iscompatible +from psyneulink.core.globals.utilities import _is_module_class, iscompatible from psyneulink.core import llvm as pnlvm @@ -447,6 +447,7 @@ class Parameters(Function_Base.Parameters): None, stateful=False, loggable=False, + pnl_internal=True, ) @tc.typecheck @@ -659,27 +660,54 @@ def _function(self, variable, context=None, **kwargs): def _gen_llvm_function_body(self, ctx, builder, params, state, arg_in, arg_out, *, tags:frozenset): - srclines = getsourcelines(self.custom_function)[0] - # strip preceeding space characters - first_line = srclines[0] - prefix_len = len(first_line) - len(first_line.lstrip()) - formatted_src = ''.join(line[prefix_len:] for line in srclines) - func_ast = ast.parse(formatted_src) + # Check for global and nonlocal vars. we can't compile those. + closure_vars = getclosurevars(self.custom_function) + assert len(closure_vars.nonlocals) == 0, "Compiling functions with non-local variables is not supported!" - func_globals = self.custom_function.__globals__ - func_params = {param_id: pnlvm.helpers.get_param_ptr(builder, self, params, param_id) for param_id in self.llvm_param_ids} + srcfile = getsourcefile(self.custom_function) + first_line = getsourcelines(self.custom_function)[1] - udf_block = builder.append_basic_block(name="post_udf") - udf_builder = pnlvm.ir.IRBuilder(udf_block) + with open(srcfile) as f: + for node in ast.walk(ast.parse(f.read(), srcfile)): + if getattr(node, 'lineno', -1) == first_line and isinstance(node, (ast.FunctionDef, ast.Lambda)): + func_ast = node + break + func_ast = None - pnlvm.codegen.UserDefinedFunctionVisitor(ctx, builder, udf_builder, func_globals, func_params, arg_in, arg_out).visit(func_ast) - # After we're done with allocating variable stack space, jump to the code - builder.branch(udf_block) + assert func_ast is not None, "UDF function source code not found" - post_block = builder.append_basic_block(name="post_udf") - # If the function didn't use return as the last statement jump back to the outer block - if not udf_builder.block.is_terminated: - udf_builder.branch(post_block) + func_globals = closure_vars.globals + assert len(func_globals) == 0 or ( + len(func_globals) == 1 and np in func_globals.values()), \ + "Compiling functions with global variables is not supported! ({})".format(closure_vars.globals) + func_params = {param_id: pnlvm.helpers.get_param_ptr(builder, self, params, param_id) for param_id in self.llvm_param_ids} + pnlvm.codegen.UserDefinedFunctionVisitor(ctx, builder, func_globals, func_params, arg_in, arg_out).visit(func_ast) + + # The generic '_gen_llvm' will append another ret void to this block + post_block = builder.append_basic_block(name="post_udf") builder.position_at_start(post_block) return builder + + def as_mdf_model(self): + import math + import modeci_mdf.functions.standard + + model = super().as_mdf_model() + ext_function_str = None + + if self.custom_function in [ + func_dict['function'] + for name, func_dict + in modeci_mdf.functions.standard.mdf_functions.items() + ]: + ext_function_str = self.custom_function.__name__ + + if _is_module_class(self.custom_function, math): + ext_function_str = f'{self.custom_function.__module__}.{self.custom_function.__name__}' + + if ext_function_str is not None: + model.metadata['custom_function'] = ext_function_str + del model.metadata['type'] + + return model diff --git a/psyneulink/core/components/mechanisms/mechanism.py b/psyneulink/core/components/mechanisms/mechanism.py index b46b2b5a5dd..e174f9004e2 100644 --- a/psyneulink/core/components/mechanisms/mechanism.py +++ b/psyneulink/core/components/mechanisms/mechanism.py @@ -788,13 +788,13 @@ Several attributes are available for viewing the labels for the current value(s) of a Mechanism's InputPort(s) and OutputPort(s). - - The `label ` attribute of an InputPort or OutputPort returns the current label of - its value, if one exists, and its value otherwise. + - The `label ` attribute of an InputPort or OutputPort returns the current label of + its value, if one exists, and its numeric value otherwise. - - The `input_labels ` and `output_labels ` attributes of - Mechanisms return a list containing the labels corresponding to the value(s) of the InputPort(s) or - OutputPort(s) of the Mechanism, respectively. If the current value of a port does not have a corresponding - label, then its numeric value is used instead. + - The `labeled_input_values ` and `labeled_output_values + ` attributes of a Mechanism return lists containing the labels + corresponding to the value(s) of the InputPort(s) or OutputPort(s) of the Mechanism, respectively. If the + current value of a Port does not have a corresponding label, then its numeric value is reported instead. >>> output_labels_dict = {"red": [1, 0, 0], ... "green": [0, 1, 0], @@ -804,13 +804,13 @@ >>> C = pnl.Composition(pathways=[M]) >>> input_dictionary = {M: [[1, 0, 0]]} >>> results = C.run(inputs=input_dictionary) - >>> M.get_output_labels(C) + >>> M.labeled_output_values(C) ['red'] - >>> M.output_ports[0].get_label(C) + >>> M.output_ports[0].labeled_value(C) 'red' Labels may be used to visualize the input and outputs of Mechanisms in a Composition with the **show_structure** option -of the Composition's `show_graph`show_graph ` method with the keyword **LABELS**. +of the Composition's `show_graph`show_graph ` method with the keyword **LABELS**. >>> C.show_graph(show_mechanism_structure=pnl.LABELS) #doctest: +SKIP @@ -1098,22 +1098,23 @@ REMOVE_PORTS, PORT_SPEC, _parse_port_spec, PORT_SPECIFIC_PARAMS, PROJECTION_SPECIFIC_PARAMS from psyneulink.core.components.shellclasses import Mechanism, Projection, Port from psyneulink.core.globals.context import Context, ContextFlags, handle_external_context +from psyneulink.core.globals.json import _get_variable_parameter_name, _substitute_expression_args # TODO: remove unused keywords from psyneulink.core.globals.keywords import \ ADDITIVE_PARAM, EXECUTION_PHASE, EXPONENT, FUNCTION_PARAMS, \ INITIALIZING, INIT_EXECUTE_METHOD_ONLY, INIT_FUNCTION_METHOD_ONLY, INPUT, \ INPUT_LABELS_DICT, INPUT_PORT, INPUT_PORT_PARAMS, INPUT_PORTS, MECHANISM, MECHANISM_VALUE, \ - MECHANISM_COMPONENT_CATEGORY, MODEL_SPEC_ID_INPUT_PORTS, MODEL_SPEC_ID_OUTPUT_PORTS, \ - MULTIPLICATIVE_PARAM, \ + MECHANISM_COMPONENT_CATEGORY, \ + MULTIPLICATIVE_PARAM, EXECUTION_COUNT, \ NAME, OUTPUT, OUTPUT_LABELS_DICT, OUTPUT_PORT, OUTPUT_PORT_PARAMS, OUTPUT_PORTS, OWNER_EXECUTION_COUNT, OWNER_VALUE, \ PARAMETER_PORT, PARAMETER_PORT_PARAMS, PARAMETER_PORTS, PROJECTIONS, REFERENCE_VALUE, RESULT, \ - TARGET_LABELS_DICT, VALUE, VARIABLE, WEIGHT + TARGET_LABELS_DICT, VALUE, VARIABLE, WEIGHT, MODEL_SPEC_ID_MDF_VARIABLE, MODEL_SPEC_ID_INPUT_PORT_COMBINATION_FUNCTION from psyneulink.core.globals.parameters import Parameter from psyneulink.core.globals.preferences.preferenceset import PreferenceLevel from psyneulink.core.globals.registry import register_category, remove_instance_from_registry from psyneulink.core.globals.utilities import \ ContentAddressableList, append_type_to_name, convert_all_elements_to_np_array, convert_to_np_array, \ - iscompatible, kwCompatibilityNumeric, convert_to_list + iscompatible, kwCompatibilityNumeric, convert_to_list, parse_valid_identifier from psyneulink.core.scheduling.condition import Condition from psyneulink.core.scheduling.time import TimeScale @@ -1292,19 +1293,34 @@ class Mechanism_Base(Mechanism): in which each label (key) specifies a string associated with a value for the corresponding InputPort(s) of the Mechanism; see `Mechanism_Labels_Dicts` for additional details. - input_labels : list[str] - contains the labels corresponding to the value(s) of the InputPort(s) of the Mechanism. If the current value - of an InputPort does not have a corresponding label, then its numeric value is used instead. + labeled_input_values : list[str] + contains the labels corresponding to the current value(s) of the InputPort(s) of the Mechanism. If the + current value of an InputPort does not have a corresponding label, then its numeric value is used instead. external_input_ports : list[InputPort] list of the `input_ports ` for the Mechanism that are not designated as `internal_only `; these receive `inputs from a Composition ` if the Mechanism is one of its `INPUT` `Nodes `. + external_input_shape : List[List or 1d np.array] + list of the `input_shape `\\s of the Mechanism's external `input_ports + ` (i.e., excluding any `InputPorts ` designated as `internal_only + `), that shows the shape of the inputs expected for the Mechanism. Each item + corresponds to an expected `path_afferent Projection `, and its shape is + the expected `value ` of that `Projection`. + + external_input_variables : List[List or 1d np.array] + list of the `variable `\\s of the Mechanism's `external_input_ports + `. + external_input_values : List[List or 1d np.array] list of the `value `\\s of the Mechanism's `external_input_ports `. + default_external_inputs : List[1d np.array] + list of the `default_input `\\s of the Mechanism's `external_input_ports + `. + COMMENT: target_labels_dict : dict contains entries that are either label:value pairs, or sub-dictionaries containing label:value pairs, @@ -1363,15 +1379,15 @@ class Mechanism_Base(Mechanism): the `value ` of that OutputPort (and its corresponding item in the the Mechanism's `output_values ` attribute). + labeled_output_values : list + contains the labels corresponding to the current value(s) of the OutputPort(s) of the Mechanism. If the + current value of an OutputPort does not have a corresponding label, then its numeric value is used instead. + output_labels_dict : dict contains entries that are either label:value pairs, or sub-dictionaries containing label:value pairs, in which each label (key) specifies a string associated with a value for the OutputPort(s) of the Mechanism; see `Mechanism_Labels_Dicts` for additional details. - output_labels : list - contains the labels corresponding to the value(s) of the OutputPort(s) of the Mechanism. If the current value - of an OutputPort does not have a corresponding label, then its numeric value is used instead. - standard_output_ports : list[dict] list of the dictionary specifications for `StandardOutputPorts ` that can be assigned as `OutputPorts `; subclasses may extend this list to include additional ones. @@ -2390,11 +2406,10 @@ def execute(self, """ if self.initialization_status == ContextFlags.INITIALIZED: - context.string = "{} EXECUTING {}: {}".format(context.source.name,self.name, - ContextFlags._get_context_string( - context.flags, EXECUTION_PHASE)) + context.string = f"{context.source.name} EXECUTING {self.name}: " \ + f"{ContextFlags._get_context_string(context.flags, EXECUTION_PHASE)}." else: - context.string = "{} INITIALIZING {}".format(context.source.name, self.name) + context.string = f"{context.source.name} INITIALIZING {self.name}." if context.source is ContextFlags.COMMAND_LINE: self._initialize_from_context(context, override=False) @@ -2480,17 +2495,15 @@ def execute(self, # Executing or simulating Composition, so get input by updating input_ports if (input is None and (context.execution_phase is not ContextFlags.IDLE) - and (self.input_port.path_afferents != [])): + and any(p.path_afferents for p in self.input_ports)): variable = self._update_input_ports(runtime_port_params[INPUT_PORT_PARAMS], context) # Direct call to execute Mechanism with specified input, so assign input to Mechanism's input_ports else: if context.source & ContextFlags.COMMAND_LINE: context.execution_phase = ContextFlags.PROCESSING - if input is not None: input = convert_all_elements_to_np_array(input) - if input is None: input = self.defaults.variable # FIX: this input value is sent to input CIMs when compositions are nested @@ -2588,6 +2601,15 @@ def execute(self, return value def _get_variable_from_input(self, input, context=None): + """Return array of results from each InputPort function executed with corresponding input item as its variable + This is called when Mechanism is executed on its own (e.g., during init or from the command line). + It: + - bypasses call to Port._update(), thus ignoring any afferent Projections assigned to the Mechanism; + - assigns each item of **input** to variable of corresponding InputPort; + - executes function of each InputPort using corresponding item of input as its variable; + - returns array of values generated by execution of each InputPort function. + """ + input = convert_to_np_array(input, dimension=2) num_inputs = np.size(input, 0) num_input_ports = len(self.input_ports) @@ -2603,13 +2625,29 @@ def _get_variable_from_input(self, input, context=None): "its number of input_ports ({2})". format(num_inputs, self.name, num_input_ports )) for input_item, input_port in zip(input, self.input_ports): - if len(input_port.defaults.value) == len(input_item): - input_port.parameters.value._set(input_item, context) + if input_port.default_input_shape.size == np.array(input_item).size: + from psyneulink.core.compositions.composition import RunError + + # Assign input_item as input_port.variable + input_port.parameters.variable._set(np.atleast_2d(input_item), context) + + # Call input_port._execute with newly assigned variable and assign result to input_port.value + base_error_msg = f"Input to '{self.name}' ({input_item}) is incompatible " \ + f"with its corresponding {InputPort.__name__} ({input_port.full_name})" + try: + input_port.parameters.value._set( + input_port._execute(input_port.parameters.variable.get(context), context), + context) + except (RunError,TypeError) as error: + raise MechanismError(f"{base_error_msg}: '{error.args[0]}.'") + except: + raise MechanismError(f"{base_error_msg}.") else: raise MechanismError(f"Length ({len(input_item)}) of input ({input_item}) does not match " - f"required length ({len(input_port.defaults.variable)}) for input " + f"required length ({input_port.default_input_shape.size}) for input " f"to {InputPort.__name__} {repr(input_port.name)} of {self.name}.") + # Return values of input_ports for use as variable of Mechanism return convert_to_np_array(self.get_input_values(context)) def _update_input_ports(self, runtime_input_port_params=None, context=None): @@ -2822,7 +2860,11 @@ def _get_output_struct_type(self, ctx): def _get_input_struct_type(self, ctx): # Extract the non-modulation portion of InputPort input struct - input_type_list = [ctx.get_input_struct_type(port).elements[0] for port in self.input_ports] + def _get_data_part_of_input_struct(p): + struct_ty = ctx.get_input_struct_type(p) + return struct_ty.elements[0] if len(p.mod_afferents) > 0 else struct_ty + + input_type_list = [_get_data_part_of_input_struct(port) for port in self.input_ports] # Get modulatory inputs @@ -2849,7 +2891,7 @@ def _get_state_initializer(self, context): return (port_state_init, *mech_state_init) def _gen_llvm_ports(self, ctx, builder, ports, group, - get_output_ptr, fill_input_data, + get_output_ptr, get_input_data_ptr, mech_params, mech_state, mech_input): group_ports = getattr(self, group) ports_param = pnlvm.helpers.get_param_ptr(builder, self, mech_params, group) @@ -2859,14 +2901,35 @@ def _gen_llvm_ports(self, ctx, builder, ports, group, for i, port in enumerate(ports): p_function = ctx.import_llvm_function(port) - # Find output location + # Find input and output locations + builder, p_input_data = get_input_data_ptr(builder, i) builder, p_output = get_output_ptr(builder, i) - # Allocate the input structure (data + modulation) - p_input = builder.alloca(p_function.args[2].type.pointee) + if len(port.mod_afferents) == 0: + # There's no modulation so the only input is data + if p_input_data.type == p_function.args[2].type: + p_input = p_input_data + else: + assert port in self.output_ports + # Ports always take at least 2d input. However, parsing + # the function result can result in 1d structure or scalar + # Casting the pointer is LLVM way of adding dimensions + array_1d = pnlvm.ir.ArrayType(p_input_data.type.pointee, 1) + array_2d = pnlvm.ir.ArrayType(array_1d, 1) + assert array_1d == p_function.args[2].type.pointee or array_2d == p_function.args[2].type.pointee, \ + "{} vs. {}".format(p_function.args[2].type.pointee, p_input_data.type.pointee) + p_input = builder.bitcast(p_input_data, p_function.args[2].type) - # Copy input data to input structure - builder = fill_input_data(builder, p_input, i) + else: + # Port input structure is: (data, [modulations]), + p_input = builder.alloca(p_function.args[2].type.pointee, + name=group + "_port_" + str(i) + "_input") + # Fill in the data. + # FIXME: We can potentially hit the same dimensionality issue + # as above, but it's more difficult to manifest and + # not even new tests that modulate output ports hit it. + p_data = builder.gep(p_input, [ctx.int32_ty(0), ctx.int32_ty(0)]) + builder.store(builder.load(p_input_data), p_data) # Copy mod_afferent inputs for idx, p_mod in enumerate(port.mod_afferents): @@ -2903,58 +2966,51 @@ def _gen_llvm_input_ports(self, ctx, builder, else: ip_output_type = pnlvm.ir.LiteralStructType(ip_output_list) - ip_output = builder.alloca(ip_output_type) + ip_output = builder.alloca(ip_output_type, name="input_ports_out") def _get_output_ptr(b, i): ptr = b.gep(ip_output, [ctx.int32_ty(0), ctx.int32_ty(i)]) return b, ptr - def _fill_input(b, p_input, i): - ip_in = builder.gep(mech_input, [ctx.int32_ty(0), ctx.int32_ty(i)]) - # Input port inputs are {original parameter, [modulations]}, - # fill in the first one. - data_ptr = builder.gep(p_input, [ctx.int32_ty(0), ctx.int32_ty(0)]) - b.store(b.load(ip_in), data_ptr) - return b + def _get_input_data_ptr(b, i): + ptr = builder.gep(mech_input, [ctx.int32_ty(0), ctx.int32_ty(i)]) + return b, ptr builder = self._gen_llvm_ports(ctx, builder, self.input_ports, "input_ports", - _get_output_ptr, _fill_input, + _get_output_ptr, _get_input_data_ptr, mech_params, mech_state, mech_input) return ip_output, builder def _gen_llvm_param_ports_for_obj(self, obj, params_in, ctx, builder, mech_params, mech_state, mech_input): - # Allocate a shadow structure to overload user supplied parameters - params_out = builder.alloca(params_in.type.pointee) - # Copy original values. This handles params without param ports. - # Few extra copies will be eliminated by the compiler. - builder.store(builder.load(params_in), params_out) - # This should be faster than 'obj._get_compilation_params' compilation_params = (getattr(obj.parameters, p_id, None) for p_id in obj.llvm_param_ids) # Filter out param ports without corresponding param for this function param_ports = [self._parameter_ports[param] for param in compilation_params if param in self._parameter_ports] + # Exit early if there's no modulation. It's difficult for compiler + # to replace pointer arguments to functions with the source location. + if len(param_ports) == 0: + return params_in, builder + + # Allocate a shadow structure to overload user supplied parameters + params_out = builder.alloca(params_in.type.pointee, name="modulated_parameters") + if len(param_ports) != len(obj.llvm_param_ids): + builder = pnlvm.helpers.memcpy(builder, params_out, params_in) + def _get_output_ptr(b, i): ptr = pnlvm.helpers.get_param_ptr(b, obj, params_out, param_ports[i].source.name) return b, ptr - def _fill_input(b, p_input, i): - param_ptr = pnlvm.helpers.get_param_ptr(b, obj, params_in, - param_ports[i].source.name) - # Parameter port inputs are {original parameter, [modulations]}, - # here we fill in the first one. - data_ptr = builder.gep(p_input, [ctx.int32_ty(0), ctx.int32_ty(0)]) - assert data_ptr.type == param_ptr.type, \ - "Mishandled modulation type for: {} in '{}' in '{}'".format( - param_ports[i].name, obj.name, self.name) - b.store(b.load(param_ptr), data_ptr) - return b + def _get_input_data_ptr(b, i): + ptr = pnlvm.helpers.get_param_ptr(b, obj, params_in, + param_ports[i].source.name) + return b, ptr builder = self._gen_llvm_ports(ctx, builder, param_ports, "_parameter_ports", - _get_output_ptr, _fill_input, + _get_output_ptr, _get_input_data_ptr, mech_params, mech_state, mech_input) return params_out, builder @@ -2963,17 +3019,41 @@ def _gen_llvm_output_port_parse_variable(self, ctx, builder, port_spec = port._variable_spec if port_spec == OWNER_VALUE: return value - elif isinstance(port_spec, tuple) and port_spec[0] == OWNER_VALUE: - index = port_spec[1]() if callable(port_spec[1]) else port_spec[1] - - assert index < len(value.type.pointee) - return builder.gep(value, [ctx.int32_ty(0), ctx.int32_ty(index)]) elif port_spec == OWNER_EXECUTION_COUNT: - execution_count = pnlvm.helpers.get_state_ptr(builder, self, mech_state, "execution_count") - return execution_count + # Convert execution count to (num_executions, TimeScale.LIFE) + # The difference in Python PNL is that the former counts across + # all contexts. This is not possible in compiled code, thus + # the two are identical. + port_spec = ("num_executions", TimeScale.LIFE) + + try: + name = port_spec[0] + ids = (x() if callable(x) else getattr(x, 'value', x) for x in port_spec[1:]) + except TypeError as e: + # TypeError means we can't index. + # Convert this to assertion failure below + pass else: #TODO: support more spec options - assert False, "Unsupported OutputPort spec: {} ({})".format(port_spec, value.type) + if name == OWNER_VALUE: + data = value + elif name in self.llvm_state_ids: + data = pnlvm.helpers.get_state_ptr(builder, self, mech_state, name) + else: + data = None + + if data is not None: + parsed = builder.gep(data, [ctx.int32_ty(0), *(ctx.int32_ty(i) for i in ids)]) + # "num_executions" are kept as int64, we need to convert the value to float first + if name == "num_executions": + count = builder.load(parsed) + count_fp = builder.uitofp(count, ctx.float_ty) + parsed = builder.alloca(count_fp.type) + builder.store(count_fp, parsed) + + return parsed + + assert False, "Unsupported OutputPort spec: {} ({})".format(port_spec, value.type) def _gen_llvm_output_ports(self, ctx, builder, value, mech_params, mech_state, mech_in, mech_out): @@ -2981,88 +3061,75 @@ def _get_output_ptr(b, i): ptr = b.gep(mech_out, [ctx.int32_ty(0), ctx.int32_ty(i)]) return b, ptr - def _fill_input(b, s_input, i): - data_ptr = self._gen_llvm_output_port_parse_variable(ctx, b, + def _get_input_data_ptr(b, i): + ptr = self._gen_llvm_output_port_parse_variable(ctx, b, mech_params, mech_state, value, self.output_ports[i]) - # Output port inputs are {original parameter, [modulations]}, - # fill in the first one. - input_ptr = builder.gep(s_input, [ctx.int32_ty(0), ctx.int32_ty(0)]) - if input_ptr.type != data_ptr.type: - port = self.output_ports[i] - warnings.warn("Shape mismatch: {} parsed value does not match " - "output port: mech value: {} spec: {} parsed {}.".format( - port, self.defaults.value, port._variable_spec, - port.defaults.variable)) - input_ptr = builder.gep(input_ptr, [ctx.int32_ty(0), ctx.int32_ty(0)]) - b.store(b.load(data_ptr), input_ptr) - return b + return b, ptr builder = self._gen_llvm_ports(ctx, builder, self.output_ports, "output_ports", - _get_output_ptr, _fill_input, + _get_output_ptr, _get_input_data_ptr, mech_params, mech_state, mech_in) return builder - def _gen_llvm_invoke_function(self, ctx, builder, function, params, state, variable, *, tags:frozenset): + def _gen_llvm_invoke_function(self, ctx, builder, function, f_params, f_state, variable, *, tags:frozenset): fun = ctx.import_llvm_function(function, tags=tags) - fun_out = builder.alloca(fun.args[3].type.pointee) + fun_out = builder.alloca(fun.args[3].type.pointee, name=function.name + "_output") - builder.call(fun, [params, state, variable, fun_out]) + builder.call(fun, [f_params, f_state, variable, fun_out]) return fun_out, builder - def _gen_llvm_is_finished_cond(self, ctx, builder, params, state): + def _gen_llvm_is_finished_cond(self, ctx, builder, m_params, m_state): return ctx.bool_ty(1) - def _gen_llvm_mechanism_functions(self, ctx, builder, params, state, arg_in, + def _gen_llvm_mechanism_functions(self, ctx, builder, m_base_params, m_params, m_state, arg_in, ip_output, *, tags:frozenset): # Default mechanism runs only the main function - f_params_ptr = pnlvm.helpers.get_param_ptr(builder, self, params, "function") + f_base_params = pnlvm.helpers.get_param_ptr(builder, self, m_base_params, "function") f_params, builder = self._gen_llvm_param_ports_for_obj( - self.function, f_params_ptr, ctx, builder, params, state, arg_in) - f_state = pnlvm.helpers.get_state_ptr(builder, self, state, "function") + self.function, f_base_params, ctx, builder, m_base_params, m_state, arg_in) + f_state = pnlvm.helpers.get_state_ptr(builder, self, m_state, "function") return self._gen_llvm_invoke_function(ctx, builder, self.function, f_params, f_state, ip_output, tags=tags) - def _gen_llvm_function_internal(self, ctx, builder, params, state, arg_in, - arg_out, *, tags:frozenset): + def _gen_llvm_function_internal(self, ctx, builder, m_params, m_state, arg_in, + arg_out, m_base_params, *, tags:frozenset): ip_output, builder = self._gen_llvm_input_ports(ctx, builder, - params, state, arg_in) - - value, builder = self._gen_llvm_mechanism_functions(ctx, builder, params, - state, arg_in, - ip_output, - tags=tags) - - # Update execution counter - exec_count_ptr = pnlvm.helpers.get_state_ptr(builder, self, state, "execution_count") - exec_count = builder.load(exec_count_ptr) - exec_count = builder.fadd(exec_count, exec_count.type(1)) - builder.store(exec_count, exec_count_ptr) - - # Update internal clock (i.e. num_executions parameter) - num_executions_ptr = pnlvm.helpers.get_state_ptr(builder, self, state, "num_executions") - for scale in [TimeScale.TIME_STEP, TimeScale.PASS, TimeScale.TRIAL, TimeScale.RUN]: - num_exec_time_ptr = builder.gep(num_executions_ptr, [ctx.int32_ty(0), ctx.int32_ty(scale.value)]) + m_base_params, m_state, arg_in) + + value, builder = self._gen_llvm_mechanism_functions(ctx, builder, m_base_params, + m_params, m_state, arg_in, + ip_output, tags=tags) + + + # Update num_executions parameter + num_executions_ptr = pnlvm.helpers.get_state_ptr(builder, self, m_state, "num_executions") + for scale in TimeScale: + assert scale.value < len(num_executions_ptr.type.pointee) + num_exec_time_ptr = builder.gep(num_executions_ptr, + [ctx.int32_ty(0), ctx.int32_ty(scale.value)], + name="num_executions_{}_ptr".format(scale)) new_val = builder.load(num_exec_time_ptr) new_val = builder.add(new_val, new_val.type(1)) builder.store(new_val, num_exec_time_ptr) - builder = self._gen_llvm_output_ports(ctx, builder, value, params, state, arg_in, arg_out) - - val_ptr = pnlvm.helpers.get_state_ptr(builder, self, state, "value") + val_ptr = pnlvm.helpers.get_state_ptr(builder, self, m_state, "value") if val_ptr.type.pointee == value.type.pointee: - pnlvm.helpers.push_state_val(builder, self, state, "value", value) + pnlvm.helpers.push_state_val(builder, self, m_state, "value", value) else: # FIXME: Does this need some sort of parsing? warnings.warn("Shape mismatch: function result does not match mechanism value param: {} vs. {}".format(value.type.pointee, val_ptr.type.pointee)) + # Run output ports after updating the mech state (num_executions and value) + builder = self._gen_llvm_output_ports(ctx, builder, value, m_base_params, m_state, arg_in, arg_out) + # is_finished should be checked after output ports ran is_finished_f = ctx.import_llvm_function(self, tags=tags.union({"is_finished"})) - is_finished_cond = builder.call(is_finished_f, [params, state, arg_in, + is_finished_cond = builder.call(is_finished_f, [m_params, m_state, arg_in, arg_out]) return builder, is_finished_cond @@ -3071,8 +3138,8 @@ def _gen_llvm_function_reset(self, ctx, builder, params, state, arg_in, arg_out, reinit_func = ctx.import_llvm_function(self.function, tags=tags) reinit_params = pnlvm.helpers.get_param_ptr(builder, self, params, "function") reinit_state = pnlvm.helpers.get_state_ptr(builder, self, state, "function") - reinit_in = builder.alloca(reinit_func.args[2].type.pointee) - reinit_out = builder.alloca(reinit_func.args[3].type.pointee) + reinit_in = builder.alloca(reinit_func.args[2].type.pointee, name="reinit_in") + reinit_out = builder.alloca(reinit_func.args[3].type.pointee, name="reinit_out") builder.call(reinit_func, [reinit_params, reinit_state, reinit_in, reinit_out]) @@ -3096,11 +3163,11 @@ def _gen_llvm_function(self, *, extra_args=[], ctx:pnlvm.LLVMBuilderContext, tag builder.ret(finished) return builder.function - def _gen_llvm_function_body(self, ctx, builder, params, state, arg_in, arg_out, *, tags:frozenset): + def _gen_llvm_function_body(self, ctx, builder, base_params, state, arg_in, arg_out, *, tags:frozenset): assert "reset" not in tags params, builder = self._gen_llvm_param_ports_for_obj( - self, params, ctx, builder, params, state, arg_in) + self, base_params, ctx, builder, base_params, state, arg_in) is_finished_flag_ptr = pnlvm.helpers.get_state_ptr(builder, self, state, "is_finished_flag") @@ -3126,17 +3193,19 @@ def _gen_llvm_function_body(self, ctx, builder, params, state, arg_in, arg_out, # Get internal function args_t = [a.type for a in builder.function.args] + args_t[4:4] = [base_params.type] internal_builder = ctx.create_llvm_function(args_t, self, name=builder.function.name + "_internal", return_type=ctx.bool_ty) - iparams, istate, iin, iout = internal_builder.function.args[:4] + iparams, istate, iin, iout, ibase_params = internal_builder.function.args[:5] internal_builder, is_finished = self._gen_llvm_function_internal(ctx, internal_builder, - iparams, istate, iin, iout, tags=tags) + iparams, istate, iin, iout, + ibase_params, tags=tags) internal_builder.ret(is_finished) # Call Internal Function internal_f = internal_builder.function - is_finished_cond = builder.call(internal_f, [params, state, arg_in, arg_out, *builder.function.args[4:]]) + is_finished_cond = builder.call(internal_f, [params, state, arg_in, arg_out, base_params, *builder.function.args[4:]]) #FIXME: Flag and count should be int instead of float # Check if we reached maximum iteration count @@ -3393,7 +3462,7 @@ def port_cell(port, include_function:bool=False, include_value:bool=False, use_l value='' if include_value: if use_label and not isinstance(port, ParameterPort): - value = f'
={port.label}' + value = f'
={port.labeled_value}' else: value = f'
={port.value}' return f'{port.name}{function}{value}' @@ -3824,6 +3893,17 @@ def _get_port_value_labels(self, port_type, context=None): def input_port(self): return self.input_ports[0] + def get_input_variables(self, context=None): + # FIX: 2/4/22 THIS WOULD PARALLEL get_input_values BUT MAY NOT BE NEEDED: + # input_variables = [] + # for input_port in self.input_ports: + # if "LearningSignal" in input_port.name: + # input_variables.append(input_port.parameters.variable.get(context).flatten()) + # else: + # input_variables.append(input_port.parameters.variable.get(context)) + # return input_variables + return [input_port.parameters.variable.get(context) for input_port in self.input_ports] + @property def input_values(self): try: @@ -3847,6 +3927,51 @@ def external_input_ports(self): except (TypeError, AttributeError): return None + @property + def external_input_shape(self): + """Alias for _default_external_input_shape""" + return self._default_external_input_shape + + @property + def _default_external_input_shape(self): + try: + shape = [] + for input_port in self.input_ports: + if input_port.internal_only or input_port.default_input: + continue + if input_port._input_shape_template == VARIABLE: + shape.append(input_port.defaults.variable) + elif input_port._input_shape_template == VALUE: + shape.append(input_port.defaults.value) + else: + assert False, f"PROGRAM ERROR: bad changes_shape in attempt to assign " \ + f"default_external_input_shape for '{input_port.name}' of '{self.name}." + return shape + except (TypeError, AttributeError): + return None + + @property + def external_input_variables(self): + """Returns variables of all external InputPorts that belong to the Mechanism""" + try: + return [input_port.variable for input_port in self.input_ports if not input_port.internal_only] + except (TypeError, AttributeError): + return None + + @property + def default_external_inputs(self): + try: + return [input_port.default_input for input_port in self.input_ports if not input_port.internal_only] + except (TypeError, AttributeError): + return None + + @property + def default_external_input_variables(self): + try: + return [input_port.defaults.variable for input_port in self.input_ports if not input_port.internal_only] + except (TypeError, AttributeError): + return None + @property def external_input_values(self): try: @@ -3862,7 +3987,7 @@ def default_external_input_values(self): return None @property - def input_labels(self): + def labeled_input_values(self): """ Returns a list with as many items as there are InputPorts of the Mechanism. Each list item represents the value of the corresponding InputPort, and is populated by a string label (from the input_labels_dict) when one @@ -3886,13 +4011,13 @@ def output_port(self): @property def output_values(self): - return self.output_ports.values + return self.get_output_values() def get_output_values(self, context=None): return [output_port.parameters.value.get(context) for output_port in self.output_ports] @property - def output_labels(self): + def labeled_output_values(self): """ Returns a list with as many items as there are OutputPorts of the Mechanism. Each list item represents the value of the corresponding OutputPort, and is populated by a string label (from the output_labels_dict) when @@ -3906,8 +4031,8 @@ def get_output_labels(self, context=None): elif context: return self.get_output_values(context) else: - return self.output_values - + # Use this to report most recent value if no context is available + return self.output_ports.values @property def ports(self): @@ -3994,28 +4119,87 @@ def _dependent_components(self): self.parameter_ports, )) - @property - def _dict_summary(self): - inputs_dict = { - MODEL_SPEC_ID_INPUT_PORTS: [ - s._dict_summary for s in self.input_ports - ] - } - inputs_dict[MODEL_SPEC_ID_INPUT_PORTS].extend( - [s._dict_summary for s in self.parameter_ports] + def as_mdf_model(self): + import modeci_mdf.mdf as mdf + + model = mdf.Node( + id=parse_valid_identifier(self.name), + **self._mdf_metadata, ) - outputs_dict = { - MODEL_SPEC_ID_OUTPUT_PORTS: [ - s._dict_summary for s in self.output_ports - ] - } + for name, val in self._mdf_model_parameters[self._model_spec_id_parameters].items(): + model.parameters.append(mdf.Parameter(id=name, value=val)) - return { - **super()._dict_summary, - **inputs_dict, - **outputs_dict - } + for ip in self.input_ports: + if len(ip.path_afferents) > 1: + for aff in ip.path_afferents: + ip_model = mdf.InputPort( + id=parse_valid_identifier(f'{self.name}_input_port_{aff.name}'), + shape=str(aff.defaults.value.shape), + type=str(aff.defaults.value.dtype) + ) + model.input_ports.append(ip_model) + + # create combination function + model.parameters.append( + mdf.Parameter( + id='combination_function_input_data', + value=f"[{', '.join(f'{mip.id}' for mip in model.input_ports)}]" + ) + ) + combination_function_id = f'{parse_valid_identifier(self.name)}_{MODEL_SPEC_ID_INPUT_PORT_COMBINATION_FUNCTION}' + combination_function_args = { + 'data': "combination_function_input_data", + 'axes': 0 + } + model.functions.append( + mdf.Function( + id=combination_function_id, + function={'onnx::ReduceSum': combination_function_args}, + args=combination_function_args + ) + ) + combination_function_dimreduce_id = f'{combination_function_id}_dimreduce' + model.functions.append( + mdf.Function( + id=combination_function_dimreduce_id, + value=f'{MODEL_SPEC_ID_MDF_VARIABLE}[0][0]', + args={ + MODEL_SPEC_ID_MDF_VARIABLE: combination_function_id, + } + ) + ) + else: + ip_model = ip.as_mdf_model() + ip_model.id = f'{parse_valid_identifier(self.name)}_{ip_model.id}' + + model.input_ports.append(ip_model) + + for op in self.output_ports: + op_model = op.as_mdf_model() + op_model.id = f'{parse_valid_identifier(self.name)}_{op_model.id}' + + model.output_ports.append(op_model) + + function_model = self.function.as_mdf_model() + + for _, func_param in function_model.metadata['function_stateful_params'].items(): + model.parameters.append(mdf.Parameter(**func_param)) + + if len(ip.path_afferents) > 1: + primary_function_input_name = combination_function_dimreduce_id + else: + primary_function_input_name = model.input_ports[0].id + + self.function._set_mdf_arg( + function_model, _get_variable_parameter_name(self.function), primary_function_input_name + ) + model.functions.append(function_model) + + for func_model in model.functions: + _substitute_expression_args(func_model) + + return model def _is_mechanism_spec(spec): diff --git a/psyneulink/core/components/mechanisms/modulatory/control/controlmechanism.py b/psyneulink/core/components/mechanisms/modulatory/control/controlmechanism.py index d3c8b25f947..3da410a7ae5 100644 --- a/psyneulink/core/components/mechanisms/modulatory/control/controlmechanism.py +++ b/psyneulink/core/components/mechanisms/modulatory/control/controlmechanism.py @@ -72,7 +72,7 @@ ControlMechanism can be assigned as the `controller ` for a Composition by specifying it in the **controller** argument of the Composition's constructor, or by using the Composition's `add_controller ` method. A Composition's `controller ` and its associated -Components can be displayed using the Composition's `show_graph ` method with its +Components can be displayed using the Composition's `show_graph ` method with its **show_control** argument assigned as `True`. @@ -92,7 +92,7 @@ *Specifying OutputPorts to be monitored* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -A ControlMechanism can be configured to monitor the output of other Mechanisms directly (by receiving direct +A ControlMechanism can be configured to monitor the output of other Mechanisms either directly (by receiving direct Projections from their OutputPorts), or by way of an `ObjectiveMechanism` that evaluates those outputs and passes the result to the ControlMechanism (see `below ` for more detailed description). The following figures show an example of each: @@ -1029,6 +1029,7 @@ class ControlMechanism(ModulatoryMechanism_Base): """ componentType = "ControlMechanism" + controlType = CONTROL # Used as key in specification dictionaries; can be overridden by subclasses initMethod = INIT_EXECUTE_METHOD_ONLY @@ -1145,6 +1146,12 @@ class Parameters(ModulatoryMechanism_Base.Parameters): :type: :read only: True + outcome_input_ports + see `outcome_input_ports ` + + :default value: None + :type: ``list`` + output_ports see `output_ports ` @@ -1182,6 +1189,7 @@ class Parameters(ModulatoryMechanism_Base.Parameters): objective_mechanism = Parameter(None, stateful=False, loggable=False, structural=True) outcome_input_ports_option = Parameter(SEPARATE, stateful=False, loggable=False, structural=True) + outcome_input_ports = Parameter(None, reference=True, stateful=False, loggable=False, read_only=True) input_ports = Parameter( [OUTCOME], @@ -1197,6 +1205,7 @@ class Parameters(ModulatoryMechanism_Base.Parameters): stateful=False, loggable=False, read_only=True, + structural=True, ) output_ports = Parameter( @@ -1206,8 +1215,8 @@ class Parameters(ModulatoryMechanism_Base.Parameters): read_only=True, structural=True, parse_spec=True, - aliases=['control', 'control_signals'], - constructor_argument='control' + aliases=[CONTROL, CONTROL_SIGNALS], + constructor_argument=CONTROL ) def _parse_output_ports(self, output_ports): @@ -1231,17 +1240,14 @@ def is_2tuple(o): MECHANISM: output_ports[i][1] } # handle dict of form {PROJECTIONS: <2 item tuple>, : , ...} - elif ( - isinstance(output_ports[i], dict) - and PROJECTIONS in output_ports[i] - and is_2tuple(output_ports[i][PROJECTIONS]) - ): - full_spec_dict = { - NAME: output_ports[i][PROJECTIONS][0], - MECHANISM: output_ports[i][PROJECTIONS][1], - **{k: v for k, v in output_ports[i].items() if k != PROJECTIONS} - } - output_ports[i] = full_spec_dict + elif isinstance(output_ports[i], dict): + for PROJ_SPEC_KEYWORD in {PROJECTIONS, self._owner.controlType}: + if (PROJ_SPEC_KEYWORD in output_ports[i] and is_2tuple(output_ports[i][PROJ_SPEC_KEYWORD])): + tuple_spec = output_ports[i].pop(PROJ_SPEC_KEYWORD) + output_ports[i].update({ + NAME: tuple_spec[0], + MECHANISM: tuple_spec[1]}) + assert True return output_ports @@ -1282,9 +1288,10 @@ def __init__(self, **kwargs ): - monitor_for_control = convert_to_list(monitor_for_control) or [] control = convert_to_list(control) or [] + monitor_for_control = convert_to_list(monitor_for_control) or [] self.allow_probes = allow_probes + self._sim_counts = {} # For backward compatibility: if kwargs: @@ -1296,7 +1303,7 @@ def __init__(self, # Only allow one of CONTROL, MODULATORY_SIGNALS OR CONTROL_SIGNALS to be specified # These are synonyms, but allowing several to be specified and trying to combine the specifications # can cause problems if different forms of specification are used to refer to the same Component(s) - control_specified = "'control'" if control else '' + control_specified = f"'{CONTROL}'" if control else '' modulatory_signals_specified = '' if MODULATORY_SIGNALS in kwargs: args = kwargs.pop(MODULATORY_SIGNALS) @@ -1324,8 +1331,6 @@ def __init__(self, function = function or DefaultAllocationFunction - self._sim_counts = {} - super(ControlMechanism, self).__init__( default_variable=default_variable, size=size, @@ -1356,9 +1361,17 @@ def _validate_params(self, request_set, target_set=None, context=None): target_set=target_set, context=context) - if OBJECTIVE_MECHANISM in target_set and \ - target_set[OBJECTIVE_MECHANISM] is not None and\ - target_set[OBJECTIVE_MECHANISM] is not False: + if (MONITOR_FOR_CONTROL in target_set + and target_set[MONITOR_FOR_CONTROL] is not None + and any(item for item in target_set[MONITOR_FOR_CONTROL] + if (isinstance(item, ObjectiveMechanism) or item is ObjectiveMechanism))): + raise ControlMechanismError(f"The '{MONITOR_FOR_CONTROL}' arg of '{self.name}' contains a specification for" + f" an {ObjectiveMechanism.componentType} ({target_set[MONITOR_FOR_CONTROL]}). " + f"This should be specified in its '{OBJECTIVE_MECHANISM}' argument.") + + if (OBJECTIVE_MECHANISM in target_set and + target_set[OBJECTIVE_MECHANISM] is not None + and target_set[OBJECTIVE_MECHANISM] is not False): if isinstance(target_set[OBJECTIVE_MECHANISM], list): @@ -1385,22 +1398,25 @@ def _validate_params(self, request_set, target_set=None, context=None): validate_monitored_port_spec(self, obj_mech_spec_list) if not isinstance(target_set[OBJECTIVE_MECHANISM], (ObjectiveMechanism, list, bool)): - raise ControlMechanismError("Specification of {} arg for {} ({}) must be an {}" - "or a list of Mechanisms and/or OutputPorts to be monitored for control". - format(OBJECTIVE_MECHANISM, - self.name, target_set[OBJECTIVE_MECHANISM], - ObjectiveMechanism.componentName)) + raise ControlMechanismError(f"Specification of {OBJECTIVE_MECHANISM} arg for '{self.name}' " + f"({target_set[OBJECTIVE_MECHANISM].name}) must be an " + f"{ObjectiveMechanism.componentType} or a list of Mechanisms and/or " + f"OutputPorts to be monitored for control.") if CONTROL in target_set and target_set[CONTROL]: control = target_set[CONTROL] - assert isinstance(control, list), \ - f"PROGRAM ERROR: control arg {control} of {self.name} should have been converted to a list." - for ctl_spec in control: - ctl_spec = _parse_port_spec(port_type=ControlSignal, owner=self, port_spec=ctl_spec) - if not (isinstance(ctl_spec, ControlSignal) - or (isinstance(ctl_spec, dict) and ctl_spec[PORT_TYPE]==ControlSignal.__name__)): - raise ControlMechanismError(f"Invalid specification for '{CONTROL}' argument of {self.name}:" - f"({ctl_spec})") + self._validate_control_arg(control) + + def _validate_control_arg(self, control): + """Treat control arg separately so it can be overridden by subclassses (e.g., GatingMechanism)""" + assert isinstance(control, list), \ + f"PROGRAM ERROR: control arg {control} of {self.name} should have been converted to a list." + for ctl_spec in control: + ctl_spec = _parse_port_spec(port_type=ControlSignal, owner=self, port_spec=ctl_spec) + if not (isinstance(ctl_spec, ControlSignal) + or (isinstance(ctl_spec, dict) and ctl_spec[PORT_TYPE] == ControlSignal)): + raise ControlMechanismError(f"Invalid specification for '{CONTROL}' argument of {self.name}:" + f"({ctl_spec})") # IMPLEMENTATION NOTE: THIS SHOULD BE MOVED TO COMPOSITION ONCE THAT IS IMPLEMENTED def _instantiate_objective_mechanism(self, input_ports=None, context=None): @@ -1542,7 +1558,8 @@ def _instantiate_input_ports(self, input_ports=None, context=None): other_input_ports = input_ports or [] # FIX 11/3/21: THIS SHOULD BE MADE A PARAMETER - self.outcome_input_ports = ContentAddressableList(component_type=OutputPort) + self.parameters.outcome_input_ports.set(ContentAddressableList(component_type=OutputPort), + override=True) # If ObjectiveMechanism is specified, instantiate it and OUTCOME InputPort that receives projection from it if self.objective_mechanism: @@ -1551,6 +1568,7 @@ def _instantiate_input_ports(self, input_ports=None, context=None): # of the objective_mechanism's constructor self._instantiate_objective_mechanism(input_ports, context=context) + # FIX: CONSOLIDATE THIS WITH SIMILAR HANDLING IN _instantiate_objective_mechanism AND ELSE BELOW # If no ObjectiveMechanism is specified, but items to monitor are specified, # assign an outcome_input_port for each item specified elif self.monitor_for_control: @@ -1579,7 +1597,6 @@ def _instantiate_input_ports(self, input_ports=None, context=None): from psyneulink.core.components.projections.pathway.mappingprojection import MappingProjection from psyneulink.core.components.mechanisms.processing.objectivemechanism import _parse_monitor_specs - self.aux_components = [] for i in range(len(projection_specs)): if option == SEPARATE: # Each outcome_input_port get its own Projection @@ -1590,10 +1607,21 @@ def _instantiate_input_ports(self, input_ports=None, context=None): self.aux_components.append(MappingProjection(sender=projection_specs[i], receiver=self.outcome_input_ports[outcome_port_index])) - # Nothing has been specified, so just instantiate the default OUTCOME InputPort + # Nothing has been specified, so just instantiate the default OUTCOME InputPort with any input_ports passed in else: - super()._instantiate_input_ports(context=context) + # # MODIFIED 1/30/21 OLD: + # super()._instantiate_input_ports(context=context) + # self.outcome_input_ports.append(self.input_ports[OUTCOME]) + # MODIFIED 1/30/21 NEW: + other_input_port_value_sizes = self._handle_arg_input_ports(other_input_ports)[0] + # Construct full list of InputPort specifications and sizes + input_ports = self.input_ports + other_input_ports + input_port_value_sizes = [[0]] + other_input_port_value_sizes + super()._instantiate_input_ports(context=context, + input_ports=input_ports, + reference_value=input_port_value_sizes) self.outcome_input_ports.append(self.input_ports[OUTCOME]) + # MODIFIED 1/30/21 END def _parse_monitor_for_control_input_ports(self, context): """Get outcome_input_port specification dictionaries for items specified in monitor_for_control. @@ -1654,7 +1682,9 @@ def _parse_monitor_for_control_input_ports(self, context): return outcome_input_port_specs, port_value_sizes, monitored_ports def _validate_monitor_for_control(self, nodes): - # Ensure all of the Components being monitored for control are in the Composition being controlled + """Ensure all of the Components being monitored for control are in the Composition being controlled + If monitor_for_control is specified as an ObjectiveMechanism, warn and move to objective_mecahnism arg + """ from psyneulink.core.components.ports.port import Port invalid_outcome_specs = [item for item in self.monitor_for_control if ((isinstance(item, Mechanism) @@ -1696,7 +1726,7 @@ def _register_control_signal_type(self, context=None): ) def _instantiate_control_signals(self, context): - """Subclassess can override for class-specific implementation (see OptimizationControlMechanism for example)""" + """Subclasses can override for class-specific implementation (see OptimizationControlMechanism for example)""" output_port_specs = list(enumerate(self.output_ports)) for i, control_signal in output_port_specs: @@ -1983,6 +2013,23 @@ def _activate_projections_for_compositions(self, composition=None): for proj in deeply_nested_aux_components.values(): composition.add_projection(proj, sender=proj.sender, receiver=proj.receiver) + # Add any remaining afferent Projections that have been assigned and are from nodes in composition + remaining_projections = set(self.projections) - dependent_projections - set(self.composition.projections) + for proj in remaining_projections: + # Projection is afferent: + if proj in self.afferents: + # Confirm sender is in composition + port, node, comp = composition._get_source(proj) + elif proj in self.efferents: + # Confirm receiver is in composition + port, node, comp = composition._get_destination(proj) + else: + assert False, f"PROGRAM ERROR: Attempt to activate Projection ('{proj.name}') in '{composition.name}'" \ + f" associated with its controller '{self.name}' that is neither an afferent nor " \ + f"efferent of '{self.name}' -- May be as yet unaccounted for condition." + if node in composition._get_all_nodes(): + proj._activate_for_compositions(composition) + def _apply_control_allocation(self, control_allocation, runtime_params, context): """Update values to `control_signals ` based on specified `control_allocation ` diff --git a/psyneulink/core/components/mechanisms/modulatory/control/gating/gatingmechanism.py b/psyneulink/core/components/mechanisms/modulatory/control/gating/gatingmechanism.py index dbf03790b30..5338d545fc4 100644 --- a/psyneulink/core/components/mechanisms/modulatory/control/gating/gatingmechanism.py +++ b/psyneulink/core/components/mechanisms/modulatory/control/gating/gatingmechanism.py @@ -185,10 +185,11 @@ from psyneulink.core.components.mechanisms.modulatory.control.controlmechanism import ControlMechanism from psyneulink.core.components.ports.modulatorysignals.gatingsignal import GatingSignal +from psyneulink.core.components.ports.port import _parse_port_spec from psyneulink.core.globals.defaults import defaultGatingAllocation from psyneulink.core.globals.keywords import \ - GATING, GATING_PROJECTION, GATING_SIGNAL, GATING_SIGNALS, \ - INIT_EXECUTE_METHOD_ONLY, MONITOR_FOR_CONTROL, PROJECTION_TYPE + CONTROL, CONTROL_SIGNALS, GATE, GATING_PROJECTION, GATING_SIGNAL, GATING_SIGNALS, \ + INIT_EXECUTE_METHOD_ONLY, MONITOR_FOR_CONTROL, PORT_TYPE, PROJECTIONS, PROJECTION_TYPE from psyneulink.core.globals.parameters import Parameter from psyneulink.core.globals.preferences.basepreferenceset import is_pref_set from psyneulink.core.globals.preferences.preferenceset import PreferenceLevel @@ -217,7 +218,7 @@ def _is_gating_spec(spec): GatingMechanism, ControlMechanism)): return True - elif isinstance(spec, str) and spec in {GATING, GATING_PROJECTION, GATING_SIGNAL}: + elif isinstance(spec, str) and spec in {GATE, GATING_PROJECTION, GATING_SIGNAL}: return True else: return False @@ -372,6 +373,7 @@ class GatingMechanism(ControlMechanism): """ componentType = "GatingMechanism" + controlType = GATE initMethod = INIT_EXECUTE_METHOD_ONLY @@ -399,6 +401,13 @@ class Parameters(ControlMechanism.Parameters): :default value: numpy.array([0.5]) :type: ``numpy.ndarray`` + output_ports + see `output_ports ` + + :default value: None + :type: + :read only: True + gating_allocation see `gating_allocation ` @@ -413,6 +422,17 @@ class Parameters(ControlMechanism.Parameters): pnl_internal=True ) + output_ports = Parameter( + None, + stateful=False, + loggable=False, + read_only=True, + structural=True, + parse_spec=True, + aliases=[CONTROL, CONTROL_SIGNALS, 'gate', 'gating_signal'], + constructor_argument='gate' + ) + @tc.typecheck def __init__(self, default_gating_allocation=None, @@ -462,12 +482,27 @@ def _register_control_signal_type(self, context=None): registry=self._portRegistry, ) + def _validate_control_arg(self, gate): + """Overrided to handle GatingMechanism-specific specifications""" + assert isinstance(gate, list), \ + f"PROGRAM ERROR: 'gate' arg ({gate}) of {self.name} should have been converted to a list." + for spec in gate: + spec = _parse_port_spec(port_type=GatingSignal, owner=self, port_spec=spec) + if not (isinstance(spec, GatingSignal) + or (isinstance(spec, dict) and spec[PORT_TYPE] == GatingSignal)): + raise GatingMechanismError(f"Invalid specification for '{GATE}' argument of {self.name}: ({spec})") + def _instantiate_control_signal_type(self, gating_signal_spec, context): """Instantiate actual ControlSignal, or subclass if overridden""" from psyneulink.core.components.ports.port import _instantiate_port from psyneulink.core.components.projections.projection import ProjectionError allocation_parameter_default = self.parameters.gating_allocation.default_value + + # Handle controlType as synonym for PROJECTIONS: + if isinstance(gating_signal_spec, dict) and self.controlType in gating_signal_spec: + gating_signal_spec[PROJECTIONS] = gating_signal_spec.pop(self.controlType) + gating_signal = _instantiate_port(port_type=GatingSignal, owner=self, variable=self.default_allocation # User specified value @@ -476,8 +511,10 @@ def _instantiate_control_signal_type(self, gating_signal_spec, context): modulation=self.defaults.modulation, port_spec=gating_signal_spec, context=context) + if not type(gating_signal) in convert_to_list(self.outputPortTypes): raise ProjectionError(f'{type(gating_signal)} inappropriate for {self.name}') + return gating_signal def _check_for_duplicates(self, control_signal, control_signals, context): diff --git a/psyneulink/core/components/mechanisms/modulatory/control/optimizationcontrolmechanism.py b/psyneulink/core/components/mechanisms/modulatory/control/optimizationcontrolmechanism.py index 6c15e5b26bf..9b7517f0f60 100644 --- a/psyneulink/core/components/mechanisms/modulatory/control/optimizationcontrolmechanism.py +++ b/psyneulink/core/components/mechanisms/modulatory/control/optimizationcontrolmechanism.py @@ -11,7 +11,6 @@ # FIX: REWORK WITH REFERENCES TO `outcome ` # INTRODUCE SIMULATION INTO DISCUSSION OF COMPOSITION-BASED - """ Contents @@ -20,18 +19,20 @@ * `OptimizationControlMechanism_Overview` - `Expected Value of Control ` - `Agent Representation and Types of Optimization ` - - `Model-Free" Optimization ` - - `Model-Based" Optimization ` + - `"Model-Free" Optimization ` + - `Model-Based Optimization ` * `OptimizationControlMechanism_Creation` - `Agent Rep ` - `State Features ` - - `State Feature Functions ` + - `agent_rep Composition ` + - `agent_rep CompositionFunctionApproximator ` + - `State Feature Functions ` - `Outcome ` * `OptimizationControlMechanism_Structure` - `Agent Representation ` - `State ` - `Input ` - - `state_input_ports ` + - `state_input_ports ` - `outcome_input_ports ` - `objective_mechanism ` - `monitor_for_control ` @@ -42,6 +43,7 @@ - `Output ` - `Randomization ControlSignal ` * `OptimizationControlMechanism_Execution` + - `OptimizationControlMechanism_Execution_Timing` - `OptimizationControlMechanism_Optimization_Procedure` - `OptimizationControlMechanism_Estimation_Randomization` * `OptimizationControlMechanism_Class_Reference` @@ -57,18 +59,19 @@ by using the `OptimizationFunction` (assigned as its `function `) to execute its `agent_rep ` -- a representation of the Composition to be optimized -- under different `control_allocations `, and selecting the one that optimizes -its `net_outcome `. A OptimizationControlMechanism can be configured to implement -forms of optimization, ranging from fully `model-based optimization ` +its `net_outcome `. An OptimizationControlMechanism can be configured to implement +various forms of optimization, ranging from fully `model-based optimization ` that uses the Composition itself as the `agent_rep ` to simulate the outcome for a given `state ` (i.e., a combination of the current input and a particular `control_allocation `), to fully `model-free optimization ` by using a `CompositionFunctionApproximator` as the `agent_rep ` that learns to predict the outcomes for a state. Intermediate forms of -optimization can also be implemented, that use simpler Compositions to approximate the dynamics of the full Composition. -The outcome of executing the `agent_rep ` is used to compute a `net_outcome -` for a given `state `, that takes into account -the `costs ` associated with the `control_allocation, and is used to determine -the optimal `control_allocations `. +optimization can also be implemented, that use simpler Compositions to approximate the dynamics of the full +Composition. The outcome of executing the `agent_rep ` is used to compute a +`net_outcome ` for a given `state `, that takes +into account the `costs ` associated with the `control_allocation +`, and is used to determine the optimal `control_allocations +`. .. _OptimizationControlMechanism_EVC: @@ -77,16 +80,16 @@ The `net_outcome ` of an OptimizationControlMechanism's `agent_rep ` is computed -- for a given `state ` (i.e., set of `state_feature_values ` and a `control_allocation -` -- as the difference between the `outcome ` computed +`) -- as the difference between the `outcome ` computed by its `objective_mechanism ` and the aggregated `costs ` of its `control_signals ` computed by its `combine_costs ` function. If the `outcome ` computed by the `objective_mechanism ` is configured to measure the value of processing (e.g., reward received, time taken to respond, or a combination of these, etc.), and the `OptimizationFunction` assigned as -the OptimizationControlMechanism's `function ` is configured find the +the OptimizationControlMechanism's `function ` is configured to find the `control_allocation ` that maximizes its `net_outcome ` (that is, the `outcome ` discounted by the -result of the `combine_costs ` function, then the OptimizationControlMechanism is +result of the `combine_costs ` function), then the OptimizationControlMechanism is said to be maximizing the `Expected Value of Control (EVC) `_. That is, it implements a cost-benefit analysis that weighs the `costs ` of the ControlSignal `values ` associated with a `control_allocation ` against @@ -120,35 +123,35 @@ ` for a given `state `, and find the `control_allocation ` that optimizes this. The `agent_rep ` can be the `Composition` to which the OptimizationControlMechanism -belongs (and controls), another (presumably simpler) one, or a `CompositionFunctionApproximator`) that is used to -estimate the `net_outcome ` Composition of which the OptimizationControlMechanism is -the `controller `. These different types of `agent representation +belongs (and controls), another (presumably simpler) one, or a `CompositionFunctionApproximator` that is used to +estimate the `net_outcome ` of the Composition of which the OptimizationControlMechanism +is the `controller `. These different types of `agent representation ` correspond closely to the distinction between *model-based* and *model-free* optimization in the `machine learning `_ and `cognitive neuroscience `_ literatures, as described below. -.. figure:: _static/Optimization_fig.svg - :scale: 50% - :alt: OptimizationControlMechanism - - **Functional Anatomy of an OptimizationControlMechanism.** *Panel A:* Examples of use in fully model-based - and model-free optimization. Note that in the example of `model-based optimization - ` (left), the OptimizationControlMechanism uses the entire - `Composition` that it controls as its `agent_rep `, whereas in - the example of `model-free optimization ` (right) the - the `agent_rep ` is a `CompositionFunctionApproximator`. The `agent_rep - ` can also be another (presumably simpler) Composition that can be used - to implement forms of optimization intermediate between fully model-based and model-free. *Panel B:* Flow of - execution during optimization. In both panels, faded items show process of adaptation when using a - `CompositionFunctionApproximator` as the `agent_rep `. + .. figure:: _static/Optimization_fig.svg + :scale: 50% + :alt: OptimizationControlMechanism + + **Functional Anatomy of an OptimizationControlMechanism.** *Panel A:* Examples of use in fully model-based + and model-free optimization. Note that in the example of `model-based optimization + ` (left), the OptimizationControlMechanism uses the entire + `Composition` that it controls as its `agent_rep `, whereas in + the example of `model-free optimization ` (right) the + the `agent_rep ` is a `CompositionFunctionApproximator`. The `agent_rep + ` can also be another (presumably simpler) Composition that can be used + to implement forms of optimization intermediate between fully model-based and model-free. *Panel B:* Flow of + execution during optimization. In both panels, faded items show process of adaptation when using a + `CompositionFunctionApproximator` as the `agent_rep `. | .. _OptimizationControlMechanism_Model_Based: *Model-Based Optimization* -The fullest form of this is implemented by assigning as the `agent_rep ` -the Composition for which the OptimizationControlMechanism is the `controller `). +The fullest form of this is implemented by assigning the Composition for which the OptimizationControlMechanism is the +`controller `) as its a`agent_rep ` On each `TRIAL `, that Composition *itself* is provided with either the most recent inputs to the Composition, or ones predicted for the upcoming trial (as determined by the `state_feature_values ` of the OptimizationControlMechanism), and then used to simulate @@ -170,17 +173,17 @@ addressed by use of the term "agent_rep", and how it is implemented, as described below. This clearest form of this uses a `CompositionFunctionApproximator`, that learns to predict the `net_outcome -`net_outcome ` for a given state (e.g., using reinforcement learning or other forms -of function approximation, , such as a `RegressionCFA`). In each `TRIAL ` the `agent_rep +` for a given state (e.g., using reinforcement learning or other forms of +function approximation, such as a `RegressionCFA`). In each `TRIAL ` the `agent_rep ` is used to search over `control_allocation `\\s, to find the one that yields the best predicted `net_outcome ` of processing on the upcoming trial, based on the current or (expected) `state_feature_values ` for that trial. The `agent_rep -` is also given the chance to adapt in order to improve its prediction -of its `net_outcome ` based on the `state `, -and `net_outcome ` of the prior trial. A Composition can also be used to generate -such predictions permitting, as noted above, forms of optimization intermediate between the extreme examples of -model-based and model-free. +` is also given the chance to adapt in order to improve its prediction of +its `net_outcome ` based on the `state ` and +`net_outcome ` of the prior `TRIAL `. A Composition can also be +used to generate such predictions, permitting forms of optimization that are intermediate between the extreme +examples of model-based and model-free, as noted above. .. _OptimizationControlMechanism_Creation: @@ -210,132 +213,310 @@ .. _OptimizationControlMechanism_State_Features_Arg: -* **state_features** -- specifies the values provided by the OptimizationControlMechanism as the input to the - `agent_rep ` when used, together with a selected `control_allocation - `, to estimate or predict the Composition's `net_outcome - `. These are used to construct the `state_input_ports - ` for the OptimizationControlMechanism, that provide the - `agent_rep` with its input, and thus the specification requirements for - **state_features** depend on whether the `agent_rep` is a `Composition` - or a `CompositionFunctionApproximator`: +* **state_features** -- specifies the sources of input to the OptimizationControlMechanism's `agent_rep + ` which, together with a selected `control_allocation + `, are provided as input to it's `evaluate ` method + when that is executed to estimate or predict the Composition's `net_outcome `. + Those sources of input are used to construct the OptimizationControlMechanism's `state_input_ports + `, one for each `external InputPort + ` of the `agent_rep `. The input to + each `state_input_port `, after being processed by it `function + `, is assigned as the corresponding value of `state_feature_values + `, the values of which provided as the input to the corresponding + InputPorts of the `INPUT ` `Nodes ` of the agent_rep each time it is `evaluated + `. Accordingly, the specification requirements for **state_features** depend on whether the + `agent_rep` is a `Composition` or a `CompositionFunctionApproximator`, + as described in each of the two sections below. + + | .. _OptimizationControlMechanism_Agent_Rep_Composition: - * *agent_rep is a Composition* -- the **state_features** specify the inputs to the Composition when it is executed - by the OptimizationControlMechanism to `evaluate ` its performance. - If **state_features** is not specified, this is done automatically by constructing a set of `state_input_ports - ` that `shadow the input ` to every - `InputPort` of every `INPUT ` `Node ` of the Composition assigned as - the `agent_rep `. In this case, if `controller_mode - ` of the Composition for which the OptimizationControlMechanism is the `controller - ` is set to *AFTER* (the default), the `input ` to - the Composition on the current trial is used as its input to the `agent_rep - ` for the optimization process; if the `controller_mode - ` is *BEFORE*, then the inputs from the previous trial are used. - - The **state_features** argument can also be specified explicitly, using the formats described below. This is - useful if different functions need to be assigned to different `state_input_ports - ` used to generate the corresponding `state_feature_values - state_feature_values ` (see `below - `). However, doing so overrides the automatic - assignment of all state_features, and so a complete and appropriate set of specifications must be provided - (see note below). - - .. _OptimizationControlMechanism_State_Features_Shapes: - - .. note:: - If **state_features** *are* specified explicitly when the `agent_rep ` - is a Composition, there must be one for every `InputPort` of every `INPUT ` `Node - ` in that Composition, and these must match -- both individually, and in their order -- - the `inputs to the Composition `) required by its `run ` - method. Failure to do so generates an error indicating this. - - .. _OptimizationControlMechanism_Selective_Input: - - .. hint:: - For cases in which only a subset of the inputs to the Composition are relevant to its optimization (e.g., - the others should be held constant), it is still the case that all must be specified as **state_features** - (see note above). This can be handled several ways. One is by specifying (as required) **state_features** - for all of the inputs, and assigning *state_feature_functions** (see `below - `) such that those assigned to the desired - inputs pass their values unmodified, while those for the inputs that are to be ignored return a constant value. - Another approach, for cases in which the desired inputs pertain to a subset of Components in the Composition - that solely responsible for determining its `net_outcome `, is to assign those - Components to a `nested Composition ` and assign that Composition as the `agent_rep - `. A third, more sophisticated approach, would be to assign - ControlSignals to the InputPorts for the irrelevant features, and specify them to suppress their values. + **state_features** *for an agent_rep that is a* **Composition** + + | + + .. _OptimizationControlMechanism_State_Features_Automatic_Assignment: + + *Automatic assignment.* By default, if **state_features**, **state_feature_default** and **state_feature_function** + are not specified, the `state_input_ports ` are configured to + `shadow the inputs ` of every `external InputPort ` + of the `agent_rep ` Composition; as a result, each time `agent_rep + ` is `evaluated `, it receives the same `external + input `) it received during its last `TRIAL` of execution. + + | + + .. _OptimizationControlMechanism_State_Features_Explicit_Specification: + + *Explicit specification.* Specifying the **state_features**, **state_feature_default** and/or + **state_feature_function** arguments explicitly can be useful if: values need to be provided as input to the + `agent_rep ` when it is evaluated other than its `external inputs + `; to restrict evaluation to a subset of its inputs (while others are held constant); + and/or to assign specific functions to one or more `state_input_ports + ` (see `below + `) that allow them to process the inputs + (e.g., modulate and/or integrate them) before they are assigned to `state_feature_values + ` and passed to the `agent_rep + `. Assignments can be made to **state_features** corresponding + to any or all InputPorts of the `agent_rep `\\'s `INPUT ` + `Nodes `, as described `below `. + Any that are not specified are assigned the value specified for **state_feature_default** (*SHADOW_INPUTS* by + default; see `state_feature_default ` for additional details). + A single assignment can be made for all **state_features**, or they can be specified individually for each `INPUT + ` `Nodes ` InputPort, as descdribed below. + + .. _OptimizationControlMechanism_State_Features_Shapes: + + .. note:: + If **state_features** are specified explicitly, the `value `\\s of the specified Components + must match the `input_shape ` of the corresponding InputPorts of the `agent_rep + `\\'s `INPUT ` `Nodes `. Those + InputPorts are listed in the `agent_rep `\\'s + `external_input_ports_of_all_input_nodes ` attribute + and, together with examples of their values, in the OptimizationControlMechanism's `state_feature_values + ` attribute. A failure to properly meet these requirements + produces an error. + + .. _OptimizationControlMechanism_State_Features_Specification: + + The **state_features** argument can be specified using any of the following formats: + + .. _OptimizationControlMechanism_State_Feature_Single_Spec: + + * *Single specification* -- any of the indivdiual specifications described `below + ` can be directly to **state_features**, that is + then used to construct *all* of the `state_input_ports `, one + for each `external InputPort ` of the `agent_rep + `. + + .. _OptimizationControlMechanism_State_Feature_Input_Dict: + + * *Inputs dictionary* -- specifies state_features (entry values) for individual `InputPorts ` and/or + `INPUT ` `Nodes ` of the `agent_rep ` + (entry keys). It must conform to the format used to `specify external inputs ` + to the `agent_rep `, in which entries consist of a key specifying either + an `INPUT ` `Node ` of the `agent_rep ` + or one of their `external InputPorts `, and a value that is the source of + the input that can be any of the forms of individual input specifications listed `below + `. The format required for the entries can be seen + using either the `agent_rep ` + `get_input_format ` method (for inputs to its `INPUT ` `) or its `external_input_ports_of_all_input_nodes + ` (for all of their `external InputPorts + `). If a nested Composition is specified (that is, one that is an `INPUT + ` Node of `agent_rep `), the state_feature assigned to it + is used to construct the `state_input_ports ` for *all* of the + `external InputPorts ` for that nested Composition, and any nested within + it at all levels of nesting. If any `INPUT ` Nodes or their InputPorts are not specified in the + dictionary, `state_feature_default ` is assigned as their + state_feature specification (this includes cases in which some but not all `INPUT ` Nodes of a + nested Composition, or their InputPorts, are specified; any unspecified INPUT Nodes of the corresponding + Compositions are assigned `state_feature_default ` as their + state_feature specification). + + .. _OptimizationControlMechanism_State_Feature_List_Inputs: + + * *List* -- a list of individual state_feature specifications, that can be any of the forms of individual + input specifications listed `below `. The items + correspond to all of the `external InputPorts ` of the `agent_rep + `, and must be specified in the order they are listed in the + `agent_rep `\\'s `external_input_ports_of_all_input_nodes + ` attribute. If the list is incomplete, the remaining + InputPorts are assigned `state_feature_default ` + as their state_feature specification, which by default is *SHADOW_INPUTS* (see `below + `. Items can be included in the list that + have not yet been added to the OptimizationControlMechanism's Composition or its `agent_rep + `. However, these must be added before the Composition is executed, + and must appear in the list in the same position that the InputPorts to which they pertain are listed in + the `agent_rep `\\'s `external_input_ports_of_all_input_nodes + ` attribute, once construction of the `agent_rep + ` is complete. + + .. _OptimizationControlMechanism_State_Feature_Set_Inputs: + + * *Set* -- a set of `INPUT ` `Nodes ` of the `agent_rep + ` that are assigned *SHADOW_INPUTS* as their state_feature + -- that is, that should receive the same inputs during evaluation as when the Composition of which + the OptimizationControlMechanism is the `controller ` is fully executed + (see `below <_OptimizationControlMechanism_SHADOW_INPUTS_State_Feature>`). The order of their specification + does not matter; however, any of the `agent_rep `\\'s `INPUT + ` Nodes that are *not* included in the set are assigned `state_feature_default + ` as their state_feature specification. Note that, + since the default for `state_feature_default ` is + *SHADOW_INPUTS*, unless this is specified otherwise omitting items from a set has no effect (i.e., they + too are assigned *SHADOW_INPUTS*); for omitted items to be treated differently, `state_feature_default + ` must be specified; for example by assigning it + ``None`` so that items omitted from the set are assigned their default input value (see `below + `. + + .. _OptimizationControlMechanism_State_Feature_Individual_Specs: + + * *Individual state_feature specifications* -- any of the specifications listed below can be used singly, + or in a dict, list or set as described `above `, + to configure `state_input_ports `. + + .. _OptimizationControlMechanism_None_State_Feature: + + * *None* -- no `state_input_port ` is constructed for + the corresponding `INPUT ` `Node ` InputPort, and its the value + of its `default variable ` is used as the input to that InputPort whenever the + ` is `evaluated `, irrespective of its input when + the `agent_rep ` was last executed. + + .. _OptimizationControlMechanism_Numeric_State_Feature: + + * *numeric value* -- create a `state_input_port ` has + no `afferent Projections `, and uses the specified value as the input to its + `function `, the result of which is assigned to the corresponding value of + `state_feature_values ` and provided as the input to + the corresponding `INPUT ` `Node ` InputPort each time the `agent_rep + ` is `evaluated `. The specified value must + be compatible with the shape of all of the `external InputPorts ` + of the `agent_rep ` (see `note + ` above). + + .. _OptimizationControlMechanism_SHADOW_INPUTS_State_Feature: + + * *SHADOW_INPUTS* -- create a `state_input_port ` that `shadows + the input ` of the InputPort to which the specification is assigned; that is, each time + `agent_rep ` is `evaluated `, the state_input_port + receives the same input that the corresponding `INPUT ` `Node ` InputPort + received during the last `TRIAL ` of execution. + + .. _OptimizationControlMechanism_Input_Port_State_Feature: + + * *InputPort specification* -- create a `state_input_port ` that + `shadows ` the input to the specified `InputPort`; that is, each time `agent_rep + ` is `evaluated `, the state_input_port receives + the same input that the specified InputPort received during the last `TRIAL ` in which the + Composition for which the OptimizationControlMechanism is the `controller ` was executed. + The specification can be any form of `InputPort specification ` for the `InpuPort` + of any `Mechanism ` that is an `INPUT ` `Node ` in the Composition + (not limited to the `agent_rep `). This includes an + `InputPort specification dictionary `, that can be used to configure the + corresponding `state_input_port `, if `Parameters ` + other than its `function ` need to be specified (which can be done directly using a + `2-item tuple ` specification or the **state_feature_function** + arg as described `below `), such as the InputPort's + `name ` or more than a single `afferent Projection `. + + .. _OptimizationControlMechanism_INPUT_Node_Specification: + + .. note:: + Only the `INPUT ` `Nodes ` of a `nested Composition ` + can be shadowed. Therefore, if the Composition that an OptimizationControlMechanism controls contains any + nested Compositions, only its `INPUT ` `Nodes ` can be specified for + shadowing in the **state_features** argument of the OptimizationControlMechanism's constructor. + + .. hint:: + Shadowing the input to a Node of a `nested Composition ` that is not an `INPUT + ` Node of that Composition can be accomplished in one or of two ways, by: a) assigning it + `INPUT ` as a `required NodeRole ` where it is added to + the nested Composition; and/or b) adding an additional Node to that Composition that shadows the desired one + (this is allowed *within* the *same* Composition), and is assigned as an `OUTPUT ` Node of + that Composition, the `OutputPort` of which which can then be specified in the **state_features** argument of + the OptimizationControlMechanism's constructor (see below). + + .. technical_note:: + The InputPorts specified as state_features are designated as `internal_only ` = `True`. + + .. _OptimizationControlMechanism_Output_Port_State_Feature: + + * *OutputPort specification* -- create a `state_input_port ` that + receives a `MappingProjection` from the specified `OutputPort`; that is, each time `agent_rep + ` is `evaluated `, the state_input_port receives + the `value ` of the specified OutputPort after the last `TRIAL ` in which the + Composition for which the OptimizationControlMechanism is the `controller ` was executed. + The specification can be any form of `OutputPort specification ` for any `OutputPort` + of a `Mechanism ` in the Composition (not limited to the `agent_rep + `. + + .. _OptimizationControlMechanism_Mechanism_State_Feature: + + * *Mechanism* -- create a `state_input_port ` that `shadows + ` the input to the `primary InputPort ` of the specified Mechanism + (this is the same as explicitly specifying the Mechanism's input_port, as described `above + `). If the Mechanism is in a `nested Composition + `, it must be an `INPUT ` `Node ` of that Composition + (see `note ` above). If the Mechanism's `OutputPort` + needs to be used, it must be specified explicitly (as described `above + `). + + .. note:: + The use of a Mechanism to specify the shadowing of its `primary InputPort ` is unique to + its specification in the **state_features** argument of an OptimizationControlMechanism, and differs from the + ordinary usage where it specifies a Projection from its `primary OutputPort ` (see + `InputPort specification `). This difference extends to the use + of a Mechanism in the *PROJECTIONS* entry of an `InputPort specification dictionary + ` used in the **state_features** argument, where there too + it designates shadowing of its `primary InputPort ` rather than a `Projection` from its + `primary OutputPort `. + + .. _OptimizationControlMechanism_Tuple_State_Feature: + + * *2-item tuple* -- the first item must be any of the forms of individual state_feature specifications + described `above `, and the second + item must be a `Function`, that is assigned as the `function ` of the corresponding + `state_input_port `; this takes precedence over + any other state_feature_function specifications (e.g., in an `InputPort specification dictionary + ` or the **state_feature_function** argument of the + OptimizationControlMechanism's constructor; see `state_feature_function + ` for additional details). + + | .. _OptimizationControlMechanism_Agent_Rep_CFA: - * *agent_rep is a CompositionFunctionApproximator* -- the **state_features** specify the inputs to the - CompositionFunctionApproximator's `evaluate ` method. This is not - done automatically (see warning below). - - .. warning:: - The **state_features** specified when the `agent_rep ` is a - `CompositionFunctionApproximator` must align with the arguments of its `evaluate - ` method. Since the latter cannot always be determined automatically, - the `state_input_ports ` cannot be created automatically, nor - can the **state_features** specification be validated; thus, specifying inappropriate **state_features** may - produce errors that are unexpected or difficult to interpret. - - COMMENT: - FIX: CONFIRM (OR IMPLEMENT?) THE FOLLOWING - If all of the inputs to the Composition are still required, these can be specified using the keyword *INPUTS*, - in which case they are retained along with any others specified. - COMMENT - - .. _OptimizationControlMechanism_State_Features_Shadow_Inputs: + **state_features** *for an agent_rep that is a* **CompositionFunctionApproximator** - The specifications in the **state_features** argument are used to construct the `state_input_ports - `, and can be any of the following, used either singly or in a list: + | - * *InputPort specification* -- this creates an `InputPort` as one of the OptimizationControlMechanism's - `state_input_ports ` that `shadows ` the - input to the specified InputPort; that is, the value of which is used as the corresponding value of the - OptimizationControlMechanism's `state_feature_values `. + The **state_features** specify the **feature_values** argument to the `CompositionFunctionApproximator`\\'s + `evaluate ` method. These cannot be determined automatically and so + they *must be specified explicitly*, in a list, with the correct number of items in the same order and with + the same shapes they are expected have in the array passed to the **feature_values** argument of the + `evaluate ` method (see warning below). - .. technical_note:: - The InputPorts specified as state_features are marked as `internal_only ` = `True`. + .. warning:: + The **state_features** for an `agent_rep ` that is a + `CompositionFunctionApproximator` cannot be created automatically nor can they be validated; + thus specifying the wrong number or invalid **state_features**, or specifying them in an incorrect + order may produce errors that are unexpected or difficult to interpret. - * *OutputPort specification* -- this can be any form of `OutputPort specification ` - for any `OutputPort` of another `Mechanism ` in the Composition; the `value ` - of the specified OutputPort is used as the corresponding value of the OptimizationControlMechanism's - `state_feature_values `. + The list of specifications can contain any of the forms of specification used for an `agent_rep + ` that is a Composition as described `above + `, with the following exception: if a + `Mechanism` is specified, its `primary OutputPort ` is used (rather than + shadowing its primary InputPort), since that is more typical usage, and there are no assumptions + made about the state features of a `CompositionFunctionApproximator` (as there are about a Composition + as `agent_rep `); if the input to the Mechanism *is* to be + `shadowed `, then its InputPort must be specified explicitly (as described + `above `). - * *Mechanism* -- if the `agent_rep ` is a Composition, it must be an - `INPUT ` `Node ` of that Composition, and the Mechanism's `primary InputPort - ` is used (since in this case the state_feature must correspond to an input to the Composition). - If the `agent_rep ` is a `CompositionFunctionApproximator`, then the - Mechanism's `primary OutputPort ` is used (since is the typically usage for specifying an - InputPort); if the input to the Mechanism is to be shadowed, then its InputPort must be specified explicitly. +| - COMMENT: - FIX: CONFIRM THAT THE FOLLOWING ALL WORK - COMMENT - State features can also be added to an existing OptimizationControlMechanism using its `add_state_features` method. - -.. _OptimizationControlMechanism_State_Feature_Functions_Arg: - -* **state_feature_functions** -- specifies the `function(s) ` assigned to the `state_input_ports - ` created for each of the corresponding **state_features**. - If **state_feature_functions** is not specified, the identity function is assigned to all of the `state_input_ports - ` (whether those were created automatically or explicitly specified; - see `above `). However, other functions can be specified - individually for the `state_input_ports ` associated with each - state_feature. This can be useful, for example to provide an average or integrated value of prior inputs, to - select specific inputs for use (see `hint ` above), and/or use a - generative model of the environment to provide inputs to the `agent_rep ` - during the optimization process. This can be done by specifying the **state_feature_functions** argument with a - dict with keys that match each of the specifications in the **state_features** argument, and corresponding values - that specify the function to use for each. +.. _OptimizationControlMechanism_State_Feature_Function_Arg: + +* **state_feature_function** -- specifies a `function ` to be used as the default + function for `state_input_ports `. This is assigned as + the `function ` to any state_input_ports for which *no other* `Function` is specified -- + that is, in either an `InputPort specification dictionary ` or a `2-item tuple + ` in the **state_features** argument (see `state_features + `). If either of the latter is specified, they override + the specification in **state_feature_function**. If **state_feature_function** is *not* specified, then + `LinearCombination` (the standard default `Function` for an `InputPort`) is assigned to any `state_input_ports + ` that are not otherwise assigned a `Function`. + Specifying functions for `state_input_ports ` can be useful, + for example to provide an average or integrated value of prior inputs to the `agent_rep + `\\'s `evaluate ` method during the optimization + process, or to use a generative model of the environment to provide those inputs. .. note:: - A dict can be used to specify **state_feature_functions** only if **state_features** are specified explicitly - (see `above `). The dict must contain one entry for - each of the items specified in **state_features**, and the value returned by each function must preserve the - shape of its input, which must match that of the corresponding input to the Composition's `run - ` method (see `note ` above). + The value returned by a function assigned to the **state_feature_function** argument must preserve the + shape of its input, and must also accommodate the shape of the inputs to all of the `state_input_ports + ` to which it is assigned (see `note + ` above). .. _OptimizationControlMechanism_Outcome_Args: @@ -429,14 +610,52 @@ *State* ~~~~~~~ -The current state of the OptimizationControlMechanism -- or, more properly, its `agent_rep +The current state of the OptimizationControlMechanism -- or, more properly, of its `agent_rep ` -- is determined by the OptimizationControlMechanism's current `state_feature_values ` (see `below -`) and `control_allocation `. -These are provided as input to the `evaluate_agent_rep ` method, -the results of which are used together with the `costs ` associated with the +`) and `control_allocation `. +These are used by the `evaluate_agent_rep ` method, +the results of which are combined with the `costs ` associated with the `control_allocation `, to evaluate the `net_outcome -` for that state. +` for that state. The current state is listed in the OptimizationControlMechanism's +`state ` attribute, and `state_dict ` +contains the Components associated with each value of `state `. + +COMMENT: + > Attributes that pertain to the state of the agent_rep for a given evaluation: + state_feature_specs: a list of the sources for state_feature_values, one for each InputPort of each INPUT Node of the agent_rep + (at all levels of nesting); None for any sources not specified in **state_features** + (corresponding InputPorts are are assigned their default input when agent_rep.evaluate() is executed). + state_feature_values: a dict with entries for each item specified in **state_features** arg of constructor, + in which the key of each entry is an InputPort of an INPUT Node of agent_rep (at any level of nesting) + and the value is the current value of the corresponding state_input_port; the dict is suitable for + use as the **predicted_inputs** or **feature_values** arg of the agent_rep's evaluate() method + (depending on whether the agent_rep is a Composition or a CFA); + note: there are not entries for InputPorts of INPUT Nodes that are not specified in **state_features**; + those are assigned either their default input values (LINK XXX) or the shadowed input of + the corresponding INPUT Node InputPort (LINK XXX), depending on how **state_features** was formatted; + (see LINK XXX for details of formatting). + state_features: a dict with entries corresponding to each item of state_feature_specs, + the keys of which are InputPorts of the INPUT Nodes of the agent_rep, + and values of which are the corresponding state_feature_specs + (i.e., sources of input for those InputPorts when evaluate() is called); + control_allocation: a list of the current values of the OCM's control_signals that are used to modulate the Parameters + specified for control when the agent_rep's evaluate() method is called; + state: a list of the values of the current state, starting with state_feature_values and ending with + control_allocations + state_dict: a dictionary with entries for each state_feature and ControlSignal, keys?? values?? + their source/destination, and their current values + > Constituents of state specifications: + - agent_rep_input_port: an InputPort of an INPUT Node of the agent_rep, + that will receive a value from state_feature_values passed to agent_rep.evaluate() + - source: the source of the input to an agent_rep_input_port, + that sends a Projection to the corresponding state_input_port + + > Relationship of numeric spec to ignoring it (i.e. assigning it None): + allows specification of value as input *just* for simulations (i.e., agent_rep_evaluate) + and not normal execution of comp + +COMMENT .. _OptimizationControlMechanism_Input: @@ -450,9 +669,9 @@ is used to execute it; and `outcome_input_ports ` that provide the outcome of executing the `agent_rep `, that is used to compute the `net_outcome ` for the `control_allocation ` under which the -execution occurred. Each of these is described below. +execution occurred. Each of these is described below. -.. _OptimizationControlMechanism_State_Features: +.. _OptimizationControlMechanism_State_Input_Ports: *state_input_ports* ~~~~~~~~~~~~~~~~~~~ @@ -461,14 +680,20 @@ from the Components specified as the OptimizationControlMechanism's `state_features `, the values of which are assigned as the `state_feature_values `, and conveyed to the `agent_rep -` when it is `executed `. If the -`agent_rep is a `Composition `, then the -OptimizationControlMechanism has a state_input_port for every `InputPort` of every `INPUT ` `Node -` of the `agent_rep ` Composition, each of which receives -a `Projection` that `shadows the input ` of the corresponding state_feature. If the -`agent_rep is a CompositionFunctionApproximator `, -then the OptimizationControlMechanism has a state_input_port that receives a Projection from each Component specified -in the **state_features** arg of its constructor. +`\\'s `evaluate ` method when it is `executed +`. The OptimizationControlMechanism has a `state_input_port +` for every specification in the **state_features** arg of its +constructor (see `above `). + +COMMENT: +OLD +If the `agent_rep is a Composition `, then the +OptimizationControlMechanism has a state_input_port for every specification in the **state_features** arg of its +constructor (see `above `). If the `agent_rep is a +CompositionFunctionApproximator `, then the OptimizationControlMechanism +has a state_input_port that receives a Projection from each Component specified in the **state_features** arg of its +constructor. +COMMENT COMMENT: In either, case the the `values ` of the @@ -480,15 +705,15 @@ State features can be of two types: -* *Input Features* -- these are values that shadow the input received by a `Mechanisms ` in the - `Composition` for which the OptimizationControlMechanism is a `controller ` (irrespective - of whether that is the OptimizationControlMechanism`s `agent_rep `). - They are implemented as `shadow InputPorts ` (see - `OptimizationControlMechanism_State_Features_Shadow_Inputs` for specification) that receive a - `Projection` from the same source as the Mechanism being shadowed. +* *Input Features* -- these are values that either shadow the input received by an `InputPort` of a `Mechanisms + ` in the `Composition` for which the OptimizationControlMechanism is a `controller + ` (irrespective of whether that is the OptimizationControlMechanism`s `agent_rep + `). They are implemented as `shadow InputPorts ` + (see `OptimizationControlMechanism_SHADOW_INPUTS_State_Feature` for specification) that receive a `Projection` + from the same source as the Mechanism being shadowed. .. -* *Output Features* -- these are the `value ` of an `OutputPort` of `Mechanism ` in the - `Composition` for which the OptimizationControlMechanism is a `controller ` (again, +* *Output Features* -- these are the `value ` of an `OutputPort` of a `Mechanism ` in + the `Composition` for which the OptimizationControlMechanism is a `controller ` (again, irrespective of whether it is the OptimizationControlMechanism`s `agent_rep `); and each is assigned a `Projection` from the specified OutputPort(s) to the InputPort of the OptimizationControlMechanism for that feature. @@ -533,7 +758,7 @@ ` are distinct from, and should not be confused with the `objective_function ` parameter of the OptimizationControlMechanism's `function `. The `objective_mechanism `\\'s - `function ` evaluates the `outcome ` of processing + `function ` evaluates the `outcome ` of processing without taking into account the `costs ` of the OptimizationControlMechanism's `control_signals `. In contrast, its `evaluate_agent_rep ` method, which is assigned as the `objective_function` @@ -562,20 +787,21 @@ then its `outcome_input_ports ` are determined by its `monitor_for_control ` and `outcome_input_ports_option ` attributes, specified in the corresponding arguments of its -constructor (see `Outcomes arguments `), and the `allow_probes -` attribute of the Composition for which the OptimizationControlMechanism is the -`controller `. The latter allows the values of the items listed in `monitor_for_control -` to be `INPUT ` or `INTERNAL ` `Nodes -` of a `nested Composition ` to be monitored and included in the computation -of `outcome ` (ordinarily, those must be `OUTPUT ` Nodes of a nested -Composition). This can be thought of as providing access to "latent variables" of the Composition being evaluated; -that is, ones that do not contribute directly to the Composition's `results `. This -applies both to items that are monitored directly by the OptimizationControlMechanism or via its ObjectiveMechanism -(see `allow_probes ` above for additional details). - -The value(s) of the specified Components are assigned as the OptimizationControlMechanism's `outcome -` attribute, which is used to compute the `net_outcome ` -of executing its `agent_rep `. +constructor (see `Outcomes arguments `). The value(s) of the specified +Components are assigned as the OptimizationControlMechanism's `outcome ` attribute, +which is used to compute the `net_outcome ` of executing its `agent_rep +`. + + .. note:: + If a `Node ` other than an `OUTPUT ` of a `nested ` + Composition is `specified to be monitored `, it is assigned as a `PROBE + ` of that nested Composition. Although `PROBE ` Nodes are generally treated + like `OUTPUT ` Nodes (since they project out of the Composition to which they belong), their + `value ` is not included in the `output_values ` or `results + ` attributes of the Composition for which the OptimizationControlMechanism is the + `controller `, unless that Composition's `include_probes_in_output + ` attribute is set to True (see Probes `Composition_Probes` for additional + information). .. _OptimizationControlMechanism_Function: @@ -607,7 +833,7 @@ - It must accept as its first argument and return as its result an array with the same shape as the OptimizationControlMechanism's `control_allocation `. .. - - It must execute the OptimizationControlMechanism's `evaluate_agent_rep + - It must be able to execute the OptimizationControlMechanism's `evaluate_agent_rep ` `num_estimates ` times, and aggregate the results in computing the `net_outcome ` for a given `control_allocation ` (see @@ -661,14 +887,19 @@ *Randomization ControlSignal* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If `num_estimates ` is specified (that is, it is not None), -a `ControlSignal` is automatically added to the OptimizationControlMechanism's `control_signals -`, named *RANDOMIZATION_CONTROL_SIGNAL*, that randomizes -the values of random variables in the `agent_rep ` over estimates of its -`net_outcome `. The `initial_seed ` and -`same_seed_for_all_allocations ` Parameters can also be -used to further refine randomization (see `OptimizationControlMechanism_Estimation_Randomization` for additional -details). +If `num_estimates ` is specified (that is, it is not None), and +`agent_rep ` has any `Components ` with random variables +(that is, that call a randomization function) specified in the OptimizationControlMechanism's `random_variables +` attribute, then a `ControlSignal` is automatically added to the +OptimizationControlMechanism's `control_signals `, named +*RANDOMIZATION_CONTROL_SIGNAL*, that randomizes the values of the `random variables +` over estimates of its `net_outcome ` +for each `control_allocation ` If `num_estimates +` is specified but `agent_rep ` +has not random variables, then a warning is issued and no *RANDOMIZATION_CONTROL_SIGNAL* is constructed. The +`initial_seed ` and `same_seed_for_all_allocations +` Parameters can also be used to further refine +randomization (see `OptimizationControlMechanism_Estimation_Randomization` for additional details). .. technical_note:: @@ -694,6 +925,20 @@ of the Composition or executing the CompositionFunctionApproximator that is its `agent_rep `. +.. _OptimizationControlMechanism_Execution_Timing: + +*Timing of Execution* +^^^^^^^^^^^^^^^^^^^^^ + +When the OptimizationControlMechanism is executed is determined by the `controller_mode ` +of the Composition for which the OptimizationControlMechanism is the `controller `: if it is +set to *AFTER* (the default), the OptimizationControlMechanism is executed at the end of a `TRIAL `, +after the Composition has executed, using `state_feature_value ` +(including any inputs to the Composition) for that `TRIAL `; if the `controller_mode +` is *BEFORE*, then the OptimizationControlMechanism is executed before the Composition +that it controls, using `state_feature_value ` (including any inputs +to the Composition) from the previous `TRIAL `. + .. _OptimizationControlMechanism_Optimization_Procedure: *Optimization Procedure* @@ -727,12 +972,15 @@ to select one from its `search_space `), and evaluates the `net_outcome ` for that `control_allocation `. It does this by calling the OptimizationControlMechanism's `evaluate_agent_rep - ` method `num_estimates ` times, - each with the current `state_feature_values ` as its input, - and executing it for `num_trials_per_estimate ` trials - for each estimate. The `control_allocation ` remains fixed for each - estimate, but the random seed of any Parameters that rely on randomization is varied, so that the values of those - Parameters are randomly sampled for every estimate (see `OptimizationControlMechanism_Estimation_Randomization`). + ` method `num_estimates ` + times, each of which uses the `state_feature_values ` + and `control_allocation ` as the input to the `agent_rep + `\\'s `evaluate ` method, executing it for + `num_trials_per_estimate ` trials for each estimate. + The `state_feature_values ` and `control_allocation + ` remain fixed for each estimate, but the random seeds of any Parameters + that rely on randomization are varied, so that the values of those Parameters are randomly sampled for every + estimate (see `OptimizationControlMechanism_Estimation_Randomization`). * *Aggregation* - the `function `\\'s `aggregation_function ` is used to aggregate the `net_outcome @@ -765,14 +1013,14 @@ ` times (i.e., by that number of calls to the OptimizationControlMechanism's `evaluate_agent_rep ` method). The values of Components listed in the OptimizationControlMechanism's `random_variables -` attribute are randomized over thoese estimates. By default, -this includes all Components in the `agent_rep ` with random variables (listed -in its `random_variables ` attribute). However, if particular Components are specified -in the **random_variables** argument of the OptimizationControlMechanism's constructor, then randomization is -restricted to their values. Randomization over estimates can be further configured using the `initial_seed -` and `same_seed_for_all_allocations -` attributes. The results of all the estimates for a given -`control_allocation ` are aggregated by the `aggregation_function +` attribute are randomized over those estimates. By default, +this includes all Components in the `agent_rep ` with random variables +(listed in its `random_variables ` attribute). However, if particular Components +are specified in the **random_variables** argument of the OptimizationControlMechanism's constructor, then +randomization is restricted to their values. Randomization over estimates can be further configured using the +`initial_seed ` and `same_seed_for_all_allocations +` attributes. The results of all the estimates for a +given `control_allocation ` are aggregated by the `aggregation_function ` of the `OptimizationFunction` assigned to the OptimizationControlMechanism's `function `, and used to compute the `net_outcome ` over the estimates for that `control_allocation ` @@ -824,15 +1072,16 @@ import copy import warnings from collections.abc import Iterable +from typing import Union import numpy as np import typecheck as tc from psyneulink.core import llvm as pnlvm -from psyneulink.core.components.component import DefaultsFlexibility +from psyneulink.core.components.component import DefaultsFlexibility, Component from psyneulink.core.components.functions.function import is_function_type from psyneulink.core.components.functions.nonstateful.optimizationfunctions import \ - GridSearch, OBJECTIVE_FUNCTION, SEARCH_SPACE + GridSearch, OBJECTIVE_FUNCTION, SEARCH_SPACE, RANDOMIZATION_DIMENSION from psyneulink.core.components.functions.nonstateful.transferfunctions import CostFunctions from psyneulink.core.components.mechanisms.mechanism import Mechanism from psyneulink.core.components.mechanisms.modulatory.control.controlmechanism import \ @@ -840,35 +1089,128 @@ from psyneulink.core.components.ports.inputport import InputPort, _parse_shadow_inputs from psyneulink.core.components.ports.modulatorysignals.controlsignal import ControlSignal from psyneulink.core.components.ports.outputport import OutputPort -from psyneulink.core.components.ports.port import _parse_port_spec, _instantiate_port +from psyneulink.core.components.ports.port import _parse_port_spec, _instantiate_port, Port from psyneulink.core.components.shellclasses import Function from psyneulink.core.globals.context import Context, ContextFlags from psyneulink.core.globals.context import handle_external_context from psyneulink.core.globals.defaults import defaultControlAllocation from psyneulink.core.globals.keywords import \ - ALL, COMPOSITION, COMPOSITION_FUNCTION_APPROXIMATOR, CONCATENATE, DEFAULT_VARIABLE, EID_FROZEN, \ - FUNCTION, INTERNAL_ONLY, OPTIMIZATION_CONTROL_MECHANISM, OWNER_VALUE, PARAMS, PROJECTIONS, \ - SHADOW_INPUTS, SHADOW_INPUT_NAME + ALL, COMPOSITION, COMPOSITION_FUNCTION_APPROXIMATOR, CONCATENATE, DEFAULT_INPUT, DEFAULT_VARIABLE, EID_FROZEN, \ + FUNCTION, INPUT_PORT, INTERNAL_ONLY, NAME, OPTIMIZATION_CONTROL_MECHANISM, NODE, OWNER_VALUE, PARAMS, PORT, \ + PROJECTIONS, SHADOW_INPUTS, VALUE +from psyneulink.core.globals.registry import rename_instance_in_registry from psyneulink.core.globals.parameters import Parameter from psyneulink.core.globals.preferences.preferenceset import PreferenceLevel from psyneulink.core.globals.sampleiterator import SampleIterator, SampleSpec -from psyneulink.core.globals.utilities import convert_to_list, convert_to_np_array, ContentAddressableList +from psyneulink.core.globals.utilities import convert_to_list, ContentAddressableList, is_numeric from psyneulink.core.llvm.debug import debug_env __all__ = [ 'OptimizationControlMechanism', 'OptimizationControlMechanismError', - 'AGENT_REP', 'STATE_FEATURES', 'STATE_FEATURE_FUNCTIONS', 'RANDOMIZATION_CONTROL_SIGNAL' + 'AGENT_REP', 'STATE_FEATURES', 'STATE_FEATURE_FUNCTION', 'RANDOMIZATION_CONTROL_SIGNAL', 'NUM_ESTIMATES', + 'DEFERRED_STATE_INPUT_PORT_PREFIX', 'NUMERIC_STATE_INPUT_PORT_PREFIX', 'SHADOWED_INPUT_STATE_INPUT_PORT_PREFIX', + 'INPUT_SOURCE_FOR_STATE_INPUT_PORT_PREFIX' ] +# constructor arguments AGENT_REP = 'agent_rep' STATE_FEATURES = 'state_features' -STATE_FEATURE_FUNCTIONS = 'state_feature_functions' +STATE_FEATURE_FUNCTION = 'state_feature_function' RANDOMIZATION_CONTROL_SIGNAL = 'RANDOMIZATION_CONTROL_SIGNAL' RANDOM_VARIABLES = 'random_variables' +NUM_ESTIMATES = 'num_estimates' + +# state_input_port names +NUMERIC_STATE_INPUT_PORT_PREFIX = "NUMERIC INPUT FOR " +INPUT_SOURCE_FOR_STATE_INPUT_PORT_PREFIX = "SOURCE OF INPUT FOR " +SHADOWED_INPUT_STATE_INPUT_PORT_PREFIX = "SHADOWED INPUT OF " +# SHADOWED_INPUT_STATE_INPUT_PORT_PREFIX = "Shadowed input of " +DEFERRED_STATE_INPUT_PORT_PREFIX = 'DEFERRED INPUT NODE InputPort ' + +def _state_input_port_name(source_port_name, agent_rep_input_port_name): + return f"INPUT FROM {source_port_name} FOR {agent_rep_input_port_name}" + +def _shadowed_state_input_port_name(shadowed_port_name, agent_rep_input_port_name): + return f"{SHADOWED_INPUT_STATE_INPUT_PORT_PREFIX}{shadowed_port_name} FOR {agent_rep_input_port_name}" + +def _numeric_state_input_port_name(agent_rep_input_port_name): + return f"{NUMERIC_STATE_INPUT_PORT_PREFIX}{agent_rep_input_port_name}" + +def _deferred_agent_rep_input_port_name(node_name, agent_rep_name): + # return f"{DEFERRED_STATE_INPUT_PORT_PREFIX}{node_name} OF {agent_rep_name}" + return f"{DEFERRED_STATE_INPUT_PORT_PREFIX}OF {agent_rep_name} ({node_name})" + +def _deferred_state_feature_spec_msg(spec_str, comp_name): + return f"{spec_str} NOT (YET) IN {comp_name}" + +def _not_specified_state_feature_spec_msg(spec_str, comp_name): + return f"NO SPECIFICATION (YET) FOR {spec_str} IN {comp_name}" + +def _state_feature_values_getter(owning_component=None, context=None): + """Return dict {agent_rep INPUT Node InputPort: value} suitable for **predicted_inputs** arg of evaluate method. + Only include entries for sources specified in **state_features**, corresponding to OCM's state_input_ports; + default input will be assigned for all other INPUT Node InputPorts in composition._instantiate_input_dict(). + """ + + # FIX: REFACTOR TO DO VALIDATIONS ON INIT AND INITIAL RUN-TIME CHECK + # AND SIMPLY RETURN VALUES (WHICH SHOULD ALL BE ASSIGNED BY RUN TIME) DURING EXECUTION / SIMULATIONS + + # If no state_input_ports return empty list + if (not owning_component.num_state_input_ports): + return {} + + # Get sources specified in **state_features** + specified_state_features = [spec for spec in owning_component.state_feature_specs if spec is not None] + # Get INPUT Node InputPorts for sources specified in **state_features** + specified_INPUT_Node_InputPorts = [port for port, spec + in zip(owning_component._specified_INPUT_Node_InputPorts_in_order, + owning_component.state_feature_specs) + if spec is not None] + num_agent_rep_input_ports = len(owning_component._get_agent_rep_input_receivers()) + + assert len(specified_state_features) == \ + len(specified_INPUT_Node_InputPorts) == \ + owning_component.num_state_input_ports + + # Construct state_feature_values dict + state_feature_values = {} + for i in range(owning_component.num_state_input_ports): + key = specified_INPUT_Node_InputPorts[i] + state_input_port = owning_component.state_input_ports[i] + spec = specified_state_features[i] + + # Get key + if not isinstance(key, InputPort): + # INPUT Node InputPort is not fully or properly specified + key = _deferred_agent_rep_input_port_name((key or str(i - num_agent_rep_input_ports)), + owning_component.agent_rep.name) + elif key not in owning_component._get_agent_rep_input_receivers(): + # INPUT Node InputPort is not (yet) in agent_rep + key = _deferred_agent_rep_input_port_name(key.full_name, owning_component.agent_rep.name) + + # Get state_feature_value + if spec is None: + # state_feature not specified; default input will be assigned in _instantiate_input_dict() + state_feature_value = _not_specified_state_feature_spec_msg((key if isinstance(key, str) else key.full_name), + owning_component.composition.name) + elif is_numeric(spec): + # if spec is numeric, use that + state_feature_value = state_input_port.function(spec) + elif (hasattr(owning_component, 'composition') + and not owning_component.composition._is_in_composition(spec)): + # spec is not in ocm.composition + state_feature_value = _deferred_state_feature_spec_msg(spec.full_name, owning_component.agent_rep.name) + elif state_input_port.parameters.value._get(context) is not None: + # if state_input_port returns a value, use that + state_feature_value = state_input_port.parameters.value._get(context) + else: + # otherwise use state_input_port's default input value + state_feature_value = state_input_port.default_input_shape + + state_feature_values[key] = state_feature_value + + return state_feature_values -def _parse_state_feature_values_from_variable(index, variable): - """Return values of state_input_ports""" - return convert_to_np_array(np.array(variable[index:]).tolist()) class OptimizationControlMechanismError(Exception): def __init__(self, error_value): @@ -885,13 +1227,13 @@ def _control_allocation_search_space_getter(owning_component=None, context=None) else: return search_space + class OptimizationControlMechanism(ControlMechanism): """OptimizationControlMechanism( \ agent_rep=None, \ state_features=None, \ - state_feature_functions=None, \ + state_feature_function=None, \ monitor_for_control=None, \ - allow_probes=False, \ objective_mechanism=None, \ function=GridSearch, \ num_estimates=1, \ @@ -915,18 +1257,23 @@ class OptimizationControlMechanism(ControlMechanism): Arguments --------- - state_features : Mechanism, InputPort, OutputPort, Projection, dict, or list containing any of these - specifies Components for which `state_input_ports ` - are created, the `values ` of which are assigned to `state_feature_values - ` and used to predict `net_outcome - `. Any `InputPort specification ` - can be used that resolves to an `OutputPort` that projects to that InputPort (see - `state_features ` for additional details>). + state_features : Mechanism, InputPort, OutputPort, Projection, numeric value, dict, or list containing any of these + specifies the Components from which `state_input_ports ` + receive their inputs, the `values ` of which are assigned to `state_feature_values + ` and provided as input to the `agent_rep + 's `evaluate ` method when it is executed. + See `state_features ` for details of specification. + + state_feature_default : same as state_features : default None + specifies the default used if a state_feature is not otherwise specified for the `InputPort` of an + `INPUT ` `Node ` of `agent_rep `. + (see `state_feature_default ` and + `state_features ` for additional details). - state_feature_functions : Function or function : default None - specifies the `function ` assigned the `InputPort` in `state_input_ports - ` assigned to each **state_feature** - (see `state_feature_functions ` for additional details). + state_feature_function : Function or function : default None + specifies the `function ` to use as the default function for the `state_input_ports + ` created for the corresponding **state_features** (see + `state_feature_function ` for additional details). agent_rep : None or Composition : default None or Composition to which OptimizationControlMechanism is assigned specifies the `Composition` used by `evaluate_agent_rep ` @@ -940,18 +1287,22 @@ class OptimizationControlMechanism(ControlMechanism): the `agent_rep `. num_estimates : int : 1 - specifies the number independent runs of `agent_rep ` used - to estimate its `net_outcome ` for each `control_allocation - ` sampled (see `num_estimates + specifies the number independent runs of `agent_rep ` randomized + over **random_variables** and used to estimate its `net_outcome ` for each + `control_allocation ` sampled (see `num_estimates ` for additional information). random_variables : Parameter or list[Parameter] : default ALL - specifies the Components with random variables to be randomized over different estimates - of each `control_allocation `; these must be in the `agent_rep - ` and have a `seed` `Parameter`. By default, all such Components in - the `agent_rep ` (listed in its `random_variables - ` attribute) are included (see `random_variables - ` for additional information). + specifies the Components of `agent_rep ` with random variables to be + randomized over different estimates of each `control_allocation `; these + must be in the `agent_rep ` and have a `seed` `Parameter`. By default, + all such Components (listed in its `random_variables ` attribute) are included + (see `random_variables ` for additional information). + + .. note:: + if **num_estimates** is specified but `agent_rep ` has no + `random variables `, a warning is generated and `num_estimates + ` is set to None. initial_seed : int : default None specifies the seed used to initialize the random number generator at construction. @@ -1011,22 +1362,54 @@ class OptimizationControlMechanism(ControlMechanism): agent_rep_type : None, COMPOSITION or COMPOSITION_FUNCTION_APPROXIMATOR identifies whether the agent_rep is a `Composition`, a `CompositionFunctionApproximator` or - one of its subclasses, or it has not been assigned (None); see `Agent Representation and Types - of Optimization ` for additional details. + one of its subclasses, or it has not been assigned (None) (see `Agent Representation and Types + of Optimization ` for additional details). + + state_features : Dict[Node:source] + dictionary in which keys are all `external InputPorts ` for `agent_rep + `, and values are the sources of their input specified in + **state_features**. These are provided as the inputs to `state_input_ports + `, the `values ` + of which are assigned to `state_feature_values ` and + provided to the `agent_rep `\\'s `evaluate ` + method when it is executed (see `state_features ` and + `OptimizationControlMechanism_State_Input_Ports` for additional details). + + state_feature_default : Mechanism, InputPort, OutputPort, Projection, dict, SHADOW_INPUTS, numeric value + determines the default used if the state_feature (i.e. source) is not otherwise specified for the `InputPort` of + an `INPUT ` `Node ` of `agent_rep `. + If it is None, then no corresponding `state_input_port ` + is created for that InputPort, and its `default variable ` is used as its input when the + `agent_rep `\\'s `evaluate ` method is executed + (see `state_features ` for additional details). state_feature_values : 2d array - the current value of each item of the OptimizationControlMechanism's - `OptimizationControlMechanism_State_Features` (each of which is a 1d array). + a dict containing the current values assigned as the input to the InputPorts of the `INPUT ` + `Nodes ` of the `agent_rep ` when its `evaluate + ` method is executed. For each such InputPort, if a `state_feature + ` has been specified for it, then its value in + state_feature_values is the `value ` of the corresponding `state_input_port + `. There are no entries for InputPorts for which the + **state_features** specification is ``None`` or it has not been otherwise specified; for those InputPorts, + their `default_variable ` is assigned directly as their input when `agent_rep + ` is `evaluated ` (see + `OptimizationControlMechanism_State_Input_Ports` for additional details). + + state_feature_function : Function of function + determines the `function ` used as the default function for + `state_input_ports ` (see `state_feature_function + ` for additional details). state_input_ports : ContentAddressableList lists the OptimizationControlMechanism's `InputPorts ` that receive `Projections ` - from the items specified in the **state_features** argument in the OptimizationControlMechanism's constructor - or constructed automatically (see `state_features `), and - that provide the `state_feature_values ` to the `agent_rep - ` (see `OptimizationControlMechanism_State_Features` for additional details). + from the items specified in the **state_features** argument in the OptimizationControlMechanism's constructor, + or constructed automatically (see `state_features `), the + values of which are assigned to `state_feature_values ` + and provided as input to the `agent_rep 's `evaluate + ` method (see `OptimizationControlMechanism_State_Input_Ports` for additional details). num_state_input_ports : int - cantains the number of `state_input_ports `. + contains the number of `state_input_ports `. outcome_input_ports : ContentAddressableList lists the OptimizationControlMechanism's `OutputPorts ` that receive `Projections ` @@ -1036,6 +1419,24 @@ class OptimizationControlMechanism(ControlMechanism): ` in a given `OptimizationControlMechanism_State` (see `Outcome ` for additional details). + state : ndarray + lists the values of the current state -- a concatenation of the `state_feature_values + ` and `control_allocation + ` following the last execution of `agent_rep + `. + + state_dict : Dict[(Port, Mechanism, Composition, index)):value] + dictionary containing information about the Components corresponding to the values in `state + `. Keys are (`Port`, `Mechanism`, `Composition`, index) tuples, + identifying the source of the value for each item at the corresponding index in + `state `, and values are its value in `state + `. The initial entries are for the OptimizationControlMechanism's + `state features `, that are the sources of its + `state_feature_values `; they are followed + by entries for the parameters modulated by the OptimizationControlMechanism's `control_signals + ` with the corresponding `control_allocation + ` values. + num_estimates : int determines the number independent runs of `agent_rep ` (i.e., calls to `evaluate_agent_rep `) used to estimate the `net_outcome @@ -1045,8 +1446,9 @@ class OptimizationControlMechanism(ControlMechanism): `OptimizationControlMechanism_Estimation_Randomization` for additional details. random_variables : Parameter or List[Parameter] - list of the Components with variables that are randomized over estimates for a given `control_allocation - `; by default, all Components in the `agent_rep + list of the `Parameters ` in `agent_rep ` with random + variables (that is, ones that call a randomization function) that are randomized over estimates for a given + `control_allocation `; by default, all Components in the `agent_rep ` with random variables are included (listed in its `random_variables ` attribute); see `OptimizationControlMechanism_Estimation_Randomization` for additional details. @@ -1147,7 +1549,8 @@ class OptimizationControlMechanism(ControlMechanism): ` specifications for each of the OptimizationControlMechanism's `control_signals `, and includes the *RANDOMIZATION_CONTROL_SIGNAL* used to randomize estimates of each `control_allocation - ` (see `note ` above). + ` (see `note ` + above). saved_samples : list contains all values of `control_allocation ` sampled by `function @@ -1181,7 +1584,6 @@ class OptimizationControlMechanism(ControlMechanism): # PREFERENCE_SET_NAME: 'DefaultControlMechanismCustomClassPreferences', # PREFERENCE_KEYWORD: ...} - # FIX: ADD OTHER Parameters() HERE?? class Parameters(ControlMechanism.Parameters): """ Attributes @@ -1205,12 +1607,6 @@ class Parameters(ControlMechanism.Parameters): :default value: None :type: - state_feature_functions - see `state_feature_functions ` - - :default value: None - :type: - function see `function ` @@ -1236,6 +1632,12 @@ class Parameters(ControlMechanism.Parameters): :default value: None :type: + outcome_input_ports_option + see `outcome_input_ports_option ` + + :default value: None + :type: + saved_samples see `saved_samples ` @@ -1265,23 +1667,51 @@ class Parameters(ControlMechanism.Parameters): :default value: None :type: + + state_feature_specs + This is for internal use only, including population of the state_features property + (see `state_features `) + + :default value: SHADOW_INPUTS + :type: ``dict`` + + state_feature_default_spec + This is a shell parameter to validate its assignment and explicity user specification of None + to override Parameter default; its .spec attribute is assigned to the user-facing + self.state_feature_default (see `state_feature_default `). + + :default value: SHADOW_INPUTS + :type: + + state_feature_function + see `state_feature_function ` + + :default value: None + :type: + + state_input_ports + see `state_input_ports ` + + :default value: None + :type: ``list`` """ + agent_rep = Parameter(None, stateful=False, loggable=False, pnl_internal=True, structural=True) + state_input_ports = Parameter(None, reference=True, stateful=False, loggable=False, read_only=True) + state_feature_specs = Parameter(SHADOW_INPUTS, stateful=False, loggable=False, read_only=True, + structural=True, parse_spec=True) + state_feature_default_spec = Parameter(SHADOW_INPUTS, stateful=False, loggable=False, read_only=True, + structural=True) + state_feature_function = Parameter(None, reference=True, stateful=False, loggable=False) + state_feature_values = Parameter(None,getter=_state_feature_values_getter, + user=False, pnl_internal=True, read_only=True) outcome_input_ports_option = Parameter(CONCATENATE, stateful=False, loggable=False, structural=True) function = Parameter(GridSearch, stateful=False, loggable=False) - state_feature_functions = Parameter(None, reference=True, stateful=False, loggable=False) search_function = Parameter(None, stateful=False, loggable=False) search_space = Parameter(None, read_only=True) search_termination_function = Parameter(None, stateful=False, loggable=False) comp_execution_mode = Parameter('Python', stateful=False, loggable=False, pnl_internal=True) search_statefulness = Parameter(True, stateful=False, loggable=False) - agent_rep = Parameter(None, stateful=False, loggable=False, pnl_internal=True, structural=True) - - # FIX: NEED TO MODIFY IF OUTCOME InputPorts ARE MOVED (CHANGE 1 to 0? IF STATE_INPUT_PORTS ARE FIRST) - state_feature_values = Parameter(_parse_state_feature_values_from_variable(1, [defaultControlAllocation]), - user=False, - pnl_internal=True) - # FIX: Should any of these be stateful? random_variables = ALL initial_seed = None @@ -1300,20 +1730,32 @@ class Parameters(ControlMechanism.Parameters): saved_samples = None saved_values = None + def _validate_state_feature_default_spec(self, state_feature_default): + if not (isinstance(state_feature_default, (InputPort, OutputPort, Mechanism)) + or state_feature_default in {SHADOW_INPUTS} + or is_numeric(state_feature_default) + or state_feature_default is None): + return f"must be an InputPort, OutputPort, Mechanism, Composition, SHADOW_INPUTS or a list or array " \ + f"with a shape appropriate for all of the INPUT Nodes or InputPorts to which it will be applied." + @handle_external_context() @tc.typecheck def __init__(self, agent_rep=None, - state_features: tc.optional(tc.optional(tc.any(Iterable, Mechanism, OutputPort, InputPort))) = None, - state_feature_functions: tc.optional(tc.optional(tc.any(dict, is_function_type))) = None, + state_features: tc.optional((tc.any(str, Iterable, InputPort, + OutputPort, Mechanism)))=SHADOW_INPUTS, + # state_feature_default=None, + state_feature_default: tc.optional((tc.any(str, Iterable, + InputPort, OutputPort,Mechanism)))=SHADOW_INPUTS, + state_feature_function: tc.optional(tc.optional(tc.any(dict, is_function_type)))=None, function=None, - num_estimates = None, - random_variables = None, + num_estimates=None, + random_variables=None, initial_seed=None, same_seed_for_all_allocations=None, - num_trials_per_estimate = None, - search_function: tc.optional(tc.optional(tc.any(is_function_type))) = None, - search_termination_function: tc.optional(tc.optional(tc.any(is_function_type))) = None, + num_trials_per_estimate=None, + search_function: tc.optional(tc.optional(tc.any(is_function_type)))=None, + search_termination_function: tc.optional(tc.optional(tc.any(is_function_type)))=None, search_statefulness=None, context=None, **kwargs): @@ -1323,28 +1765,27 @@ def __init__(self, for k in kwargs.copy(): if k == 'features': if state_features: - warnings.warn(f"Both 'features' and 'state_features' were specified in the constructor for an" - f" {self.__class__.__name__}. Note: 'features' has been deprecated; " - f"'state_features' ({state_features}) will be used.") + warnings.warn(f"Both 'features' and '{STATE_FEATURES}' were specified in the constructor " + f"for an {self.__class__.__name__}. Note: 'features' has been deprecated; " + f"'{STATE_FEATURES}' ({state_features}) will be used.") else: warnings.warn(f"'features' was specified in the constructor for an {self.__class__.__name__}; " - f"Note: 'features' has been deprecated; please use 'state_features' in the future.") + f"Note: 'features' has been deprecated; please use '{STATE_FEATURES}' in the future.") state_features = kwargs['features'] kwargs.pop('features') continue if k == 'feature_function': - if state_feature_functions: - warnings.warn(f"Both 'feature_function' and 'state_feature_functions' were specified in the " + if state_feature_function: + warnings.warn(f"Both 'feature_function' and 'state_feature_function' were specified in the " f"constructor for an {self.__class__.__name__}. Note: 'feature_function' has been " - f"deprecated; 'state_feature_functions' ({state_feature_functions}) will be used.") + f"deprecated; 'state_feature_function' ({state_feature_function}) will be used.") else: warnings.warn(f"'feature_function' was specified in the constructor for an" f"{self.__class__.__name__}; Note: 'feature_function' has been deprecated; " - f"please use 'state_feature_functions' in the future.") - state_feature_functions = kwargs['feature_function'] + f"please use 'state_feature_function' in the future.") + state_feature_function = kwargs['feature_function'] kwargs.pop('feature_function') continue - self.state_features = convert_to_list(state_features) function = function or GridSearch @@ -1355,6 +1796,8 @@ def __init__(self, self._assign_deferred_init_name(self.__class__.__name__) # Store args for deferred initialization self._store_deferred_init_args(**locals()) + self._init_args['state_feature_specs'] = state_features + self._init_args['state_feature_default_spec'] = state_feature_default # Flag for deferred initialization self.initialization_status = ContextFlags.DEFERRED_INIT @@ -1365,9 +1808,28 @@ def __init__(self, assert False, f"PROGRAM ERROR: 'agent_rep' arg should have been specified " \ f"in internal call to constructor for {self.name}." + # If agent_rep is a Composition, but there are more state_features than INPUT Nodes, + # defer initialization until they are added + elif agent_rep.componentCategory=='Composition': + from psyneulink.core.compositions.composition import NodeRole + if (state_features + and len(convert_to_list(state_features)) > len(agent_rep.get_nodes_by_role(NodeRole.INPUT))): + # Temporarily name InputPort + self._assign_deferred_init_name(self.__class__.__name__) + # Store args for deferred initialization + self._store_deferred_init_args(**locals()) + self._init_args['state_feature_specs'] = state_features + self._init_args['state_feature_default_spec'] = state_feature_default + # Flag for deferred initialization + self.initialization_status = ContextFlags.DEFERRED_INIT + return + super().__init__( + agent_rep=agent_rep, + state_feature_specs=state_features, + state_feature_default_spec=state_feature_default, + state_feature_function=state_feature_function, function=function, - state_feature_functions=state_feature_functions, num_estimates=num_estimates, num_trials_per_estimate = num_trials_per_estimate, random_variables=random_variables, @@ -1376,7 +1838,6 @@ def __init__(self, search_statefulness=search_statefulness, search_function=search_function, search_termination_function=search_termination_function, - agent_rep=agent_rep, **kwargs ) @@ -1395,19 +1856,19 @@ def _validate_params(self, request_set, target_set=None, context=None): raise OptimizationControlMechanismError(f"The '{AGENT_REP}' arg of an {self.__class__.__name__} " f"must be either a {Composition.__name__} or a sublcass of one") - elif request_set[STATE_FEATURE_FUNCTIONS]: + elif request_set[STATE_FEATURE_FUNCTION]: state_feats = request_set.pop(STATE_FEATURES, None) - state_feat_fcts = request_set.pop(STATE_FEATURE_FUNCTIONS, None) + state_feat_fcts = request_set.pop(STATE_FEATURE_FUNCTION, None) # If no or only one item is specified in state_features, only one state_function is allowed if ((not state_feats or len(convert_to_list(state_feats))==1) and len(convert_to_list(state_feat_fcts))!=1): raise OptimizationControlMechanismError(f"Only one function is allowed to be specified for " - f"the '{STATE_FEATURE_FUNCTIONS}' arg of {self.name} " + f"the '{STATE_FEATURE_FUNCTION}' arg of {self.name} " f"if either no only one items is specified for its " f"'{STATE_FEATURES}' arg.") if len(convert_to_list(state_feat_fcts))>1 and not isinstance(state_feat_fcts, dict): raise OptimizationControlMechanismError(f"The '{STATE_FEATURES}' arg of {self.name} contains more " - f"than one item, so its '{STATE_FEATURE_FUNCTIONS}' arg " + f"than one item, so its '{STATE_FEATURE_FUNCTION}' arg " f"must be either only a single function (applied to all " f"{STATE_FEATURES}) or a dict with entries of the form " f":.") @@ -1415,40 +1876,31 @@ def _validate_params(self, request_set, target_set=None, context=None): invalid_fct_specs = [fct_spec for fct_spec in state_feat_fcts if fct_spec not in state_feats] if invalid_fct_specs: raise OptimizationControlMechanismError(f"The following entries of the dict specified for " - f"'{STATE_FEATURE_FUNCTIONS} of {self.name} have keys that " + f"'{STATE_FEATURE_FUNCTION} of {self.name} have keys that " f"do not match any InputPorts specified in its " f"{STATE_FEATURES} arg: {invalid_fct_specs}.") - if self.random_variables is not ALL: - # invalid_params = [param.name for param in self.random_variables - # if param not in [r._owner._owner for r in self.agent_rep.random_variables]] - # if invalid_params: - # raise OptimizationControlMechanismError(f"The following Parameters were specified for the " - # f"{RANDOM_VARIABLES} arg of {self.name} that are do randomizable " - # f"(i.e., they do not have a 'seed' attribute: " - # f"{invalid_params}.") invalid_params = [param.name for param in self.random_variables if param not in self.agent_rep.random_variables] if invalid_params: raise OptimizationControlMechanismError(f"The following Parameters were specified for the " - f"{RANDOM_VARIABLES} arg of {self.name} that are do randomizable " - f"(i.e., they do not have a 'seed' attribute: " + f"{RANDOM_VARIABLES} arg of {self.name} that are do" + f"randomizable (i.e., they do not have a 'seed' attribute: " f"{invalid_params}.") # FIX: CONSIDER GETTING RID OF THIS METHOD ENTIRELY, AND LETTING state_input_ports # BE HANDLED ENTIRELY BY _update_state_input_ports_for_controller def _instantiate_input_ports(self, context=None): - """Instantiate InputPorts for state_features (with state_feature_functions if specified). + """Instantiate InputPorts for state_features (with state_feature_function if specified). This instantiates the OptimizationControlMechanism's `state_input_ports; these are used to provide input to the agent_rep when its evaluate method is called - (see Composition._build_predicted_inputs_dict). - The OptimizationCOntrolMechanism's outcome_input_ports are instantiated by + The OptimizationControlMechanism's outcome_input_ports are instantiated by ControlMechanism._instantiate_input_ports in the call to super(). - InputPorts are constructed for **state_features** by calling _parse_state_feature_specs - with them and **state_feature_functions** arguments of the OptimizationControlMechanism constructor. + InputPorts are constructed for **state_features** by calling _parse_state_feature_specs() + with them and **state_feature_function** arguments of the OptimizationControlMechanism constructor. The constructed state_input_ports are passed to ControlMechanism_instantiate_input_ports(), which appends them to the InputPort(s) that receive input from the **objective_mechanism* (if specified) or **monitor_for_control** ports (if **objective_mechanism** is not specified). @@ -1457,35 +1909,29 @@ def _instantiate_input_ports(self, context=None): - every outcome_input_ports receive Projections from within the agent_rep if it is a Composition. If no **state_features** are specified in the constructor, assign ones for INPUT Nodes of owner. - - warn for model-free `model-free optimization `. - - ignore here for `model-based optimization ` - (handled in _update_state_input_ports_for_controller) + - warn for use of CompositionFunctionApproximator as agent_rep; + - ignore here for Composition as agent_rep + (handled in _update_state_input_ports_for_controller). See `state_features ` and - `OptimizationControlMechanism_State_Features` for additional details. + `OptimizationControlMechanism_State_Input_Ports` for additional details. """ - # If any state_features were specified parse them and pass to ControlMechanism._instantiate_input_ports() - state_input_ports_specs = None - # FIX: 11/3/21 : - # ADD CHECK IN _parse_state_feature_specs THAT IF A NODE RATHER THAN InputPort IS SPECIFIED, + # ADD CHECK IN _parse_state_feature_specs() THAT IF A NODE RATHER THAN InputPort IS SPECIFIED, # ITS PRIMARY IS USED (SEE SCRATCH PAD FOR EXAMPLES) - if not self.state_features: - # For model-free (agent_rep = CompositionFunctionApproximator), warn if no state_features specified. - # Note: for model-based optimization, state_input_ports and any state_feature_functions specified + if not self.state_feature_specs: + # If agent_rep is CompositionFunctionApproximator, warn if no state_features specified. + # Note: if agent rep is Composition, state_input_ports and any state_feature_function specified # are assigned in _update_state_input_ports_for_controller. if self.agent_rep_type == COMPOSITION_FUNCTION_APPROXIMATOR: - warnings.warn(f"No 'state_features' specified for use with `agent_rep' of {self.name}") + warnings.warn(f"No '{STATE_FEATURES}' specified for use with `agent_rep' of {self.name}") - else: - # FIX: 11/29/21: DISALLOW FOR COMPOSITION - # Implement any specified state_features - state_input_ports_specs = self._parse_state_feature_specs(self.state_features, - self.state_feature_functions) - # Note: - # if state_features were specified for model-free (i.e., agent_rep is a CompositionFunctionApproximator), - # assume they are OK (no way to check their validity for agent_rep.evaluate() method, and skip assignment + # Implement any specified state_features + state_input_ports_specs = self._parse_state_feature_specs(context) + # Note: + # if state_features were specified and agent_rep is a CompositionFunctionApproximator, + # assume they are OK (no way to check their validity for agent_rep.evaluate() method, and skip assignment # Pass state_input_ports_sepcs to ControlMechanism for instantiation and addition to OCM's input_ports super()._instantiate_input_ports(state_input_ports_specs, context=context) @@ -1493,9 +1939,9 @@ def _instantiate_input_ports(self, context=None): # Assign to self.state_input_ports attribute start = self.num_outcome_input_ports # FIX: 11/3/21 NEED TO MODIFY IF OUTCOME InputPorts ARE MOVED stop = start + len(state_input_ports_specs) if state_input_ports_specs else 0 - # FIX 11/3/21: THIS SHOULD BE MADE A PARAMETER - self.state_input_ports = ContentAddressableList(component_type=InputPort, - list=self.input_ports[start:stop]) + self.parameters.state_input_ports.set(ContentAddressableList(component_type=InputPort, + list=self.input_ports[start:stop]), + override=True) # Ensure that every state_input_port has no more than one afferent projection # FIX: NEED TO MODIFY IF OUTCOME InputPorts ARE MOVED @@ -1506,185 +1952,930 @@ def _instantiate_input_ports(self, context=None): f"{port.name} should receive exactly one projection, " f"but it receives {len(port.path_afferents)} projections.") - def _validate_monitor_for_control(self, nodes): - # Ensure all of the Components being monitored for control are in the agent_rep if it is Composition - if self.agent_rep_type == COMPOSITION: - try: - super()._validate_monitor_for_control(self.agent_rep._get_all_nodes()) - except ControlMechanismError as e: - raise OptimizationControlMechanismError(f"{self.name} has 'outcome_ouput_ports' that receive " - f"Projections from the following Components that do not " - f"belong to its {AGENT_REP} ({self.agent_rep.name}): {e.data}.") - - # FIX: 12/9/21 -- DEPRECATE DIRECT PROJECTIONS FROM PROBES, ELIMINATING THE NEED FOR THIS OVERRIDE - # def _parse_monitor_for_control_input_ports(self, context): - # """Override ControlMechanism to implement allow_probes=DIRECT option - # - # If is False (default), simply pass results of super()._parse_monitor_for_control_input_ports(context); - # this is restricted to the use of OUTPUT Nodes in nested Compositions, and routes Projections from nodes in - # nested Compositions through their respective output_CIMs. - # - # If allow_probes option is True, any INTERNAL Nodes of nested Compositions specified in monitor_for_control - # are assigned NodeRole.OUTPUT, and Projections from them to the OptimizationControlMechanism are routed - # from the nested Composition(s) through the respective output_CIM(s). - # - # If allow_probes option is DIRECT, Projection specifications are added to Port specification dictionaries, - # so that the call to super()._instantiate_input_ports in ControlMechanism instantiates Projections from - # monitored node to OptimizationControlMechanism. This allows *direct* Projections from monitored nodes in - # nested Compositions to the OptimizationControlMechanism, bypassing output_CIMs and preventing inclusion - # of their values in the results attribute of those Compositions. - # - # Return port specification dictionaries (*with* Projection specifications), their value sizes and null list - # (to suppress Projection assignment to aux_components in ControlMechanism._instantiate_input_ports) - # """ - # - # outcome_input_port_specs, outcome_value_sizes, monitored_ports \ - # = super()._parse_monitor_for_control_input_ports(context) - # - # if self.allow_probes == DIRECT: - # # Add Projection specifications to port specification dictionaries for outcome_input_ports - # # and return monitored_ports = [] - # - # if self.outcome_input_ports_option == SEPARATE: - # # Add port spec to to each outcome_input_port_spec (so that a Projection is specified directly to each) - # for i in range(self.num_outcome_input_ports): - # outcome_input_port_specs[i].update({PROJECTIONS: monitored_ports[i]}) - # else: - # # Add all ports specs as list to single outcome_input_port - # outcome_input_port_specs[0].update({PROJECTIONS: monitored_ports}) - # - # # Return [] for ports to suppress creation of Projections in _instantiate_input_ports - # monitored_ports = [] - # - # return outcome_input_port_specs, outcome_value_sizes, monitored_ports + def _get_agent_rep_input_receivers(self, comp=None, type=PORT, comp_as_node=False): + if not self.agent_rep_type or self.agent_rep_type == COMPOSITION_FUNCTION_APPROXIMATOR: + return [None] + comp = comp or self.agent_rep + return comp._get_input_receivers(comp=comp, type=type, comp_as_node=comp_as_node) - def _update_state_input_ports_for_controller(self, context=None): - """Check and update state_input_ports for model-based optimization (agent_rep==Composition) + def _get_specs_not_in_agent_rep(self, state_feature_specs): + from psyneulink.core.compositions.composition import Composition + agent_rep_nodes = self.agent_rep._get_all_nodes() + return [spec for spec in state_feature_specs + if ((isinstance(spec, (Mechanism, Composition)) + and spec not in agent_rep_nodes) + or (isinstance(spec, Port) + and spec.owner not in agent_rep_nodes))] + + def _validate_input_nodes(self, nodes, enforce=None): + """Check that nodes are INPUT Nodes of agent_rep + INPUT Nodes are those at the top level of agent_rep as well as those of any Compositions nested within it + that are themselves INPUT Nodes of their enclosing Composition. + Raise exception for non-INPUT Nodes if **enforce** is specified; otherwise just issue warning. + """ + from psyneulink.core.compositions.composition import Composition + agent_rep_input_nodes = self._get_agent_rep_input_receivers(type=NODE,comp_as_node=ALL) + agent_rep_input_ports = self._get_agent_rep_input_receivers(type=PORT) + agent_rep_all_nodes = self.agent_rep._get_all_nodes() + non_input_node_specs = [node for node in nodes + if ((isinstance(node, (Mechanism, Composition)) and node not in agent_rep_input_nodes) + or (isinstance(node, Port) and (not isinstance(node, InputPort) + or node not in agent_rep_input_ports)))] + non_agent_rep_node_specs = [node for node in nodes + if ((isinstance(node, (Mechanism, Composition)) and node not in agent_rep_all_nodes) or + (isinstance(node, Port) and node.owner not in agent_rep_all_nodes))] + + # Deal with Nodes that are in agent_rep but not INPUT Nodes + if non_input_node_specs: + items = ', '.join([n._name for n in non_input_node_specs]) + if len(non_input_node_specs) == 1: + items_str = f"contains an item ({items}) that is not an INPUT Node" + else: + items_str = f"contains items ({items}) that are not INPUT Nodes" + message = f"The '{STATE_FEATURES}' specified for '{self.name}' {items_str} " \ + f"within its {AGENT_REP} ('{self.agent_rep.name}'); only INPUT Nodes can be in a set " \ + f"or used as keys in a dict used to specify '{STATE_FEATURES}'." + if enforce: + raise OptimizationControlMechanismError(message) + else: + warnings.warn(message) + + # Deal with Nodes that are not in agent_rep + if non_agent_rep_node_specs: + items = ', '.join([n._name for n in non_agent_rep_node_specs]) + singular = len(non_agent_rep_node_specs) == 1 + if singular: + items_str = f"contains an item ({items}) that is" + else: + items_str = f"contains items ({items}) that are" + message = f"The '{STATE_FEATURES}' specified for '{self.name}' {items_str} not in its {AGENT_REP} " \ + f"('{self.agent_rep.name}'). Executing '{self.agent_rep.name}' before " \ + f"{'it is' if singular else 'they are'} added will generate an error ." + if enforce: + raise OptimizationControlMechanismError(message) + else: + warnings.warn(message) + + # FIX: 1/29/22 - REFACTOR TO SUPPORT InportPort SPECIFICATION DICT FOR MULT. PROJS. TO STATE_INPUT_PORT + def _parse_state_feature_specs(self, context=None): + """Parse entries of state_features specifications used to construct state_input_ports. + + Called from _instantiate_input_ports() + + Parse **state_features** arg of constructor for OptimizationControlMechanism, assigned to state_feature_specs. + + state_feature_specs lists sources of inputs to *all* INPUT Nodes of agent_rep, at all levels of nesting; there + is one entry for every INPUT Node in agent_rep, and every INPUT Node of any nested Composition that is + itself an INPUT Node at any level of nesting. + + Construct a state_input_port for every entry in state_feature_specs that is not None: + the value of those state_input_ports comprise the state_feature_values attribute, and are provided as the + input to the INPUT Nodes of agent_rep when its evaluate() method is executed (as the **predicted_inputs** + argument if agent_rep is a Composition, and the **feature_values** argument if it is a + CompositionFunctionApproximator); for INPUT; + for None entries in state_feature_specs, the corresponding INPUT Nodes are provided their + default_external_input_shape as their input when agent_rep.evaluate() executes. + + Projection(s) to state_input_ports from sources specified in state_feature_specs can be direct, + or indirect by way of a CIM if the source is in a nested Composition. + + Handle four formats: + + - dict {INPUT Node: source or None, INPUT Node or InputPort: source or None...}: + - every key must be an INPUT Node of agent_rep or an INPUT Node of a nested Composition within it that is + itself an INPUT Node of its enclosing Composition, or the external InputPort of one, at any level of + nesting; + - if a Mechanism is specified as a key, construct a state_input_port for each of its external InputPorts, + and assign the value of the dict entry as the source for all of them; + - if a Composition is specified as a key, construct a state_input_port for each external InputPort of each + of its INPUT Nodes, and those of any Compositions nested within it at all levels of nesting, + and assign the the value of the dict entry as the source for all of them; + - for INPUT Nodes not specified or assigned None as their value, assign corresponding entries in + state_feature_specs as state_feature_default + - if only one or some of the INPUT Nodes of a nested Composition are specified, + for the remaining ones assign the corresponding entries in state_feature_specs as state_feature_default + - if None is specified, don't construct a state_input_port + - list [source, None, source...]: specifies source specs for INPUT Node external InputPorts: + - must be listed in same order as *expanded* list of agent_rep INPUT Node external InputPorts to which they + correspond (i.e., nested Compositions that are INPUT Nodes replaced by their INPUT Nodes, + for all levels of nesting); + - if there are fewer sources listed than INPUT Node external InputPorts, assign state_feature_default to + the entries in state_feature_specs corresponding to the remaining INPUT Node external InputPorts + - if there more sources listed than INPUT Nodes, leave the excess ones, and label them as + 'EXPECT ' for later resolution (see below). + + - set {INPUT Node, Input Node...}: specifies INPUT Nodes to be shadowed + - every item must be an INPUT Node of agent_rep or an INPUT Node of a nested Composition within it that + is itself an INPUT Node of its enclosing Composition, at any level of nesting; + - if a Composition is specified, construct a state_input_port for each of its INPUT Node extenal InputPorts, + and those of any Compositions nested within it at all levels of nesting, each of which shadows the + input of the corresponding INPUT Node (see _InputPort_Shadow_Inputs). + - if only one or some of the INPUT Nodes of a nested Composition are specified, use state_feature_default. + + IMPLEMENTATION NOTE: this is a legacy format for consistency with generic specification of shadowing inputs + - SHADOW_INPUTS dict {"SHADOW_INPUTS":[shadowable input, None, shadowable input...]}: + - all items must be a Mechanism (or one of its external InputPorts) that is an INPUT Node of agent_rep or + of a nested Composition within it that is itself an INPUT Node; + - must be listed in same order as *expanded* list of agent_rep INPUT Nodes to which they correspond + (see list format above); + - construct a state_input_port for each non-None spec, and assign it a Projection that shadows the spec. + (see _InputPort_Shadow_Inputs). + + If shadowing is specified for an INPUT Node InputPort, set INTERNAL_ONLY to True in entry of params dict in + specification dictionary for corresponding state_input_port (so that inputs to Composition are not + required if the specified source is itself an INPUT Node). + + If an INPUT Node (or one of its external InputPorts) is specified that is not (yet) in agent_rep, + and/or a source is specified that is not yet in self.composition, warn and defer creating a + state_input_port; final check is made, and error(s) generated for unresolved specifications at run time. + + Assign functions specified in **state_feature_function** to InputPorts for all state_features + + Return list of InputPort specification dictionaries for state_input_ports + """ - If no agent_rep has been specified or it is model-free, return - (note: validation of state_features specified for model-free optimization is up to the - CompositionFunctionApproximator) + from psyneulink.core.compositions.composition import Composition, NodeRole + # Agent rep's input Nodes and their names + agent_rep_input_ports = self._get_agent_rep_input_receivers(type=PORT) + self._specified_INPUT_Node_InputPorts_in_order = [] + + # List of assigned state_feature_function (vs. user provided specs) + self._state_feature_functions = [] + + # VALIDATION AND WARNINGS ----------------------------------------------------------------------------------- + + # Only list spec allowed if agent_rep is a CompositionFunctionApproximator + if self.agent_rep_type == COMPOSITION_FUNCTION_APPROXIMATOR and not isinstance(self.state_feature_specs, list): + agent_rep_name = f" ({self.agent_rep.name})" if not isinstance(self.agent_rep, type) else '' + raise OptimizationControlMechanismError( + f"The {AGENT_REP} specified for {self.name}{agent_rep_name} is a {COMPOSITION_FUNCTION_APPROXIMATOR}, " + f"so its '{STATE_FEATURES}' argument must be a list, not a {type(self.state_feature_specs).__name__} " + f"({self.state_feature_specs}).") + + # agent_rep has not yet been (fully) constructed + if not agent_rep_input_ports and self.agent_rep_type is COMPOSITION: + # FIX: 3/18/22 - ADD TESTS FOR THESE (in test_deferred_init or test_partial_deferred_init()?) + if (isinstance(self.state_feature_specs, set) + or isinstance(self.state_feature_specs, dict) and SHADOW_INPUTS not in self.state_feature_specs): + # Dict and set specs reference Nodes that are not yet in agent_rep + warnings.warn(f"Nodes are specified in the {STATE_FEATURES}' arg for '{self.name}' that are not " + f"(yet) in its its {AGENT_REP} ('{self.agent_rep.name}'). They must all be assigned " + f"to it before the Composition is executed'. It is generally safer to assign all " + f"Nodes to the {AGENT_REP} of a controller before specifying its '{STATE_FEATURES}'.") + else: + # List and SHADOW_INPUTS specs are dangerous before agent_rep has been fully constructed + warnings.warn(f"The '{STATE_FEATURES}' arg for '{self.name}' has been specified before any Nodes have " + f"been assigned to its {AGENT_REP} ('{self.agent_rep.name}'). Their order must be the " + f"same as the order of the corresponding INPUT Nodes for '{self.agent_rep.name}' once " + f"they are added, or unexpected results may occur. It is safer to assign all Nodes to " + f"the {AGENT_REP} of a controller before specifying its '{STATE_FEATURES}'.") - For model-based optimization (agent_rep is a Composition): + # HELPER METHODS ------------------------------------------------------------------------------------------ - - ensure that state_input_ports for all specified state_features are for InputPorts of INPUT Nodes of agent_rep; - raises an error if any receive a Projection that is not a shadow Projection from an INPUT Node of agent_rep - (note: there should already be state_input_ports for any **state_features** specified in the constructor). + def expand_nested_input_comp_to_input_nodes(comp): + input_nodes = [] + for node in comp.get_nodes_by_role(NodeRole.INPUT): + if isinstance(node, Composition): + input_nodes.extend(expand_nested_input_comp_to_input_nodes(node)) + else: + input_nodes.append(node) + return input_nodes - - if no state_features specified, assign a state_input_port for every InputPort of every INPUT Node of agent_rep - (note: shadow Projections for all state_input_ports are created in Composition._update_shadow_projections()). + def get_port_for_mech_spec(spec:Union[Port,Mechanism]): + """Return port for Mechanism specified as state_feature + This is used to override the standard interpretation of a Mechanism in an InputPort specification: + - return Primary InputPort of Mechanism (to be shadowed) if agent_rep is Composition + - return Primary OutputPort of Mechanism (standard behavior) if agent_rep is a CFA + """ + # assert isinstance(mech, Mechanism), \ + # f"PROGRAM ERROR: {mech} should be Mechanism in call to get_port_for_mech_spec() for '{self.name}'" + if isinstance(spec, Port): + return spec + if self.agent_rep_type == COMPOSITION: + # FIX: 11/29/21: MOVE THIS TO _parse_shadow_inputs + # (ADD ARG TO THAT FOR DOING SO, OR RESTRICT TO InputPorts IN GENERAL) + if len(spec.input_ports)!=1: + raise OptimizationControlMechanismError( + f"A Mechanism ({spec.name}) is specified to be shadowed in the '{STATE_FEATURES}' arg " + f"for '{self.name}', but it has more than one {InputPort.__name__}; a specific one of its " + f"{InputPort.__name__}s must be specified to be shadowed.") + return spec.input_port + else: + # agent_rep is a CFA + return spec.output_port + + # PARSE SPECS ------------------------------------------------------------------------------------------ + # Generate parallel lists of state feature specs (for sources of inputs) + # and INPUT Nodes to which they (if specified in dict or set format) + def _parse_specs(state_feature_specs, specified_input_ports=None, spec_type="list"): + """Validate and parse INPUT Node specs assigned to construct state_feature_specs + Validate number and identity of specs relative to agent_rep INPUT Nodes. + Assign spec for every INPUT Mechanism (nested) within agent_rep (i.e., for all nested Compositions) + as entries in state_feature_specs + Return names for use as state_input_port_names in main body of method + """ - - assign state_feature_functions to relevant state_input_ports (same function for all if no state_features - are specified or only one state_function is specified; otherwise, use dict for specifications). + parsed_feature_specs = [] + num_user_specs = len(state_feature_specs) + num_specified_ports = len(specified_input_ports) + num_agent_rep_input_ports = len(agent_rep_input_ports) + # Total number of specs to be parsed: + self._num_state_feature_specs = max(num_user_specs, num_agent_rep_input_ports) + + assert num_user_specs == num_specified_ports, f"ALERT: num state_feature_specs != num ports in _parse_spec()" + # Note: there may be more state_feature_specs (i.e., ones for unspecified input_ports) + # than num_specified_ports + + if self.agent_rep_type == COMPOSITION: + + # FIX: 3/18/22 - THESE SEEM DUPLICATIVE OF _validate_state_features; JUST CALL THAT HERE? + # ALSO, WARNING IS TRIGGERED IF MECHANIMS RATHER THAN ITS INPUT_PORTS ARE SPEC'D + # AT THE LEAST, MOVE TO THEIR OWN VALIDATION HELPER METHOD + # Too FEW specs for number of agent_rep receivers + if len(self.state_feature_specs) < num_agent_rep_input_ports: + warnings.warn(f"There are fewer '{STATE_FEATURES}' specified for '{self.name}' than the number " + f"of {InputPort.__name__}'s for all of the INPUT Nodes of its {AGENT_REP} " + f"('{self.agent_rep.name}'); the remaining inputs will be assigned default values " + f"when '{self.agent_rep.name}`s 'evaluate' method is executed. If this is not the " + f"desired behavior, use its get_inputs_format() method to see the format for its " + f"inputs.") + + # Too MANY specs for number of agent_rep receivers + if num_user_specs > num_agent_rep_input_ports: + # specs_not_in_agent_rep = [f"'{spec.name if isinstance(spec, Mechanism) else spec.owner.name}'" + # for spec in self._get_specs_not_in_agent_rep(state_feature_specs)] + specs_not_in_agent_rep = \ + [f"'{spec.name if isinstance(spec,(Mechanism, Composition)) else spec.owner.name}'" + for spec in self._get_specs_not_in_agent_rep(user_specs)] + + if specs_not_in_agent_rep: + spec_type = ", ".join(specs_not_in_agent_rep) + warnings.warn( + f"The '{STATE_FEATURES}' specified for {self.name} is associated with a number of " + f"{InputPort.__name__}s ({len(state_feature_specs)}) that is greater than for the " + f"{InputPort.__name__}s of the INPUT Nodes ({num_agent_rep_input_ports}) for the " + f"Composition assigned as its {AGENT_REP} ('{self.agent_rep.name}'), which includes " + f"the following that are not (yet) in '{self.agent_rep.name}': {spec_type}. Executing " + f"{self.name} before the additional item(s) are added as (part of) INPUT Nodes will " + f"generate an error.") + else: + warnings.warn( + f"The '{STATE_FEATURES}' specified for {self.name} is associated with a number of " + f"{InputPort.__name__}s ({len(state_feature_specs)}) that is greater than for the " + f"{InputPort.__name__}s of the INPUT Nodes ({num_agent_rep_input_ports}) for the " + f"Composition assigned as its {AGENT_REP} ('{self.agent_rep.name}'). Executing " + f"{self.name} before the additional item(s) are added as (part of) INPUT Nodes will " + f"generate an error.") + + # Nested Compositions not allowed to be specified in a list spec + nested_comps = [node for node in state_feature_specs if isinstance(node, Composition)] + if nested_comps: + comp_names = ", ".join([f"'{n.name}'" for n in nested_comps]) + raise OptimizationControlMechanismError( + f"The '{STATE_FEATURES}' argument for '{self.name}' includes one or more Compositions " + f"({comp_names}) in the {spec_type} specified for its '{STATE_FEATURES}' argument; these must be " + f"replaced by direct references to the Mechanisms (or their InputPorts) within them to be " + f"shadowed.") + + state_input_port_names = [] + for i in range(self._num_state_feature_specs): + + state_input_port_name = None + state_feature_fct = None + + # FIX: CONSOLIDATE THIS WITH PARSING OF SPEC BELOW + # AGENT_REP INPUT NODE InputPort + # Assign it's name to be used in state_features + # (and specs for CFA and any Nodes not yet in agent_rep) + if self.agent_rep_type == COMPOSITION: + if i < num_agent_rep_input_ports: + # spec is for Input{ort of INPUT Node already in agent_rep + # so get agent_rep_input_port and its name (spec will be parsed and assigned below) + agent_rep_input_port = agent_rep_input_ports[i] + agent_rep_input_port_name = agent_rep_input_port.full_name + else: + # spec is for deferred NODE InputPort (i.e., not (yet) in agent_rep) + # so get specified value for spec, for later parsing and assignment (once Node is known) + agent_rep_input_port = specified_input_ports[i] + # - assign "DEFERRED n" as node name + agent_rep_input_port_name = \ + _deferred_agent_rep_input_port_name(str(i - num_agent_rep_input_ports), + self.agent_rep.name) + # For CompositionFunctionApproximator, assign spec as agent_rep_input_port + else: + spec = state_feature_specs[i] + agent_rep_input_port = spec + agent_rep_input_port_name = spec.full_name if isinstance(spec, Port) else spec.name + # Assign state_input_port_name here as won't get done below (i can't be < num_user_specs for CFA) + state_input_port_name = f"FEATURE {i} FOR {self.agent_rep.name}" + + # SPEC and state_input_port_name + # Parse and assign user specifications (note: may be for INPUT Node InputPorts not yet inagent_rep) + if i < num_user_specs: # i.e., if num_agent_rep_input_ports < num_user_specs) + spec = state_feature_specs[i] + # Unpack tuple + + if isinstance(spec, tuple): + state_feature_fct = spec[1] + spec = spec[0] + + # Assign spec and state_input_port name + if is_numeric(spec): + state_input_port_name = _numeric_state_input_port_name(agent_rep_input_port_name) + + elif isinstance(spec, (InputPort, Mechanism)): + spec_name = spec.full_name if isinstance(spec, InputPort) else spec.input_port.full_name + state_input_port_name = _shadowed_state_input_port_name(spec_name, + agent_rep_input_port_name) + elif isinstance(spec, OutputPort): + state_input_port_name = _state_input_port_name(spec.full_name, + agent_rep_input_port_name) + elif isinstance(spec, Composition): + assert False, f"Composition spec ({spec}) made it to _parse_specs for {self.name}." + + elif spec == SHADOW_INPUTS: + # Shadow the specified agent_rep_input_port (Name assigned where shadow input is parsed) + spec = agent_rep_input_port + state_input_port_name = _shadowed_state_input_port_name(agent_rep_input_port_name, + agent_rep_input_port_name) + + elif isinstance(spec, dict): + state_input_port_name = spec[NAME] if NAME in spec else f"INPUT FOR {agent_rep_input_port_name}" + # tuple specification of function (assigned above) overrides dictionary specification + if state_feature_fct is None: + if FUNCTION in spec: + state_feature_fct = spec[FUNCTION] + elif PARAMS in spec and FUNCTION in spec[PARAMS]: + state_feature_fct = spec[PARAMS][FUNCTION] + + elif spec is not None: + assert False, f"PROGRAM ERROR: unrecognized form of state_feature specification for {self.name}" + + # Fewer specifications than number of INPUT Nodes, so assign state_feature_default to the rest + else: + # Note: state_input_port name assigned above + spec = self.state_feature_default + + parsed_feature_specs.append(spec) + self._state_feature_functions.append(state_feature_fct) + self._specified_INPUT_Node_InputPorts_in_order.append(agent_rep_input_port) + state_input_port_names.append(state_input_port_name) + + if not any(self._state_feature_functions): + self._state_feature_functions = None + self.parameters.state_feature_specs.set(parsed_feature_specs, override=True) + return state_input_port_names or [] + + # END OF PARSE SPECS ----------------------------------------------------------------------------------- + + user_specs = self.parameters.state_feature_specs.spec + self.state_feature_default = self.parameters.state_feature_default_spec.spec + + # SINGLE ITEM spec, SO APPLY TO ALL agent_rep_input_ports + if (user_specs is None + or isinstance(user_specs, (str, tuple, InputPort, OutputPort, Mechanism, Composition)) + or (is_numeric(user_specs) and (np.array(user_specs).ndim < 2))): + specs = [user_specs] * len(agent_rep_input_ports) + # OK to assign here (rather than in _parse_secs()) since spec is intended for *all* state_input_ports + self.parameters.state_feature_specs.set(specs, override=True) + state_input_port_names = _parse_specs(state_feature_specs=specs, + specified_input_ports=agent_rep_input_ports, + spec_type='list') + + # LIST OR SHADOW_INPUTS DICT: source specs + # Source specs but not INPUT Nodes specified; spec is either: + # - list: [spec, spec...] + # - SHADOW_INPUTS dict (with list spec as its only entry): {SHADOW_INPUTS: {[spec, spec...]}} + # Treat specs as sources of input to INPUT Nodes of agent_rep (in corresponding order): + # Call _parse_specs to construct a regular dict using INPUT Nodes as keys and specs as values + elif isinstance(user_specs, list) or (isinstance(user_specs, dict) and SHADOW_INPUTS in user_specs): + if isinstance(user_specs, list): + num_missing_specs = len(agent_rep_input_ports) - len(self.state_feature_specs) + specs = user_specs + [self.state_feature_default] * num_missing_specs + spec_type = 'list' + else: + # SHADOW_INPUTS spec: + if isinstance(user_specs[SHADOW_INPUTS], set): + # Set not allowed as SHADOW_INPUTS spec; catch here to provide context-relevant error message + raise OptimizationControlMechanismError( + f"The '{STATE_FEATURES}' argument for '{self.name}' uses a set in a '{SHADOW_INPUTS.upper()}' " + f"dict; this must be a single item or list of specifications in the order of the INPUT Nodes" + f"of its '{AGENT_REP}' ({self.agent_rep.name}) to which they correspond." ) + # FIX: 3/18/22 - ?DOES THIS NEED TO BE DONE HERE, OR CAN IT BE DONE IN A RELEVANT _validate METHOD? + # All specifications in list specified for SHADOW_INPUTS must be shadowable + # (i.e., either an INPUT Node or the InputPort of one) or None; + # note: if spec is not in agent_rep, might be added later, + # so defer dealing with that until runtime. + bad_specs = [spec for spec in user_specs[SHADOW_INPUTS] + if ( # spec is not an InputPort + ((isinstance(spec, Port) and not isinstance(spec, InputPort)) + # spec is an InputPort of a Node in agent_rep but not one of its INPUT Nodes + or (isinstance(spec, InputPort) + and spec.owner in self.agent_rep._get_all_nodes() + and spec.owner not in self._get_agent_rep_input_receivers(type=NODE, + comp_as_node=ALL)) + ) + and spec is not None)] + if bad_specs: + bad_spec_names = [f"'{item.owner.name}'" if hasattr(item, 'owner') + else f"'{item.name}'" for item in bad_specs] + raise OptimizationControlMechanismError( + f"The '{STATE_FEATURES}' argument for '{self.name}' has one or more items in the list " + f"specified for '{SHADOW_INPUTS.upper()}' ({', '.join([name for name in bad_spec_names])}) " + f"that are not (part of) any INPUT Nodes of its '{AGENT_REP}' ('{self.agent_rep.name}')." ) + + specs = user_specs[SHADOW_INPUTS] + spec_type = f"{SHADOW_INPUTS.upper()} dict" + + specified_input_ports = agent_rep_input_ports + [None] * (len(specs) - len(agent_rep_input_ports)) + state_input_port_names = _parse_specs(state_feature_specs=specs, + specified_input_ports=specified_input_ports, + spec_type=spec_type) + + # FIX: 2/25/22 - ?ITEMS IN set ARE SHADOWED, BUT UNSPECIFIED ITEMS IN SET AND DICT ARE ASSIGNED DEFAULT VALUES + # SET OR DICT: specification by INPUT Nodes + # INPUT Nodes of agent_rep specified in either a: + # - set, without source specs: {node, node...} + # - dict, with source specs for each: {node: spec, node: spec...} + # Call _parse_specs to convert to or flesh out dict with INPUT Nodes as keys and any specs as values + # adding any unspecified INPUT Nodes of agent_rep and assiging default values for any unspecified values + elif isinstance(user_specs, (set, dict)): + + # FIX: 3/4/22 REINSTATE & MOVE TO ABOVE?? + self._validate_input_nodes(set(user_specs)) + + # FIX: MOVE TO _validate_input_nodes + # Validate user_specs + internal_input_port_specs = [f"'{spec.full_name}'" for spec in user_specs + if isinstance(spec, InputPort) and spec.internal_only] + if internal_input_port_specs: + raise OptimizationControlMechanismError( + f"The following {InputPort.__name__}s specified in the '{STATE_FEATURES}' arg for {self.name} " + f"do not receive any external inputs and thus cannot be assigned '{STATE_FEATURES}': " + f"{', '.join(internal_input_port_specs)}.") + non_input_port_specs = [f"'{spec.full_name}'" for spec in user_specs + if isinstance(spec, Port) and not isinstance(spec, InputPort)] + if non_input_port_specs: + raise OptimizationControlMechanismError( + f"The following {Port.__name__}s specified in the '{STATE_FEATURES}' arg for {self.name} " + f"are not {InputPort.__name__} and thus cannot be assigned '{STATE_FEATURES}': " + f"{', '.join(non_input_port_specs)}.") + + expanded_specified_ports = [] + expanded_dict_with_ports = {} + dict_format = isinstance(user_specs, dict) + + # Expand any Nodes specified in user_specs set or keys of dict to corresponding InputPorts + for spec in user_specs: + # Expand any specified Compositions into corresponding InputPorts for all INPUT Nodes (including nested) + if isinstance(spec, Composition): + ports = self._get_agent_rep_input_receivers(spec) + # Expand any specified Mechanisms into corresponding InputPorts except any internal ones + elif isinstance(spec, Mechanism): + ports = [input_port for input_port in spec.input_ports if not input_port.internal_only] + else: + ports = [spec] + expanded_specified_ports.extend(ports) + if dict_format: + # Assign values specified in user_specs dict to corresponding InputPorts + expanded_dict_with_ports.update({port:user_specs[spec] for port in ports}) + + # # Get specified ports in order of agent_rep INPUT Nodes, with None assigned to any unspecified InputPorts + all_specified_ports = [port if port in expanded_specified_ports + else None for port in agent_rep_input_ports] + # Get any not found anywhere (including nested) in agent_rep, which are placed at the end of list + all_specified_ports.extend([port for port in expanded_specified_ports if port not in agent_rep_input_ports]) + + if isinstance(user_specs, set): + # Just pass ports; _parse_specs assigns shadowing projections for them and None to all unspecified ones + specs = all_specified_ports + else: + # Pass values from user_spec dict to be parsed; + # corresponding ports are safely in all_specified_ports + # unspecified ports are assigned state_feature_default per requirements of list format + specs = [expanded_dict_with_ports[port] if port is not None and port in all_specified_ports + else self.state_feature_default for port in all_specified_ports] + + state_input_port_names = _parse_specs(state_feature_specs=specs, + specified_input_ports=list(all_specified_ports), + spec_type='dict') + + else: + assert False, f"PROGRAM ERROR: Unanticipated type specified for '{STATE_FEATURES}' arg of '{self.name}: " \ + f"'{user_specs}' ({type(user_specs)})." + + # CONSTRUCT InputPort SPECS ----------------------------------------------------------------------------- + + state_input_port_specs = [] + + for i in range(self._num_state_feature_specs): + # Note: state_feature_specs have now been parsed (user's specs are in parameters.state_feature_specs.spec); + # state_feature_specs correspond to all InputPorts of agent_rep's INPUT Nodes (including nested ones) + spec = self.state_feature_specs[i] + + if spec is None: + continue + + # FIX: 3/22/22 - COULD/SHOULD ANY OF THE FOLLOWING BE DONE IN _parse_specs(): + + if isinstance(self.state_feature_specs[i], dict): + # If spec is an InputPort specification dict: + # - if a Mechanism is specified as the source, specify for shadowing: + # - add SHADOW_INPUTS entry to specify shadowing of Mechanism's primary InputPort + # - process dict through _parse_shadow_inputs(), + # (preserves spec as dict in case other parameters (except function, handled below) are specified) + # - replace self.state_feature_specs[i] with the InputPort (required by state_feature_values) + # - if a function is specified, clear from dict + # - it has already been assigned to self._state_feature_functions in _parse_spec() + # - it will be properly assigned to InputPort specification dict in _assign_state_feature_function + def _validate_entries(spec=None, source=None): + if spec and source: + if (SHADOW_INPUTS in spec) or (PARAMS in spec and SHADOW_INPUTS in spec[PARAMS]): + error_msg = "both PROJECTIONS and SHADOW_INPUTS cannot specified" + elif len(convert_to_list(source)) != 1: + error_msg = "PROJECTIONS entry has more than one source" + return + else: + error_msg = f"missing a 'PROJECTIONS' entry specifying the source of the input." + raise OptimizationControlMechanismError(f"Error in InputPort specification dictionary used in '" + f"{STATE_FEATURES}' arg of '{self.name}': {error_msg}.") + # Handle shadowing of Mechanism as source + if PROJECTIONS in spec: + source = get_port_for_mech_spec(spec.pop(PROJECTIONS)) + if spec: # No need to check if nothing left in dict + _validate_entries(spec, source) + spec[SHADOW_INPUTS] = source + elif PARAMS in spec and PROJECTIONS in spec[PARAMS]: + source = get_port_for_mech_spec(spec[PARAMS].pop(PROJECTIONS)) + _validate_entries(spec, source) + spec[PARAMS][SHADOW_INPUTS] = source + else: + _validate_entries() + + # Clear FUNCTION entry + if self._state_feature_functions[i]: + spec.pop(FUNCTION, None) + if PARAMS in spec: + spec[PARAMS].pop(FUNCTION, None) + + spec = _parse_shadow_inputs(self, spec)[0] # _parse_shadow_inputs returns a list, so get item + self.state_feature_specs[i] = source + + if is_numeric(spec): + # Construct InputPort specification dict that configures it to use its InputPort.default_variable + # as its input, and assigns the spec's value to the VALUE entry, + # which assigns it as the value of the InputPort.default_variable + spec_val = copy.copy(spec) + spec = {VALUE: spec_val, + PARAMS: {DEFAULT_INPUT: DEFAULT_VARIABLE}} + + if isinstance(spec, Mechanism): + # Replace with primary InputPort to be shadowed + spec = get_port_for_mech_spec(spec) + self.state_feature_specs[i] = spec + + # Get InputPort specification dictionary for state_input_port and update its entries + parsed_spec = _parse_port_spec(owner=self, port_type=InputPort, port_spec=spec) + parsed_spec[NAME] = state_input_port_names[i] + if parsed_spec[PARAMS] and SHADOW_INPUTS in parsed_spec[PARAMS]: + # Composition._update_shadow_projections will take care of PROJECTIONS specification + parsed_spec[PARAMS][INTERNAL_ONLY]=True, + parsed_spec[PARAMS][PROJECTIONS]=None + # Assign function for state_input_port if specified--------------------------------------------------- + parsed_spec = self._assign_state_feature_function(parsed_spec, i) + parsed_spec = [parsed_spec] # so that extend works below + state_input_port_specs.extend(parsed_spec) + + return state_input_port_specs + + def _assign_state_feature_function(self, specification_dict, idx=None): + """Assign any specified state_feature_function to corresponding state_input_ports + idx is index into self._state_feature_functions; if None, use self.state_feature_function specified by user + Specification in InputPort specification dictionary or **state_features** tuple + takes precedence over **state_feature_function** specification. + Assignment of function to dict specs handled above, so skip here + Return state_input_port_dicts with FUNCTION entries added as appropriate. + """ + + # Note: state_feature_function has been validated in _validate_params + default_function = self.state_feature_function # User specified in constructor + try: + if self._state_feature_functions: + assert len(self._state_feature_functions) == self._num_state_feature_specs, \ + f"PROGRAM ERROR: Length of _state_feature_functions for {self.name} should be same " \ + f"as number of state_input_port_dicts passed to _assign_state_feature_function" + state_feature_functions = self._state_feature_functions + except AttributeError: + # state_features assigned automatically in _update_state_input_ports_for_controller, + # so _state_feature_functions (for individual state_features) not created + state_feature_functions = None + fct = state_feature_functions[idx] if state_feature_functions else None + if fct: + specification_dict[FUNCTION] = self._parse_state_feature_function(fct) + elif default_function and FUNCTION not in specification_dict[PARAMS]: + # Assign **state_feature_function** (aka default_function) if specified and no other has been specified + specification_dict[FUNCTION] = self._parse_state_feature_function(default_function) + return specification_dict + + def _parse_state_feature_function(self, feature_function): + if isinstance(feature_function, Function): + return copy.deepcopy(feature_function) + else: + return feature_function + + def _update_state_input_ports_for_controller(self, context=None): + """Check and update state_input_ports at run time if agent_rep is a Composition + + If no agent_rep has been specified or it is a CompositionFunctionApproximator, return + (note: validation of state_features specified for CompositionFunctionApproximator optimization + is up to the CompositionFunctionApproximator) + + If agent_rep is a Composition: + - if has any new INPUT Node InputPorts: + - construct state_input_ports for them + - add to _specified_INPUT_Node_InputPorts_in_order + - call _validate_state_features() + - call _update_state_input_port_names() """ - # FIX: 11/15/21 - REPLACE WITH ContextFlags.PROCESSING ?? - # TRY TESTS WITHOUT THIS - # Don't instantiate unless being called by Composition.run() (which does not use ContextFlags.METHOD) - # This avoids error messages if called prematurely (i.e., before run is complete) - # MODIFIED 11/29/21 OLD: - if context.flags & ContextFlags.METHOD: + # Don't instantiate unless being called by Composition.run() + # This avoids error messages if called prematurely (i.e., before construction of Composition is complete) + if context.flags & ContextFlags.PROCESSING: return - # MODIFIED 11/29/21 END - # Don't bother for model-free optimization (see OptimizationControlMechanism_Model_Free) - # since state_input_ports specified or model-free optimization are entirely the user's responsibility; - # this is because they can't be programmatically validated against the agent_rep's evaluate() method. - # (This contrast with model-based optimization, for which there must be a state_input_port for every - # InputPort of every INPUT node of the agent_rep (see OptimizationControlMechanism_Model_Based). + # Don't bother for agent_rep that is not a Composition, since state_input_ports specified can be validated + # or assigned by default for a CompositionApproximator, and so are either up to its implementation or to + # do the validation and/or default assignment (this contrasts with agent_rep that is a Composition, for + # which there must be a state_input_port for every InputPort of every INPUT node of the agent_rep. if self.agent_rep_type != COMPOSITION: return - from psyneulink.core.compositions.composition import Composition, NodeRole, CompositionInterfaceMechanism + from psyneulink.core.compositions.composition import Composition + num_agent_rep_input_ports = len(self.agent_rep_input_ports) + num_state_feature_specs = len(self.state_feature_specs) + + if num_state_feature_specs < num_agent_rep_input_ports: + # agent_rep is Composition, but state_input_ports are missing for some agent_rep INPUT Node InputPorts + # so construct a state_input_port for each missing one, using state_feature_default; + # note: assumes INPUT Nodes added are at the end of the list in self.agent_rep_input_ports + # FIX: 3/24/22 - REFACTOR THIS TO CALL _parse_state_feature_specs? + state_input_ports = [] + local_context = Context(source=ContextFlags.METHOD) + default = self.state_feature_default + new_agent_rep_input_ports = self.agent_rep_input_ports[self.num_state_input_ports:] + for input_port in new_agent_rep_input_ports: + # Instantiate state_input_port for each agent_rep INPUT Node InputPort not already specified: + params = {INTERNAL_ONLY:True, + PARAMS: {}} + if default is None: + continue + if default == SHADOW_INPUTS: + params[SHADOW_INPUTS] = input_port + input_port_name = _shadowed_state_input_port_name(input_port.full_name, input_port.full_name) + self.state_feature_specs.append(input_port) + elif is_numeric(default): + params[VALUE]: default + input_port_name = _numeric_state_input_port_name(input_port.full_name) + self.state_feature_specs.append(default) + elif isinstance(default, (Port, Mechanism, Composition)): + params[PROJECTIONS]: default + self.state_feature_specs.append(default) + if self.state_feature_function: + # Use **state_feature_function** if specified by user in constructor + params = self._assign_state_feature_function(params) + state_input_port = _instantiate_port(name=input_port_name, + port_type=InputPort, + owner=self, + reference_value=input_port.value, + params=params, + context=local_context) + + state_input_ports.append(state_input_port) + # FIX: 3/24/22 - MAKE THIS A PROPERTY? (OR NEED IT REMAIN STABLE FOR LOOPS?) + self._num_state_feature_specs += 1 + + self.add_ports(state_input_ports, + update_variable=False, + context=local_context) + + # Assign OptimizationControlMechanism attributes + self.state_input_ports.extend(state_input_ports) + + # IMPLEMENTATION NOTE: Can't just assign agent_rep_input_ports to _specified_INPUT_Node_InputPorts_in_order + # below since there may be specifications in _specified_INPUT_Node_InputPorts_in_order + # for agent_rep INPUT Node InputPorts that have not yet been added to Composition + # (i.e., they are deferred) + # Update _specified_INPUT_Node_InputPorts_in_order with any new agent_rep_input_ports + for i in range(num_agent_rep_input_ports): + if i < len(self._specified_INPUT_Node_InputPorts_in_order): + # Replace existing ones (in case any deferred ones are "placemarked" with None) + self._specified_INPUT_Node_InputPorts_in_order[i] = self.agent_rep_input_ports[i] + else: + # Add any that have been added to Composition + self._specified_INPUT_Node_InputPorts_in_order.append(self.agent_rep_input_ports[i]) - def _get_all_input_nodes(comp): - """Return all input_nodes, including those for any Composition nested one level down. - Note: more deeply nested Compositions will either be served by their containing one(s) or own controllers - """ - _input_nodes = comp.get_nodes_by_role(NodeRole.INPUT) - input_nodes = [] - for node in _input_nodes: - if isinstance(node, Composition): - input_nodes.extend(_get_all_input_nodes(node)) - else: - input_nodes.append(node) - return input_nodes + if context._execution_phase == ContextFlags.PREPARING: + # Restrict validation until run time, when the Composition is expected to be fully constructed + self._validate_state_features(context) - if self.state_features: - # FIX: 11/26/21 - EXPLAIN THIS BEHAVIOR IN DOSCSTRING; - warnings.warn(f"The 'state_features' argument has been specified for {self.name}, that is being " - f"configured as a model-based {self.__class__.__name__} (i.e, one that uses a " - f"{Composition.componentType} as its agent_rep). This overrides automatic assignment of " - f"all inputs to its agent_rep ({self.agent_rep.name}) as the 'state_features'; only the " - f"ones specified will be used ({self.state_features}), and they must match the shape of the " - f"input to {self.agent_rep.name} when it is run. Remove this specification from the " - f"constructor for {self.name} if automatic assignment is preferred.") - - comp = self.agent_rep - # Ensure that all InputPorts shadowed by specified state_input_ports - # are in agent_rep or one of its nested Compositions - invalid_state_features = [input_port for input_port in self.state_input_ports - if (not (input_port.shadow_inputs.owner in - list(comp.nodes) + [n[0] for n in comp._get_nested_nodes()]) - and (not [input_port.shadow_inputs.owner.composition is x for x in - comp._get_nested_compositions() - if isinstance(input_port.shadow_inputs.owner, - CompositionInterfaceMechanism)]))] - if any(invalid_state_features): - raise OptimizationControlMechanismError(f"{self.name}, being used as controller for model-based " - f"optimization of {self.agent_rep.name}, has 'state_features' " - f"specified ({[d.name for d in invalid_state_features]}) that " - f"are missing from the Composition or any nested within it.") - - # Ensure that all InputPorts shadowed by specified state_input_ports - # reference INPUT Nodes of agent_rep or of a nested Composition - invalid_state_features = [input_port for input_port in self.state_input_ports - if (not (input_port.shadow_inputs.owner in _get_all_input_nodes(self.agent_rep)) - and (isinstance(input_port.shadow_inputs.owner, - CompositionInterfaceMechanism) - and not (input_port.shadow_inputs.owner.composition in - [nested_comp for nested_comp in comp._get_nested_compositions() - if nested_comp in comp.get_nodes_by_role(NodeRole.INPUT)])))] - if any(invalid_state_features): - raise OptimizationControlMechanismError(f"{self.name}, being used as controller for model-based " - f"optimization of {self.agent_rep.name}, has 'state_features' " - f"specified ({[d.name for d in invalid_state_features]}) that " - f"are not INPUT nodes for the Composition or any nested " - f"within it.") - return + self._update_state_input_port_names(context) - # Model-based agent_rep, but no state_features have been specified, - # so assign a state_input_port to shadow every InputPort of every INPUT node of agent_rep - shadow_input_ports = [] - for node in _get_all_input_nodes(self.agent_rep): - for input_port in node.input_ports: - if input_port.internal_only: - continue - # if isinstance(input_port.owner, CompositionInterfaceMechanism): - # input_port = input_port. - shadow_input_ports.append(input_port) - - local_context = Context(source=ContextFlags.METHOD) - state_input_ports_to_add = [] - # for input_port in input_ports_not_specified: - for input_port in shadow_input_ports: - input_port_name = f"{SHADOW_INPUT_NAME} of {input_port.owner.name}[{input_port.name}]" - params = {SHADOW_INPUTS: input_port, - INTERNAL_ONLY:True} - # Note: state_feature_functions has been validated _validate_params - # to have only a single function in for model-based agent_rep - if self.state_feature_functions: - params.update({FUNCTION: self._parse_state_feature_function(self.state_feature_functions)}) - state_input_ports_to_add.append(_instantiate_port(name=input_port_name, - port_type=InputPort, - owner=self, - reference_value=input_port.value, - params=params, - context=local_context)) - self.add_ports(state_input_ports_to_add, - update_variable=False, - context=local_context) - self.state_input_ports.extend(state_input_ports_to_add) + def _update_state_input_port_names(self, context=None): + """Update names of state_input_port for any newly instantiated INPUT Node InputPorts + + If its instantiation has NOT been DEFERRED, assert that: + - corresponding agent_rep INPUT Node InputPort is in Composition + - state_input_port either has path_afferents or it is for a numeric spec + + If it's instantiation HAS been DEFERRED, for any newly added agent_rep INPUT Node InputPorts: + - add agent_rep INPUT Node InputPort to _specified_INPUT_Node_InputPorts_in_order + - if state_input_port: + - HAS path_afferents, get source and generate new name + - does NOT have path_afferents, assert it is for a numeric spec and generate new name + - assign new name + """ + + num_agent_rep_input_ports = len(self.agent_rep_input_ports) + for i, state_input_port in enumerate(self.state_input_ports): + + if context and context.flags & ContextFlags.PREPARING: + # By run time, state_input_port should either have path_afferents assigned or be for a numeric spec + assert state_input_port.path_afferents or NUMERIC_STATE_INPUT_PORT_PREFIX in state_input_port.name, \ + f"PROGRAM ERROR: state_input_port instantiated for '{self.name}' ({state_input_port.name}) " \ + f"with a specification in '{STATE_FEATURES}' ({self.parameters.state_feature_specs.spec[i]}) " \ + f"that is not numeric but has not been assigned any path_afferents." + + if DEFERRED_STATE_INPUT_PORT_PREFIX not in state_input_port.name: + # state_input_port should be associated with existing agent_rep INPUT Node InputPort + assert i < num_agent_rep_input_ports, \ + f"PROGRAM ERROR: state_input_port instantiated for '{self.name}' ({state_input_port.name}) " \ + f"but there is no corresponding INPUT Node in '{AGENT_REP}'." + continue + + if i >= num_agent_rep_input_ports: + # No more new agent_rep INPUT Node InputPorts + break + + # Add new agent_rep INPUT Node InputPorts + self._specified_INPUT_Node_InputPorts_in_order[i] = self.agent_rep_input_ports[i] + agent_rep_input_port_name = self.agent_rep_input_ports[i].full_name + + if state_input_port.path_afferents: + # Non-numeric spec, so get source and change name accordingly + source_input_port_name = self.state_feature_specs[i].full_name + if 'INPUT FROM' in state_input_port.name: + new_name = _state_input_port_name(source_input_port_name, agent_rep_input_port_name) + elif SHADOWED_INPUT_STATE_INPUT_PORT_PREFIX in state_input_port.name: + new_name = _shadowed_state_input_port_name(source_input_port_name, agent_rep_input_port_name) + elif NUMERIC_STATE_INPUT_PORT_PREFIX in state_input_port.name: + # Numeric spec, so change name accordingly + new_name = _numeric_state_input_port_name(agent_rep_input_port_name) + else: + # Non-numeric but path_afferents haven't yet been assigned (will get tested again at run time) + continue + + # Change name of state_input_port + state_input_port.name = rename_instance_in_registry(registry=self._portRegistry, + category=INPUT_PORT, + new_name= new_name, + component=state_input_port) + + def _validate_state_features(self, context): + """Validate that state_features are legal and consistent with agent_rep. + + Called by _update_state_input_ports_for_controller, + - after new Nodes have been added to Composition + - and/or in run() as final check before execution. + + Ensure that: + - the number of state_feature_specs equals the number of external InputPorts of INPUT Nodes of agent_rep; + - if state_feature_specs are specified as a user dict, keys are valid INPUT Nodes of agent_rep; + - all InputPorts shadowed by specified state_input_ports are in agent_rep or one of its nested Compositions; + - any Projections received from output_ports are from Nodes in agent_rep or its nested Compositions; + - all InputPorts shadowed by state_input_ports reference INPUT Nodes of agent_rep or Compositions nested in it; + - state_features are compatible with input format for agent_rep Composition + """ + + # FIX: 3/4/22 - DO user_specs HAVE TO BE RE-VALIDATED? ?IS IT BECAUSE THEY MAY REFER TO NEWLY ADDED NODES? + from psyneulink.core.compositions.composition import \ + Composition, CompositionInterfaceMechanism, CompositionError, RunError, NodeRole + + comp = self.agent_rep + user_specs = self.parameters.state_feature_specs.spec + + if isinstance(user_specs, dict) and SHADOW_INPUTS in user_specs: + state_feature_specs = user_specs[SHADOW_INPUTS] + else: + state_feature_specs = user_specs + if isinstance(state_feature_specs, list): + # Convert list to dict (assuming list is in order of InputPorts of INPUT Nodes) + input_ports = comp.external_input_ports_of_all_input_nodes + if len(state_feature_specs) > len(input_ports): + nodes_not_in_agent_rep = [f"'{spec.name if isinstance(spec, Mechanism) else spec.owner.name}'" + for spec in self._get_specs_not_in_agent_rep(state_feature_specs)] + missing_nodes_str = (f", that includes the following: {', '.join(nodes_not_in_agent_rep)} " + f"missing from {self.agent_rep.name}" + if nodes_not_in_agent_rep else '') + raise OptimizationControlMechanismError( + f"The number of '{STATE_FEATURES}' specified for {self.name} ({len(state_feature_specs)}) " + f"is more than the number of INPUT Nodes ({len(input_ports)}) of the Composition assigned " + f"as its {AGENT_REP} ('{self.agent_rep.name}'){missing_nodes_str}.") + input_dict = {} + for i, spec in enumerate(state_feature_specs): + input_dict[input_ports[i]] = spec + state_features = state_feature_specs + elif isinstance(state_feature_specs, (set, dict)): + # If set or dict is specified, check that items of set or keys of dict are legal INPUT nodes: + self._validate_input_nodes(set(state_feature_specs), enforce=True) + if isinstance(state_feature_specs, dict): + # If dict is specified, get values for checks below + state_features = list(state_feature_specs.values()) + else: + state_features = list(state_feature_specs) + + # Include agent rep in error messages if it is not the same as self.composition + self_has_state_features_str = f"'{self.name}' has '{STATE_FEATURES}' specified " + agent_rep_str = ('' if self.agent_rep == self.composition + else f"both its `{AGENT_REP}` ('{self.agent_rep.name}') as well as ") + not_in_comps_str = f"that are missing from {agent_rep_str}'{self.composition.name}' and any " \ + f"{Composition.componentCategory}s nested within it." + + # Ensure that all InputPorts shadowed by specified state_input_ports + # are in agent_rep or one of its nested Compositions + invalid_state_features = [input_port for input_port in self.state_input_ports + if (input_port.shadow_inputs + and not (input_port.shadow_inputs.owner in + list(comp.nodes) + [n[0] for n in comp._get_nested_nodes()]) + and (not [input_port.shadow_inputs.owner.composition is x for x in + comp._get_nested_compositions() + if isinstance(input_port.shadow_inputs.owner, + CompositionInterfaceMechanism)]))] + # Ensure any Projections received from output_ports are from Nodes in agent_rep or its nested Compositions + for input_port in self.state_input_ports: + if input_port.shadow_inputs: + continue + try: + all(comp._get_source(p) for p in input_port.path_afferents) + except CompositionError: + invalid_state_features.append(input_port) + if any(invalid_state_features): + raise OptimizationControlMechanismError( + self_has_state_features_str + f"({[d.name for d in invalid_state_features]}) " + not_in_comps_str) + + # Ensure that all InputPorts shadowed by specified state_input_ports + # reference INPUT Nodes of agent_rep or of a nested Composition + invalid_state_features = [input_port for input_port in self.state_input_ports + if (input_port.shadow_inputs + and not (input_port.shadow_inputs.owner + in self.agent_rep_input_ports) + and (isinstance(input_port.shadow_inputs.owner, + CompositionInterfaceMechanism) + and not (input_port.shadow_inputs.owner.composition in + [nested_comp for nested_comp in comp._get_nested_compositions() + if nested_comp in comp.get_nodes_by_role(NodeRole.INPUT)])))] + if any(invalid_state_features): + raise OptimizationControlMechanismError( + self_has_state_features_str + f"({[d.name for d in invalid_state_features]}) " + not_in_comps_str) + + # # FOLLOWING IS FOR DEBUGGING: (TO SEE CODING ERRORS DIRECTLY) ----------------------- + # print("****** DEBUGGING CODE STILL IN OCM -- REMOVE FOR PROPER TESTING ************") + # inputs_dict, num_inputs = self.agent_rep._parse_input_dict(self.parameters.state_feature_values._get(context)) + # # END DEBUGGING --------------------------------------------------------------------- + + # Ensure state_features are compatible with input format for agent_rep Composition + try: + # Call this to check for errors in constructing inputs dict + self.agent_rep._parse_input_dict(self.parameters.state_feature_values._get(context)) + except (RunError, CompositionError) as error: + raise OptimizationControlMechanismError( + f"The '{STATE_FEATURES}' argument has been specified for '{self.name}' that is using a " + f"{Composition.componentType} ('{self.agent_rep.name}') as its agent_rep, but some of the " + f"specifications are not compatible with the inputs required by its 'agent_rep': '{error.error_value}' " + f"Use the get_inputs_format() method of '{self.agent_rep.name}' to see the required format, or " + f"remove the specification of '{STATE_FEATURES}' from the constructor for {self.name} " + f"to have them automatically assigned.") + except KeyError as error: # This occurs if a Node is illegal for a reason other than above, + pass # and will issue the corresponding error message. + except: # Legal Node specifications, but incorrect for input to agent_rep + specs = [f.full_name if hasattr(f, 'full_name') else (f.name if isinstance(f, Component) else f) + for f in state_features] + raise OptimizationControlMechanismError( + f"The '{STATE_FEATURES}' argument has been specified for '{self.name}' that is using a " + f"{Composition.componentType} ('{self.agent_rep.name}') as its agent_rep, but the " + f"'{STATE_FEATURES}' ({specs}) specified are not compatible with the inputs required by 'agent_rep' " + f"when it is executed. Use its get_inputs_format() method to see the required format, " + f"or remove the specification of '{STATE_FEATURES}' from the constructor for {self.name} " + f"to have them automatically assigned.") + + def _validate_monitor_for_control(self, nodes): + # Ensure all of the Components being monitored for control are in the agent_rep if it is Composition + if self.agent_rep_type == COMPOSITION: + try: + super()._validate_monitor_for_control(self.agent_rep._get_all_nodes()) + except ControlMechanismError as e: + raise OptimizationControlMechanismError(f"{self.name} has 'outcome_ouput_ports' that receive " + f"Projections from the following Components that do not belong " + f"to its {AGENT_REP} ({self.agent_rep.name}): {e.data}.") def _instantiate_output_ports(self, context=None): """Assign CostFunctions.DEFAULTS as default for cost_option of ControlSignals. @@ -1698,27 +2889,12 @@ def _instantiate_output_ports(self, context=None): def _instantiate_control_signals(self, context): """Size control_allocation and assign modulatory_signals + Set size of control_allocation equal to number of modulatory_signals. Assign each modulatory_signal sequentially to corresponding item of control_allocation. Assign RANDOMIZATION_CONTROL_SIGNAL for random_variables """ - # MODIFIED 11/21/21 NEW: - # FIX - PURPOSE OF THE FOLLOWING IS TO "CAPTURE" CONTROL SPECS MADE LOCALLY ON MECHANISMS IN THE COMP - # AND INSTANTIATE ControlSignals FOR THEM HERE, ALONG WITH THOSE SPECIFIED IN THE CONSTRUCTOR - # FOR THE OCM. ALSO CAPTURES DUPLICATES (SEE MOD BELOW). - # FIX: WITHOUT THIS, GET THE mod param ERROR; WITH IT, GET FAILURES IN test_control: - # TestModelBasedOptimizationControlMechanisms_Execution - # test_evc - # test_stateful_mechanism_in_simulation - # TestControlMechanisms: - # test_lvoc - # test_lvoc_both_prediction_specs - # test_lvoc_features_function - # if self.agent_rep and self.agent_rep.componentCategory=='Composition': - # control_signals_from_composition = self.agent_rep._get_control_signals_for_composition() - # self.output_ports.extend(control_signals_from_composition) - # MODIFIED 11/21/21 END control_signals = [] for i, spec in list(enumerate(self.output_ports)): control_signal = self._instantiate_control_signal(spec, context=context) @@ -1730,17 +2906,59 @@ def _instantiate_control_signals(self, context): # MODIFIED 11/20/21 END self.output_ports[i] = control_signal - self._create_randomization_control_signal( - context, - set_control_signal_index=False - ) - - self.defaults.value = np.tile( - control_signal.parameters.variable.default_value, - (len(self.output_ports), 1) - ) + self._create_randomization_control_signal(context) + self.defaults.value = np.tile(control_signal.parameters.variable.default_value, (len(self.output_ports), 1)) self.parameters.control_allocation._set(copy.deepcopy(self.defaults.value), context) + def _create_randomization_control_signal(self, context): + if self.num_estimates: + # must be SampleSpec in allocation_samples arg + randomization_seed_mod_values = SampleSpec(start=1, stop=self.num_estimates, step=1) + + # FIX: 11/3/21 noise PARAM OF TransferMechanism IS MARKED AS SEED WHEN ASSIGNED A DISTRIBUTION FUNCTION, + # BUT IT HAS NO PARAMETER PORT BECAUSE THAT PRESUMABLY IS FOR THE INTEGRATOR FUNCTION, + # BUT THAT IS NOT FOUND BY model.all_dependent_parameters + # FIX: 1/4/22: CHECK IF THIS WORKS WITH CFA + # (i.e., DOES IT [make sense to HAVE A random_variables ATTRIBUTE?) + # Get Components with variables to be randomized across estimates + # and construct ControlSignal to modify their seeds over estimates + if self.random_variables is ALL: + self.random_variables = self.agent_rep.random_variables + + if not self.random_variables: + warnings.warn(f"'{self.name}' has '{NUM_ESTIMATES} = {self.num_estimates}' specified, " + f"but its '{AGENT_REP}' ('{self.agent_rep.name}') has no random variables: " + f"'{RANDOMIZATION_CONTROL_SIGNAL}' will not be created, and num_estimates set to None.") + self.num_estimates = None + return + + randomization_control_signal = ControlSignal(name=RANDOMIZATION_CONTROL_SIGNAL, + modulates=[param.parameters.seed.port + for param in self.random_variables], + allocation_samples=randomization_seed_mod_values) + randomization_control_signal_index = len(self.output_ports) + randomization_control_signal._variable_spec = (OWNER_VALUE, randomization_control_signal_index) + + randomization_control_signal = self._instantiate_control_signal(randomization_control_signal, context) + + self.output_ports.append(randomization_control_signal) + + # Otherwise, assert that num_estimates and number of seeds generated by randomization_control_signal are equal + num_seeds = self.control_signals[RANDOMIZATION_CONTROL_SIGNAL].parameters.allocation_samples._get(context).num + assert self.num_estimates == num_seeds, \ + f"PROGRAM ERROR: The value of the {NUM_ESTIMATES} Parameter of {self.name}" \ + f"({self.num_estimates}) is not equal to the number of estimates that will be generated by " \ + f"its {RANDOMIZATION_CONTROL_SIGNAL} ControlSignal ({num_seeds})." + + function_search_space = self.function.parameters.search_space._get(context) + if randomization_control_signal_index >= len(function_search_space): + # TODO: check here if search_space has an item for each + # control_signal? or is allowing it through for future + # checks the right way? + + # search_space must be a SampleIterator + function_search_space.append(SampleIterator(randomization_seed_mod_values)) + def _instantiate_function(self, function, function_params=None, context=None): # this indicates a significant peculiarity of OCM, in that its function # corresponds to its value (control_allocation) rather than anything to @@ -1778,13 +2996,22 @@ def _instantiate_attributes_after_function(self, context=None): corrected_search_space = [SampleIterator(specification=search_space)] self.parameters.search_space._set(corrected_search_space, context) + try: + randomization_control_signal_index = self.control_signals.names.index(RANDOMIZATION_CONTROL_SIGNAL) + except ValueError: + randomization_control_signal_index = None + # Assign parameters to function (OptimizationFunction) that rely on OptimizationControlMechanism + # NOTE: as in this call, randomization_dimension must be set + # after search_space to avoid IndexError when getting + # num_estimates of function self.function.reset(**{ DEFAULT_VARIABLE: self.parameters.control_allocation._get(context), OBJECTIVE_FUNCTION: self.evaluate_agent_rep, # SEARCH_FUNCTION: self.search_function, # SEARCH_TERMINATION_FUNCTION: self.search_termination_function, SEARCH_SPACE: self.parameters.control_allocation_search_space._get(context), + RANDOMIZATION_DIMENSION: randomization_control_signal_index }) if isinstance(self.agent_rep, type): @@ -1794,18 +3021,12 @@ def _instantiate_attributes_after_function(self, context=None): self._initialize_composition_function_approximator(context) def _execute(self, variable=None, context=None, runtime_params=None): - """Find control_allocation that optimizes result of agent_rep.evaluate(). + """Find control_allocation that optimizes net_outcome of agent_rep.evaluate(). """ if self.is_initializing: return [defaultControlAllocation] - # # FIX: THESE NEED TO BE FOR THE PREVIOUS TRIAL; ARE THEY FOR FUNCTION_APPROXIMATOR? - # FIX: NEED TO MODIFY IF OUTCOME InputPorts ARE MOVED - self.parameters.state_feature_values._set(_parse_state_feature_values_from_variable( - self.num_outcome_input_ports, - variable), context) - # Assign default control_allocation if it is not yet specified (presumably first trial) control_allocation = self.parameters.control_allocation._get(context) if control_allocation is None: @@ -1818,29 +3039,38 @@ def _execute(self, variable=None, context=None, runtime_params=None): # have an adapt method, we also don't need to call the net_outcome getter net_outcome = self.parameters.net_outcome._get(context) - # FIX: NEED TO MODIFY IF OUTCOME InputPorts ARE MOVED - self.agent_rep.adapt(_parse_state_feature_values_from_variable(self.num_outcome_input_ports, variable), + self.agent_rep.adapt(self.parameters.state_feature_values._get(context), control_allocation, net_outcome, context=context) # freeze the values of current context, because they can be changed in between simulations, # and the simulations must start from the exact spot - self.agent_rep._initialize_from_context(self._get_frozen_context(context), - base_context=context, - override=True) + frozen_context = self._get_frozen_context(context) + + alt_controller = None + if self.agent_rep.controller is None: + try: + alt_controller = context.composition.controller + except AttributeError: + pass + + self.agent_rep._initialize_as_agent_rep( + frozen_context, base_context=context, alt_controller=alt_controller + ) # Get control_allocation that optimizes net_outcome using OptimizationControlMechanism's function # IMPLEMENTATION NOTE: skip ControlMechanism._execute since it is a stub method that returns input_values optimal_control_allocation, optimal_net_outcome, saved_samples, saved_values = \ - super(ControlMechanism,self)._execute(variable=control_allocation, - num_estimates=self.parameters.num_estimates._get(context), - context=context, - runtime_params=runtime_params - ) + super(ControlMechanism,self)._execute( + variable=control_allocation, + num_estimates=self.parameters.num_estimates._get(context), + context=context, + runtime_params=runtime_params + ) # clean up frozen values after execution - self.agent_rep._delete_contexts(self._get_frozen_context(context)) + self.agent_rep._clean_up_as_agent_rep(frozen_context, alt_controller=alt_controller) optimal_control_allocation = np.array(optimal_control_allocation).reshape((len(self.defaults.value), 1)) if self.function.save_samples: @@ -1854,7 +3084,12 @@ def _execute(self, variable=None, context=None, runtime_params=None): def _get_frozen_context(self, context=None): return Context(execution_id=f'{context.execution_id}{EID_FROZEN}') - def _set_up_simulation(self, base_context=Context(execution_id=None), control_allocation=None): + def _set_up_simulation( + self, + base_context=Context(execution_id=None), + control_allocation=None, + alt_controller=None + ): sim_context = copy.copy(base_context) sim_context.execution_id = self.get_next_sim_id(base_context, control_allocation) @@ -1863,13 +3098,17 @@ def _set_up_simulation(self, base_context=Context(execution_id=None), control_al except AttributeError: self.parameters.simulation_ids._set([sim_context.execution_id], base_context) - self.agent_rep._initialize_from_context(sim_context, self._get_frozen_context(base_context), override=False) + self.agent_rep._initialize_as_agent_rep( + sim_context, + base_context=self._get_frozen_context(base_context), + alt_controller=alt_controller + ) return sim_context - def _tear_down_simulation(self, sim_context=None): + def _tear_down_simulation(self, sim_context, alt_controller=None): if not self.agent_rep.parameters.retain_old_simulation_data._get(): - self.agent_rep._delete_contexts(sim_context, check_simulation_storage=True) + self.agent_rep._clean_up_as_agent_rep(sim_context, alt_controller=alt_controller) def evaluate_agent_rep(self, control_allocation, context=None, return_results=False): """Call `evaluate ` method of `agent_rep ` @@ -1903,11 +3142,17 @@ def evaluate_agent_rep(self, control_allocation, context=None, return_results=Fa # agent_rep is a Composition (since runs_simulations = True) if self.agent_rep.runs_simulations: + alt_controller = None + if self.agent_rep.controller is None: + try: + alt_controller = context.composition.controller + except AttributeError: + pass # KDM 5/20/19: crudely using default here because it is a stateless parameter # and there is a bug in setting parameter values on init, see TODO note above # call to self._instantiate_defaults around component.py:1115 if self.defaults.search_statefulness: - new_context = self._set_up_simulation(context, control_allocation) + new_context = self._set_up_simulation(context, control_allocation, alt_controller) else: new_context = context @@ -1926,7 +3171,7 @@ def evaluate_agent_rep(self, control_allocation, context=None, return_results=Fa return_results=return_results) context.composition = old_composition if self.defaults.search_statefulness: - self._tear_down_simulation(new_context) + self._tear_down_simulation(new_context, alt_controller) # FIX: THIS SHOULD BE REFACTORED TO BE HANDLED THE SAME AS A Composition AS agent_rep # If results of the simulation should be returned then, do so. agent_rep's evaluate method will @@ -1948,65 +3193,6 @@ def evaluate_agent_rep(self, control_allocation, context=None, return_results=Fa context=context ) - def _create_randomization_control_signal( - self, - context, - set_control_signal_index=True - ): - if self.num_estimates: - # must be SampleSpec in allocation_samples arg - randomization_seed_mod_values = SampleSpec(start=1, stop=self.num_estimates, step=1) - - # FIX: 11/3/21 noise PARAM OF TransferMechanism IS MARKED AS SEED WHEN ASSIGNED A DISTRIBUTION FUNCTION, - # BUT IT HAS NO PARAMETER PORT BECAUSE THAT PRESUMABLY IS FOR THE INTEGRATOR FUNCTION, - # BUT THAT IS NOT FOUND BY model.all_dependent_parameters - # Get Components with variables to be randomized across estimates - # and construct ControlSignal to modify their seeds over estimates - if self.random_variables is ALL: - self.random_variables = self.agent_rep.random_variables - - randomization_control_signal = ControlSignal( - name=RANDOMIZATION_CONTROL_SIGNAL, - modulates=[ - param.parameters.seed.port - for param in self.random_variables - ], - allocation_samples=randomization_seed_mod_values - ) - randomization_control_signal_index = len(self.output_ports) - randomization_control_signal._variable_spec = ( - OWNER_VALUE, randomization_control_signal_index - ) - randomization_control_signal = self._instantiate_control_signal( - randomization_control_signal, context - ) - self.output_ports.append(randomization_control_signal) - - # Otherwise, assert that num_estimates and number of seeds generated by randomization_control_signal are equal - num_seeds = self.control_signals[RANDOMIZATION_CONTROL_SIGNAL].parameters.allocation_samples._get(context).num - assert self.num_estimates == num_seeds, \ - f"PROGRAM ERROR: The value of the 'num_estimates' Parameter of {self.name}" \ - f"({self.num_estimates}) is not equal to the number of estimates that will be generated by " \ - f"its {RANDOMIZATION_CONTROL_SIGNAL} ControlSignal ({num_seeds})." - - function_search_space = self.function.parameters.search_space._get(context) - if randomization_control_signal_index >= len(function_search_space): - # TODO: check here if search_space has an item for each - # control_signal? or is allowing it through for future - # checks the right way? - - # search_space must be a SampleIterator - function_search_space.append(SampleIterator(randomization_seed_mod_values)) - - # workaround for fact that self.function.reset call in - # _instantiate_attributes_after_function expects to use - # old/unset values when running _update_default_variable, - # which calls self.agent_rep.evaluate and is brittle. - if set_control_signal_index: - self.function.parameters.randomization_dimension._set( - randomization_control_signal_index, context - ) - def _get_evaluate_input_struct_type(self, ctx): # We construct input from optimization function input return ctx.get_input_struct_type(self.function) @@ -2039,7 +3225,7 @@ def _gen_llvm_net_outcome_function(self, *, ctx, tags=frozenset()): "output_ports", None) # calculate cost function - total_cost = builder.alloca(ctx.float_ty) + total_cost = builder.alloca(ctx.float_ty, name="total_cost") builder.store(ctx.float_ty(-0.0), total_cost) for i, op in enumerate(self.output_ports): op_i_params = builder.gep(op_params, [ctx.int32_ty(0), @@ -2049,15 +3235,25 @@ def _gen_llvm_net_outcome_function(self, *, ctx, tags=frozenset()): op_f = ctx.import_llvm_function(op, tags=frozenset({"costs"})) - op_in = builder.alloca(op_f.args[2].type.pointee) + op_in = builder.alloca(op_f.args[2].type.pointee, + name="output_port_cost_in") # copy allocation_sample, the input is 1-element array in a struct data_in = builder.gep(allocation_sample, [ctx.int32_ty(0), ctx.int32_ty(i)]) - data_out = builder.gep(op_in, [ctx.int32_ty(0), ctx.int32_ty(0), - ctx.int32_ty(0)]) + + # Port input struct is {data, modulation} if modulation is present, + # otherwise it's just data + if len(op.mod_afferents) > 0: + data_out = builder.gep(op_in, [ctx.int32_ty(0), ctx.int32_ty(0), + ctx.int32_ty(0)]) + else: + data_out = builder.gep(op_in, [ctx.int32_ty(0), ctx.int32_ty(0)]) + if data_in.type != data_out.type: - warnings.warn("Shape mismatch: Allocation sample '{}' ({}) doesn't match input port input ({}).".format(i, self.parameters.control_allocation_search_space.get(), op.defaults.variable)) + warnings.warn(f"Shape mismatch: Allocation sample '{i}' " + f"({self.parameters.control_allocation_search_space.get()}) " + f"doesn't match input port input ({op.defaults.variable}).") assert len(data_out.type.pointee) == 1 data_out = builder.gep(data_out, [ctx.int32_ty(0), ctx.int32_ty(0)]) @@ -2084,13 +3280,10 @@ def _gen_llvm_net_outcome_function(self, *, ctx, tags=frozenset()): builder.ret_void() return llvm_func - def _gen_llvm_evaluate_alloc_range_function(self, *, ctx:pnlvm.LLVMBuilderContext, - tags=frozenset()): + def _gen_llvm_evaluate_alloc_range_function(self, *, ctx:pnlvm.LLVMBuilderContext, tags=frozenset()): assert "evaluate" in tags assert "alloc_range" in tags - evaluate_f = ctx.import_llvm_function(self, - tags=tags - {"alloc_range"}) - + evaluate_f = ctx.import_llvm_function(self, tags=tags - {"alloc_range"}) args = [*evaluate_f.type.pointee.args[:2], ctx.int32_ty, ctx.int32_ty, @@ -2113,19 +3306,18 @@ def _gen_llvm_evaluate_alloc_range_function(self, *, ctx:pnlvm.LLVMBuilderContex search_space = pnlvm.helpers.get_param_ptr(builder, self.function, func_params, "search_space") - allocation = builder.alloca(evaluate_f.args[2].type.pointee) + allocation = builder.alloca(evaluate_f.args[2].type.pointee, name="allocation") with pnlvm.helpers.for_loop(builder, start, stop, stop.type(1), "alloc_loop") as (b, idx): func_out = b.gep(arg_out, [idx]) - pnlvm.helpers.create_allocation(b, allocation, search_space, idx) + pnlvm.helpers.create_sample(b, allocation, search_space, idx) b.call(evaluate_f, [params, state, allocation, func_out, arg_in, data]) builder.ret_void() return llvm_func - def _gen_llvm_evaluate_function(self, *, ctx:pnlvm.LLVMBuilderContext, - tags=frozenset()): + def _gen_llvm_evaluate_function(self, *, ctx:pnlvm.LLVMBuilderContext, tags=frozenset()): assert "evaluate" in tags args = [ctx.get_param_struct_type(self.agent_rep).as_pointer(), ctx.get_state_struct_type(self.agent_rep).as_pointer(), @@ -2152,7 +3344,7 @@ def _gen_llvm_evaluate_function(self, *, ctx:pnlvm.LLVMBuilderContext, const_state = self.agent_rep._get_state_initializer(None) builder.store(comp_state.type.pointee(const_state), comp_state) else: - builder.store(builder.load(base_comp_state), comp_state) + builder = pnlvm.helpers.memcpy(builder, comp_state, base_comp_state) # Create a simulation copy of composition data comp_data = builder.alloca(base_comp_data.type.pointee, name="data_copy") @@ -2160,7 +3352,7 @@ def _gen_llvm_evaluate_function(self, *, ctx:pnlvm.LLVMBuilderContext, const_data = self.agent_rep._get_data_initializer(None) builder.store(comp_data.type.pointee(const_data), comp_data) else: - builder.store(builder.load(base_comp_data), comp_data) + builder = pnlvm.helpers.memcpy(builder, comp_data, base_comp_data) # Evaluate is called on composition controller assert self.composition.controller is self @@ -2247,19 +3439,19 @@ def _gen_llvm_evaluate_function(self, *, ctx:pnlvm.LLVMBuilderContext, param_is_zero = builder.icmp_unsigned("==", num_trials_per_estimate, ctx.int32_ty(0)) num_sims = builder.select(param_is_zero, ctx.int32_ty(1), - num_trials_per_estimate, "corrected_estimates") + num_trials_per_estimate, "corrected_trials per_estimate") - num_runs = builder.alloca(ctx.int32_ty, name="num_runs") - builder.store(num_sims, num_runs) + num_trials = builder.alloca(ctx.int32_ty, name="num_sim_trials") + builder.store(num_sims, num_trials) # We only provide one input - num_inputs = builder.alloca(ctx.int32_ty, name="num_inputs") + num_inputs = builder.alloca(ctx.int32_ty, name="num_sim_inputs") builder.store(num_inputs.type.pointee(1), num_inputs) # Simulations don't store output comp_output = sim_f.args[4].type(None) builder.call(sim_f, [comp_state, comp_params, comp_data, comp_input, - comp_output, num_runs, num_inputs]) + comp_output, num_trials, num_inputs]) # Extract objective mechanism value idx = self.agent_rep._get_node_index(self.objective_mechanism) @@ -2306,7 +3498,7 @@ def _gen_llvm_function(self, *, ctx:pnlvm.LLVMBuilderContext, tags:frozenset): def _gen_llvm_invoke_function(self, ctx, builder, function, params, context, variable, *, tags:frozenset): fun = ctx.import_llvm_function(function) - fun_out = builder.alloca(fun.args[3].type.pointee) + fun_out = builder.alloca(fun.args[3].type.pointee, name="func_out") args = [params, context, variable, fun_out] # If we're calling compiled version of Composition.evaluate, @@ -2317,86 +3509,161 @@ def _gen_llvm_invoke_function(self, ctx, builder, function, params, context, var return fun_out, builder - def _gen_llvm_output_port_parse_variable(self, ctx, builder, params, context, value, port): - i = self.output_ports.index(port) - # Allocate the only member of the port input struct - oport_input = builder.alloca(ctx.get_input_struct_type(port).elements[0]) - # FIXME: workaround controller signals occasionally being 2d - dest_ptr = pnlvm.helpers.unwrap_2d_array(builder, oport_input) - dest_ptr = builder.gep(dest_ptr, [ctx.int32_ty(0), ctx.int32_ty(0)]) - val_ptr = builder.gep(value, [ctx.int32_ty(0), ctx.int32_ty(0), ctx.int32_ty(i)]) - builder.store(builder.load(val_ptr), dest_ptr) - return oport_input - - # @property - # def state_feature_values(self): - # if hasattr(self.agent_rep, 'model_based_optimizer') and self.agent_rep.model_based_optimizer is self: - # return self.agent_rep._get_predicted_input() - # else: - # return np.array(np.array(self.variable[1:]).tolist()) + def _gen_llvm_output_port_parse_variable(self, ctx, builder, params, state, value, port): + # The function returns (sample_optimal, value_optimal), + # but the value of mechanism is only 'sample_optimal' + value = builder.gep(value, [ctx.int32_ty(0), ctx.int32_ty(0)]) + return super()._gen_llvm_output_port_parse_variable(ctx, builder, params, state, value, port) @property def agent_rep_type(self): from psyneulink.core.compositions.compositionfunctionapproximator import CompositionFunctionApproximator - if isinstance(self.agent_rep, CompositionFunctionApproximator): + if (isinstance(self.agent_rep, CompositionFunctionApproximator) + or self.agent_rep.componentCategory is COMPOSITION_FUNCTION_APPROXIMATOR): return COMPOSITION_FUNCTION_APPROXIMATOR elif self.agent_rep.componentCategory=='Composition': return COMPOSITION else: return None - def _parse_state_feature_function(self, feature_function): - if isinstance(feature_function, Function): - return copy.deepcopy(feature_function) - else: - return feature_function + @property + def agent_rep_input_ports(self): + return self._get_agent_rep_input_receivers(type=PORT) - @tc.typecheck - def _parse_state_feature_specs(self, state_features, feature_functions, context=None): - """Parse entries of state_features into InputPort spec dictionaries - Set INTERNAL_ONLY entry of params dict of InputPort spec dictionary to True - (so that inputs to Composition are not required if the specified state is on an INPUT Mechanism) - Assign functions specified in **state_feature_functions** to InputPorts for all state_features - Return list of InputPort specification dictionaries + @property + def num_state_input_ports(self): + try: + return len(self.state_input_ports) + except: + return 0 + + # @property + # def _num_state_feature_specs(self): + # return len(self.state_feature_specs) + + @property + def state_features(self): + """Return {InputPort name: source name} for all state_features. + If state_feature_spec is numeric for a Node, assign its value as the source + If existing INPUT Node is not specified in state_feature_specs, assign state_feature_default as source + If an InputPort is referenced in state_feature_specs that is not yet in agent_rep, + assign "DEFERRED INPUT NODE OF " as key for the entry; + (it should be resolved by runtime, or an error is generated). + If a state_feature_spec is referenced that is not yet in ocm.composition, + assign " NOT (YET) IN " as the value of the entry; + (it should be resolved by runtime, or an error is generated). """ - _state_input_ports = _parse_shadow_inputs(self, state_features) + self._update_state_input_port_names() - parsed_features = [] + agent_rep_input_ports = self.agent_rep.external_input_ports_of_all_input_nodes + state_features_dict = {} + state_input_port_num = 0 - for spec in _state_input_ports: - # MODIFIED 11/29/21 NEW: - # If optimization uses Composition, assume that shadowing a Mechanism means shadowing its primary InputPort - if isinstance(spec, Mechanism) and self.agent_rep_type == COMPOSITION: - # FIX: 11/29/21: MOVE THIS TO _parse_shadow_inputs - # (ADD ARG TO THAT FOR DOING SO, OR RESTRICTING TO INPUTPORTS IN GENERAL) - if len(spec.input_ports)!=1: - raise OptimizationControlMechanismError(f"A Mechanism ({spec.name}) is specified in the " - f"'{STATE_FEATURES}' arg for {self.name} that has " - f"more than one InputPort; a specific one or subset " - f"of them must be specified.") - spec = spec.input_port - parsed_spec = _parse_port_spec(owner=self, port_type=InputPort, port_spec=spec) # returns InputPort dict - parsed_spec[PARAMS].update({INTERNAL_ONLY:True, - PROJECTIONS:None}) - if feature_functions: - if isinstance(feature_functions, dict) and spec in feature_functions: - feat_fct = feature_functions.pop(spec) + # Process all state_feature_specs, that may include ones for INPUT Nodes not (yet) in agent_rep + for i in range(self._num_state_feature_specs): + spec = self.state_feature_specs[i] + input_port = self._specified_INPUT_Node_InputPorts_in_order[i] + # Get key for state_features dict + if input_port in agent_rep_input_ports: + # Specified InputPort belongs to an INPUT Node already in agent_rep, so use as key + key = input_port.full_name + else: + # Specified InputPort is not (yet) in agent_rep + input_port_name = (f"{input_port.full_name}" if input_port + else f"{str(i-len(agent_rep_input_ports))}") + key = _deferred_agent_rep_input_port_name(input_port_name, self.agent_rep.name) + + # Get source for state_features dict + if spec is None: + # no state_input_port has been constructed, so assign source as None + source = None + else: + if is_numeric(spec): + # assign numeric spec as source + source = spec + # increment state_port_num, since one is implemented for numeric spec else: - feat_fct = feature_functions - parsed_spec.update({FUNCTION: self._parse_state_feature_function(feat_fct)}) - parsed_spec = [parsed_spec] # so that extend works below + # spec is a Component, so get distal source of Projection to state_input_port + # (spec if it is an OutputPort; or ??input_CIM.output_port if it spec for shadowing an input?? + state_input_port = self.state_input_ports[state_input_port_num] + if self.composition._is_in_composition(spec): + source = spec.full_name + else: + source = _deferred_state_feature_spec_msg(spec.full_name, self.composition.name) + state_input_port_num += 1 - parsed_features.extend(parsed_spec) + state_features_dict[key] = source - return parsed_features + return state_features_dict @property - def num_state_input_ports(self): - try: - return len(self.state_input_ports) - except: - return 0 + def state(self): + """Array that is concatenation of state_feature_values and control_allocations""" + # Use self.state_feature_values Parameter if state_features specified; else use state_input_port values + return list(self.state_feature_values.values()) + list(self.control_allocation) + + @property + def state_distal_sources_and_destinations_dict(self): + """Return dict with (Port, Node, Composition, index) tuples as keys and corresponding state[index] as values. + Initial entries are for sources of the state_feature_values (i.e., distal afferents for state_input_ports) + and subsequent entries are for destination parameters modulated by the OptimizationControlMechanism's + ControlSignals (i.e., distal efferents of its ControlProjections). + Note: the index is required, since a state_input_port may have more than one afferent Projection + (that is, a state_feature_value may be determined by Projections from more than one source), + and a ControlSignal may have more than one ControlProjection (that is, a given element of the + control_allocation may apply to more than one Parameter). However, for state_input_ports that shadow + a Node[InputPort], only that Node[InputPort] is listed in state_dict even if the Node[InputPort] being + shadowed has more than one afferent Projection (this is because it is the value of the Node[InputPort] + (after it has processed the value of its afferent Projections) that determines the input to the + state_input_port. + """ + sources_and_destinations = self.state_feature_sources + sources_and_destinations.update(self.control_signal_destinations) + return sources_and_destinations + + @property + def state_feature_sources(self): + """Dict with {InputPort: source} for all INPUT Nodes of agent_rep, and sources in **state_feature_specs. + Used by state_distal_sources_and_destinations_dict() + """ + state_dict = {} + # FIX: 3/4/22 - THIS NEEDS TO HANDLE BOTH state_input_ports BUT ALSO state_feature_values FOR WHICH THERE ARE NO INPUTPORTS + specified_state_features = [spec for spec in self.state_feature_specs if spec is not None] + for state_index, port in enumerate(self.state_input_ports): + if port.path_afferents: + get_info_method = self.composition._get_source + # MODIFIED 1/8/22: ONLY ONE PROJECTION PER STATE FEATURE + if port.shadow_inputs: + port = port.shadow_inputs + if port.owner in self.composition.nodes: + composition = self.composition + else: + composition = port.path_afferents[0].sender.owner.composition + get_info_method = composition._get_destination + source_port, node, comp = get_info_method(port.path_afferents[0]) + else: + if port.default_input is DEFAULT_VARIABLE: + source_port = DEFAULT_VARIABLE + node = None + comp = None + else: + source_port = specified_state_features[state_index] + node = None + comp = None + state_dict.update({(source_port, node, comp, state_index):self.state[state_index]}) + return state_dict + + @property + def control_signal_destinations(self): + state_dict = {} + state_index = self.num_state_input_ports + # Get recipients of control_allocations values of state: + for ctl_index, control_signal in enumerate(self.control_signals): + for projection in control_signal.efferents: + port, node, comp = self.composition._get_destination(projection) + state_dict.update({(port, node, comp, state_index + ctl_index):self.state[state_index + ctl_index]}) + return state_dict @property def _model_spec_parameter_blacklist(self): @@ -2421,19 +3688,3 @@ def _initialize_composition_function_approximator(self, context): self.agent_rep.initialize(features_array=np.array(self.defaults.variable[1:]), control_signals = self.control_signals, context=context) - - # FIX: THE FOLLOWING SHOULD BE MERGED WITH HANDLING OF PredictionMechanisms FOR ORIG MODEL-BASED APPROACH; - # FIX: SHOULD BE GENERALIZED AS SOMETHING LIKE update_feature_values - @tc.typecheck - @handle_external_context() - def add_state_features(self, features, context=None): - """Add InputPorts and Projections to OptimizationControlMechanism for state_features used to - predict `net_outcome ` - - **state_features** argument can use any of the forms of specification allowed for InputPort(s) - """ - - if features: - features = self._parse_state_feature_specs(features=features, - context=context) - self.add_ports(InputPort, features) diff --git a/psyneulink/core/components/mechanisms/modulatory/learning/learningmechanism.py b/psyneulink/core/components/mechanisms/modulatory/learning/learningmechanism.py index 663b65a2a6d..c61c02501f5 100644 --- a/psyneulink/core/components/mechanisms/modulatory/learning/learningmechanism.py +++ b/psyneulink/core/components/mechanisms/modulatory/learning/learningmechanism.py @@ -46,7 +46,7 @@ `, generated by the `primary_learned_projection` and its associated `output_source`. All of the MappingProjection(s) modified by a LearningMechanism must project from one `ProcessingMechanism ` to another in the same `Composition`. The learning components of a Composition can be -displayed using the Composition's `show_graph`show_graph ` method with its +displayed using the Composition's `show_graph`show_graph ` method with its **show_learning** argument assigned `True` or *ALL*. .. _LearningMechanism_Note @@ -370,8 +370,7 @@ Composition, all of the Components required for learning are created automatically. The types of Components that are generated depend on the type of learning specified and the configuration of the `Composition `, as described below. All of the learning Components of a Composition can be displayed using its `show_graph -``show_graph ` method with -the **show_learning** argument assigned `True` or *ALL*. +`. By providing the standard Components for communication among `Mechanisms ` (`InputPorts ` and `OutputPorts `), Mechanisms (and/or other Compositions) that are `INPUT ` `Nodes ` of a Composition can receive inputs from the environment - in the same way that any other Node receives inputs, from `afferent Projections ` (in + in the same way that any other Node receives inputs, from `afferent Projections ` (in this case, the `input_CIM ` of the Composition to which they belong); and, similarly, Components that are `OUTPUT ` `Nodes ` of a Composition can either report their outputs to the Composition or, if they are in a `nested Composition `, send their outputs to @@ -67,7 +67,7 @@ `), and the value of which is a tuple containing the corresponding (`InputPort`, `OutputPort`) pair used to transmit the information to or from the CompositionInterfaceMechanism. CompositionIntefaceMechanisms can be seen graphically using the `show_cim ` option of the -Composition's `show_graph ` method (see figure below). +Composition's `show_graph ` method (see figure below). .. figure:: _static/CIM_figure.svg @@ -232,40 +232,105 @@ def remove_ports(self, ports, context=None): output_ports_marked_for_deletion.add(port) self.user_added_ports[OUTPUT_PORTS] = self.user_added_ports[OUTPUT_PORTS] - output_ports_marked_for_deletion - def _get_destination_node_for_input_port(self, input_port, comp=None): - """Return Port, Node and Composition for destination of projection from input_CIM to (possibly nested) node""" + # def _get_source_node_for_input_CIM(self, port, start_comp=None, end_comp=None): + # """Return Port, Node and Composition for source of projection to input_CIM from (possibly nested) outer comp + # **port** should be an InputPort or OutputPort of the CompositionInterfaceMechanism; + # **comp** specifies the Composition at which to begin the search (or continue it when called recursively; + # assumes the current CompositionInterfaceMechanism's Composition by default + # """ + # # Ensure method is being called on an output_CIM + # assert self == self.composition.input_CIM + # # CIM MAP ENTRIES: [SENDER PORT, [output_CIM InputPort, output_CIM OutputPort]] + # # Get sender to input_port of output_CIM + # comp = start_comp or self.composition + # port_map = port.owner.port_map + # idx = 0 if isinstance(port, InputPort) else 1 + # input_port = [port_map[k][0] for k in port_map if port_map[k][idx] is port] + # assert len(input_port)==1, f"PROGRAM ERROR: Expected exactly 1 input_port for {port.name} " \ + # f"in port_map for {port.owner}; found {len(input_port)}." + # # assert len(input_port[0].path_afferents)==1, f"PROGRAM ERROR: Port ({input_port.name}) expected to have " \ + # # f"just one path_afferent; has {len(input_port.path_afferents)}." + # if not input_port[0].path_afferents or comp == end_comp: + # return input_port[0], input_port[0].owner, comp + # sender = input_port[0].path_afferents[0].sender + # # if not isinstance(sender.owner, CompositionInterfaceMechanism): + # return self._get_source_node_for_input_CIM(sender, sender.owner.composition) + + def _get_destination_info_from_input_CIM(self, port, comp=None): + """Return Port, Node and Composition for "ultimate" destination of projection to **port**. + **port**: InputPort or OutputPort of the input_CIM to which the projection of interest projects; + used to find destination (key) in output_CIM's port_map. + **comp**: Composition at which to begin the search (or continue it when called recursively); + assumes the Composition for the input_CIM to which **port** belongs by default + """ + # Ensure method is being called on an input_CIM + assert self == self.composition.input_CIM # CIM MAP ENTRIES: [RECEIVER PORT, [input_CIM InputPort, input_CIM OutputPort]] - # Get sender to input_port of CIM for corresponding output_port - comp = comp or self - port_map = input_port.owner.port_map - output_port = [port_map[k][1] for k in port_map if port_map[k][0] is input_port] - assert len(output_port)==1, f"PROGRAM ERROR: Expected only 1 output_port for {input_port.name} " \ - f"in port_map for {input_port.owner}; found {len(output_port)}." + # Get receiver of output_port of input_CIM + comp = comp or self.composition + port_map = port.owner.port_map + idx = 0 if isinstance(port, InputPort) else 1 + output_port = [port_map[k][1] for k in port_map if port_map[k][idx] is port] + assert len(output_port)==1, f"PROGRAM ERROR: Expected exactly 1 output_port for {port.name} " \ + f"in port_map for {port.owner}; found {len(output_port)}." assert len(output_port[0].efferents)==1, f"PROGRAM ERROR: Port ({output_port.name}) expected to have " \ f"just one efferent; has {len(output_port.efferents)}." receiver = output_port[0].efferents[0].receiver if not isinstance(receiver.owner, CompositionInterfaceMechanism): return receiver, receiver.owner, comp - return self._get_destination_node_for_input_port(receiver, receiver.owner.composition) - - def _get_source_node_for_output_port(self, output_port, comp=None): - """Return Port, Node and Composition for source of projection to output_CIM from (possibly nested) node""" + return self._get_destination_info_from_input_CIM(receiver, receiver.owner.composition) + + def _get_modulated_info_from_parameter_CIM(self, port, comp=None): + """Return Port, Node and Composition for parameter modulated by ControlSignal that projects to parameter_CIM. + **port**: InputPort or OutputPort of the parameter_CIM to which the ControlSignal projects; + used to find destination (key) in parameter_CIM's port_map. + **comp**: Composition at which to begin the search (or continue it when called recursively); + assumes the Composition for the parameter_CIM to which **port** belongs by default. + """ + # Ensure method is being called on a parameter_CIM + assert self == self.composition.parameter_CIM + # CIM MAP ENTRIES: [RECEIVER PORT, [input_CIM InputPort, input_CIM OutputPort]] + # Get receiver of output_port of input_CIM + comp = comp or self.composition + port_map = port.owner.port_map + idx = 0 if isinstance(port, InputPort) else 1 + output_port = [port_map[k][1] for k in port_map if port_map[k][idx] is port] + assert len(output_port)==1, f"PROGRAM ERROR: Expected exactly 1 output_port for {port.name} " \ + f"in port_map for {port.owner}; found {len(output_port)}." + assert len(output_port[0].efferents)==1, f"PROGRAM ERROR: Port ({output_port.name}) expected to have " \ + f"just one efferent; has {len(output_port.efferents)}." + receiver = output_port[0].efferents[0].receiver + if not isinstance(receiver.owner, CompositionInterfaceMechanism): + return receiver, receiver.owner, comp + return self._get_modulated_info_from_parameter_CIM(receiver, receiver.owner.composition) + + def _get_source_info_from_output_CIM(self, port, comp=None): + """Return Port, Node and Composition for "original" source of projection from **port**. + **port** InputPort or OutputPort of the output_CIM from which the projection of interest projects; + used to find source (key) in output_CIM's port_map. + **comp** Composition at which to begin the search (or continue it when called recursively); + assumes the current CompositionInterfaceMechanism's Composition by default. + """ + # Ensure method is being called on an output_CIM + assert self == self.composition.output_CIM, f"_get_source_info_from_output_CIM called on {self.name} " \ + f"which is not an output_CIM" # CIM MAP ENTRIES: [SENDER PORT, [output_CIM InputPort, output_CIM OutputPort]] - # Get sender to input_port of CIM for corresponding output_port - comp = comp or self - port_map = output_port.owner.port_map - input_port = [port_map[k][0] for k in port_map if port_map[k][1] is output_port] - assert len(input_port)==1, f"PROGRAM ERROR: Expected only 1 input_port for {output_port.name} " \ - f"in port_map for {output_port.owner}; found {len(input_port)}." + # Get sender to input_port of output_CIM + comp = comp or self.composition + port_map = port.owner.port_map + idx = 0 if isinstance(port, InputPort) else 1 + input_port = [port_map[k][0] for k in port_map if port_map[k][idx] is port] + assert len(input_port)==1, f"PROGRAM ERROR: Expected exactly 1 input_port for {port.name} " \ + f"in port_map for {port.owner}; found {len(input_port)}." assert len(input_port[0].path_afferents)==1, f"PROGRAM ERROR: Port ({input_port.name}) expected to have " \ f"just one path_afferent; has {len(input_port.path_afferents)}." sender = input_port[0].path_afferents[0].sender if not isinstance(sender.owner, CompositionInterfaceMechanism): return sender, sender.owner, comp - return self._get_source_node_for_output_port(sender, sender.owner.composition) + return self._get_source_info_from_output_CIM(sender, sender.owner.composition) def _sender_is_probe(self, output_port): """Return True if source of output_port is a PROBE Node of the Composition to which it belongs""" from psyneulink.core.compositions.composition import NodeRole - port, node, comp = self._get_source_node_for_output_port(output_port, self.composition) + port, node, comp = self._get_source_info_from_output_CIM(output_port, self.composition) return NodeRole.PROBE in comp.get_roles_by_node(node) diff --git a/psyneulink/core/components/mechanisms/processing/integratormechanism.py b/psyneulink/core/components/mechanisms/processing/integratormechanism.py index 9b479cc0b71..4da4319a3bc 100644 --- a/psyneulink/core/components/mechanisms/processing/integratormechanism.py +++ b/psyneulink/core/components/mechanisms/processing/integratormechanism.py @@ -89,11 +89,13 @@ from psyneulink.core.components.functions.stateful.integratorfunctions import AdaptiveIntegrator from psyneulink.core.components.mechanisms.processing.processingmechanism import ProcessingMechanism_Base from psyneulink.core.components.mechanisms.mechanism import Mechanism +from psyneulink.core.globals.json import _substitute_expression_args from psyneulink.core.globals.keywords import \ DEFAULT_VARIABLE, INTEGRATOR_MECHANISM, VARIABLE, PREFERENCE_SET_NAME from psyneulink.core.globals.parameters import Parameter from psyneulink.core.globals.preferences.basepreferenceset import is_pref_set, REPORT_OUTPUT_PREF from psyneulink.core.globals.preferences.preferenceset import PreferenceEntry, PreferenceLevel +from psyneulink.core.globals.utilities import parse_valid_identifier __all__ = [ 'DEFAULT_RATE', 'IntegratorMechanism', 'IntegratorMechanismError' @@ -228,3 +230,32 @@ def _handle_default_variable(self, default_variable=None, size=None, input_ports input_ports=input_ports, function=function, params=params) + + def as_mdf_model(self): + import modeci_mdf.mdf as mdf + + model = super().as_mdf_model() + function_model = [ + f for f in model.functions + if f.id == parse_valid_identifier(self.function.name) + ][0] + assert function_model.id == parse_valid_identifier(self.function.name), (function_model.id, parse_valid_identifier(self.function.name)) + + for _, func_param in function_model.metadata['function_stateful_params'].items(): + model.parameters.append(mdf.Parameter(**func_param)) + + res = self.function._get_mdf_noise_function() + try: + main_noise_function, extra_noise_functions = res + except TypeError: + pass + else: + main_noise_function.id = f'{model.id}_{main_noise_function.id}' + model.functions.append(main_noise_function) + model.functions.extend(extra_noise_functions) + function_model.args['noise'] = main_noise_function.id + + for func_model in model.functions: + _substitute_expression_args(func_model) + + return model diff --git a/psyneulink/core/components/mechanisms/processing/objectivemechanism.py b/psyneulink/core/components/mechanisms/processing/objectivemechanism.py index f25a190559d..84b69156e63 100644 --- a/psyneulink/core/components/mechanisms/processing/objectivemechanism.py +++ b/psyneulink/core/components/mechanisms/processing/objectivemechanism.py @@ -72,7 +72,7 @@ used to specify attributes of the InputPort and/or MappingProjection(s) to it, that the ObjectiveMechanism creates to monitor the specified OutputPort. In general, the `value ` of each specified OutputPort determines the format of the `variable ` of the InputPort that is created for it by the ObjectiveMechanism. -However, this can be overridden using the ObjectiveMechanism's `default_variable ` +However, this can be overridden using the ObjectiveMechanism's `default_variable ` or `size ` attributes (see `Mechanism InputPort specification `), or by specifying a Projection from the OutputPort to the InputPort (see `Input Source Specification `). If an item in the @@ -180,10 +180,10 @@ ` and/or 'exponent ` attributes of the corresponding InputPorts, it can be configured to calculate differences, ratios, etc. (see `example ` below). The `function ` can also -be replaced with any `CombinationFunction`, or any python function that takes an 2d array as its input (with a number -of items in axis 0 equal to the number of the ObjectiveMechanism's InputPorts), and generates a 1d array as its result. -If it implements :keyword:`weight` and/or :keyword:`exponent` attributes, those are assigned from `weight -` and `exponent ` attributes of its `input_ports +be replaced with any `CombinationFunction `, or any python function that takes an 2d array as +its input (with a number of items in axis 0 equal to the number of the ObjectiveMechanism's InputPorts), and generates +a 1d array as its result. If it implements :keyword:`weight` and/or :keyword:`exponent` attributes, those are assigned +from `weight ` and `exponent ` attributes of its `input_ports ` (also listed in the `monitor_weights_and_exponents ` attribute); otherwise, they are ignored. @@ -464,10 +464,10 @@ class ObjectiveMechanism(ProcessingMechanism_Base): OutputPorts specified in its `monitor ` attribute. function : CombinationFunction, ObjectiveFunction, function, or method - the function used to evaluate the values monitored by the ObjectiveMechanism. The function can be - any PsyNeuLink `CombinationFunction` or a Python function that takes a 2d array with an arbitrary number of - items or a number equal to the number of items in the ObjectiveMechanism's variable (i.e., its number of - input_ports) and returns a 1d array. + the function used to evaluate the values monitored by the ObjectiveMechanism. The function can be any + `CombinationFunction ` or a Python function that takes a 2d array with an arbitrary + number of items or a number equal to the number of items in the ObjectiveMechanism's variable (i.e., + its number of input_ports) and returns a 1d array. output_port : OutputPort contains the `primary OutputPort ` of the ObjectiveMechanism; the default is @@ -498,7 +498,7 @@ class ObjectiveMechanism(ProcessingMechanism_Base): """ - componentType = OBJECTIVE_MECHANISM + componentType = 'ObjectiveMechanism' classPreferenceLevel = PreferenceLevel.SUBTYPE # These will override those specified in TYPE_DEFAULT_PREFERENCES diff --git a/psyneulink/core/components/mechanisms/processing/processingmechanism.py b/psyneulink/core/components/mechanisms/processing/processingmechanism.py index 6eb238cf6a3..8da4cbdfbe5 100644 --- a/psyneulink/core/components/mechanisms/processing/processingmechanism.py +++ b/psyneulink/core/components/mechanisms/processing/processingmechanism.py @@ -93,7 +93,9 @@ from psyneulink.core.components.functions.nonstateful.transferfunctions import SoftMax from psyneulink.core.components.functions.nonstateful.selectionfunctions import OneHot -from psyneulink.core.components.mechanisms.mechanism import Mechanism_Base +from psyneulink.core.components.mechanisms.mechanism import Mechanism_Base, Mechanism +from psyneulink.core.components.ports.inputport import InputPort +from psyneulink.core.components.ports.outputport import OutputPort from psyneulink.core.globals.keywords import \ FUNCTION, MAX_ABS_INDICATOR, MAX_ABS_ONE_HOT, MAX_ABS_VAL, MAX_INDICATOR, MAX_ONE_HOT, MAX_VAL, MEAN, MEDIAN, \ NAME, PROB, PROCESSING_MECHANISM, PREFERENCE_SET_NAME, STANDARD_DEVIATION, VARIANCE @@ -284,7 +286,7 @@ class ProcessingMechanism(ProcessingMechanism_Base): def __init__(self, default_variable=None, size=None, - input_ports:tc.optional(tc.any(list, dict))=None, + input_ports:tc.optional(tc.any(Iterable, Mechanism, OutputPort, InputPort))=None, output_ports:tc.optional(tc.any(str, Iterable))=None, function=None, params=None, diff --git a/psyneulink/core/components/mechanisms/processing/transfermechanism.py b/psyneulink/core/components/mechanisms/processing/transfermechanism.py index b484af0c3fa..44adbd44596 100644 --- a/psyneulink/core/components/mechanisms/processing/transfermechanism.py +++ b/psyneulink/core/components/mechanisms/processing/transfermechanism.py @@ -842,6 +842,7 @@ from psyneulink.core.components.ports.inputport import InputPort from psyneulink.core.components.ports.outputport import OutputPort from psyneulink.core.globals.context import ContextFlags, handle_external_context +from psyneulink.core.globals.json import _get_variable_parameter_name, _substitute_expression_args from psyneulink.core.globals.keywords import \ COMBINE, comparison_operators, EXECUTION_COUNT, FUNCTION, GREATER_THAN_OR_EQUAL, \ CURRENT_VALUE, LESS_THAN_OR_EQUAL, MAX_ABS_DIFF, \ @@ -851,7 +852,7 @@ from psyneulink.core.globals.preferences.basepreferenceset import is_pref_set from psyneulink.core.globals.preferences.preferenceset import PreferenceLevel from psyneulink.core.globals.utilities import \ - all_within_range, append_type_to_name, iscompatible, is_comparison_operator, convert_to_np_array, safe_equals + all_within_range, append_type_to_name, iscompatible, is_comparison_operator, convert_to_np_array, safe_equals, parse_valid_identifier from psyneulink.core.scheduling.time import TimeScale __all__ = [ @@ -1227,7 +1228,7 @@ class Parameters(ProcessingMechanism_Base.Parameters): ) termination_threshold = Parameter(None, modulable=True) termination_comparison_op = Parameter(LESS_THAN_OR_EQUAL, modulable=False, loggable=False) - termination_measure_value = Parameter(0.0, modulable=False, read_only=True) + termination_measure_value = Parameter(0.0, modulable=False, read_only=True, pnl_internal=True) output_ports = Parameter( [RESULTS], @@ -1410,8 +1411,11 @@ def _validate_params(self, request_set, target_set=None, context=None): # Validate INTEGRATION_RATE: if INTEGRATION_RATE in target_set and target_set[INTEGRATION_RATE] is not None: integration_rate = np.array(target_set[INTEGRATION_RATE]) - if (not np.isscalar(integration_rate.tolist()) - and integration_rate.shape != self.defaults.variable.squeeze().shape): + if ( + not np.isscalar(integration_rate.tolist()) + and integration_rate.shape != self.defaults.variable.shape + and integration_rate.shape != self.defaults.variable.squeeze().shape + ): raise TransferError(f"{repr(INTEGRATION_RATE)} arg for {self.name} ({integration_rate}) " f"must be either an int or float, or have the same shape " f"as its {VARIABLE} ({self.defaults.variable}).") @@ -1546,7 +1550,7 @@ def _gen_llvm_is_finished_cond(self, ctx, builder, params, state): ctx.int32_ty(0)]) threshold = builder.load(threshold_ptr) - cmp_val_ptr = builder.alloca(threshold.type) + cmp_val_ptr = builder.alloca(threshold.type, name="is_finished_value") if self.termination_measure is max: assert self._termination_measure_num_items_expected == 1 # Get inside of the structure @@ -1575,7 +1579,7 @@ def _gen_llvm_is_finished_cond(self, ctx, builder, params, state): func = ctx.import_llvm_function(self.termination_measure) func_params = pnlvm.helpers.get_param_ptr(builder, self, params, "termination_measure") func_state = pnlvm.helpers.get_state_ptr(builder, self, state, "termination_measure") - func_in = builder.alloca(func.args[2].type.pointee) + func_in = builder.alloca(func.args[2].type.pointee, name="is_finished_func_in") # Populate input func_in_current_ptr = builder.gep(func_in, [ctx.int32_ty(0), ctx.int32_ty(0)]) @@ -1600,32 +1604,32 @@ def _gen_llvm_is_finished_cond(self, ctx, builder, params, state): cmp_str = self.parameters.termination_comparison_op.get(None) return builder.fcmp_ordered(cmp_str, cmp_val, threshold) - def _gen_llvm_mechanism_functions(self, ctx, builder, params, state, arg_in, - ip_out, *, tags:frozenset): + def _gen_llvm_mechanism_functions(self, ctx, builder, m_base_params, m_params, + m_state, arg_in, ip_out, *, tags:frozenset): if self.integrator_mode: - if_state = pnlvm.helpers.get_state_ptr(builder, self, state, + if_state = pnlvm.helpers.get_state_ptr(builder, self, m_state, "integrator_function") - if_param_ptr = pnlvm.helpers.get_param_ptr(builder, self, params, - "integrator_function") + if_base_params = pnlvm.helpers.get_param_ptr(builder, self, m_base_params, + "integrator_function") if_params, builder = self._gen_llvm_param_ports_for_obj( - self.integrator_function, if_param_ptr, ctx, builder, - params, state, arg_in) + self.integrator_function, if_base_params, ctx, builder, + m_base_params, m_state, arg_in) mf_in, builder = self._gen_llvm_invoke_function( ctx, builder, self.integrator_function, if_params, if_state, ip_out, tags=tags) else: mf_in = ip_out - mf_state = pnlvm.helpers.get_state_ptr(builder, self, state, "function") - mf_param_ptr = pnlvm.helpers.get_param_ptr(builder, self, params, "function") + mf_state = pnlvm.helpers.get_state_ptr(builder, self, m_state, "function") + mf_base_params = pnlvm.helpers.get_param_ptr(builder, self, m_base_params, "function") mf_params, builder = self._gen_llvm_param_ports_for_obj( - self.function, mf_param_ptr, ctx, builder, params, state, arg_in) + self.function, mf_base_params, ctx, builder, m_base_params, m_state, arg_in) mf_out, builder = self._gen_llvm_invoke_function(ctx, builder, self.function, mf_params, mf_state, mf_in, tags=tags) - clip_ptr = pnlvm.helpers.get_param_ptr(builder, self, params, "clip") + clip_ptr = pnlvm.helpers.get_param_ptr(builder, self, m_params, "clip") if len(clip_ptr.type.pointee) != 0: assert len(clip_ptr.type.pointee) == 2 clip_lo = builder.load(builder.gep(clip_ptr, [ctx.int32_ty(0), @@ -1803,3 +1807,52 @@ def _update_default_variable(self, new_default_variable, context=None): self.parameters.initial_value._set(copy.deepcopy(integrator_function_variable), context) super()._update_default_variable(new_default_variable, context=context) + + def as_mdf_model(self): + import modeci_mdf.mdf as mdf + + model = super().as_mdf_model() + function_model = [ + f for f in model.functions + if f.id == parse_valid_identifier(self.function.name) + ][0] + assert function_model.id == parse_valid_identifier(self.function.name), (function_model.id, parse_valid_identifier(self.function.name)) + + if self.defaults.integrator_mode: + integrator_function_model = self.integrator_function.as_mdf_model() + + primary_input = function_model.args[_get_variable_parameter_name(self.function)] + self.integrator_function._set_mdf_arg( + integrator_function_model, + _get_variable_parameter_name(self.integrator_function), + primary_input + ) + self.function._set_mdf_arg( + function_model, + _get_variable_parameter_name(self.function), + integrator_function_model.id + ) + + for _, func_param in integrator_function_model.metadata['function_stateful_params'].items(): + model.parameters.append(mdf.Parameter(**func_param)) + + model.functions.append(integrator_function_model) + + res = self.integrator_function._get_mdf_noise_function() + try: + main_noise_function, extra_noise_functions = res + except TypeError: + pass + else: + main_noise_function.id = f'{model.id}_{main_noise_function.id}' + model.functions.append(main_noise_function) + model.functions.extend(extra_noise_functions) + + self.integrator_function._set_mdf_arg( + integrator_function_model, 'noise', main_noise_function.id + ) + + for func_model in model.functions: + _substitute_expression_args(func_model) + + return model diff --git a/psyneulink/core/components/ports/inputport.py b/psyneulink/core/components/ports/inputport.py index 03bf08ed93a..2b1ee1b637a 100644 --- a/psyneulink/core/components/ports/inputport.py +++ b/psyneulink/core/components/ports/inputport.py @@ -39,10 +39,10 @@ provided by the `Projections ` to that Mechanism from others in a `Composition`. If the InputPort belongs to an `ORIGIN` Mechanism (see `Mechanism_Role_In_Compositions`), then it receives the input specified when that Composition is `run `. The `PathwayProjections ` received by an InputPort are listed in its -`path_afferents `, and its `ModulatoryProjections ` in its `mod_afferents -` attribute. Its `function ` combines the values received from its -PathWayProjections, modifies the combined value according to value(s) any ModulatoryProjections it receives, and -provides the result to the assigned item of its owner Mechanism's `variable ` and +`path_afferents `, and its `ModulatoryProjections ` in its +`mod_afferents ` attribute. Its `function ` combines the values received +from its PathWayProjections, modifies the combined value according to value(s) any ModulatoryProjections it receives, +and provides the result to the assigned item of its owner Mechanism's `variable ` and `input_values ` attributes (see `below` and `Mechanism InputPorts ` for additional details about the role of InputPorts in Mechanisms, and their assignment to the items of a Mechanism's `variable ` attribute). @@ -80,7 +80,7 @@ An InputPort must be owned by a `Mechanism `. When InputPort is specified in the constructor for a Mechanism (see `below `), it is automatically assigned to that Mechanism as its owner. If -the InputPort is created on its own, its `owner ` can specified in the **owner** argument of its +the InputPort is created on its own, its `owner ` can specified in the **owner** argument of its constructor, in which case it is assigned to that Mechanism. If its **owner** argument is not specified, its initialization is `deferred ` until COMMENT: @@ -145,7 +145,6 @@ ` and `Mechanism InputPort specification ` for details). - Adding InputPorts to a Mechanism after it is created ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -209,7 +208,7 @@ * **InputPort specification dictionary** -- this can be used to specify the attributes of an InputPort, using any of the entries that can be included in a `Port specification dictionary ` (see `examples ` in Port). If the dictionary is used to specify an - InputPort in the constructor for a Mechanism, and it includes a *VARIABLE* and/or *VALUE* or entry, the value + InputPort in the constructor for a Mechanism, and it includes a *VARIABLE* and/or *VALUE* entry, the value must be compatible with the item of the owner Mechanism's `variable ` to which the InputPort is assigned (see `Mechanism InputPort specification `). @@ -253,8 +252,8 @@ An InputPort can also be specified by specifying one or more Ports, Mechanisms or Projections that should project to it, as described below. Specifying an InputPort in this way creates both the InputPort and any of the specified or implied Projection(s) to it (if they don't already exist). `MappingProjections ` - are assigned to the InputPort's `path_afferents ` attribute, while `ControlProjections - ` and `GatingProjections ` to its `mod_afferents ` + are assigned to the InputPort's `path_afferents ` attribute, while `ControlProjections + ` and `GatingProjections ` to its `mod_afferents ` attribute. Any of the following can be used to specify an InputPort by the Components that projection to it (see `below ` for an explanation of the relationship between the `value` of these Components and the InputPort's `variable `): @@ -292,12 +291,12 @@ * **value, Port specification, or list of Port specifications** -- specifies either the `variable ` of the InputPort, or one or more Ports that should project to it. The Port specification(s) can be a (Port name, Mechanism) tuple (see above), and/or include Mechanisms (in which - case their `primary OutputPort ` is used. All of the Port specifications must be + case their `primary OutputPort ` is used. All of the Port specifications must be consistent with (that is, their `value ` must be compatible with the `variable ` of) the Projection specified in the fourth item if that is included; * **weight** -- must be an integer or a float; multiplies the `value ` of the InputPort - before it is combined with others by the Mechanism's `function ` (see + before it is combined with others by the Mechanism's `function ` (see ObjectiveMechanism for `examples `); * **exponent** -- must be an integer or float; exponentiates the `value ` of the @@ -327,27 +326,69 @@ one(s) specified (see below). For each InputPort specified, and all of the InputPorts belonging to any Mechanisms specified, a new InputPort - is created along with Projections to it that parallel those received by the corresponding InputPort in the - list. In other words, for each InputPort specified, a new one is created that receives exactly the same inputs - from the same `senders ` as the ones specified. + is created along with Projections to it that parallel those received by the corresponding InputPort in the list. + That is, for each InputPort specified, one is created that receives exactly the same inputs from the same `senders + ` as the ones specified (see `examples ` below). If an InputPort shadows another, its `shadow_inputs ` attribute identifies the InputPort that it shadows. + .. _InputPort_Shadow_Nested_Note: + .. note:: Only InputPorts belonging to Mechanisms in the *same Composition*, or ones that are `INPUT ` - `Nodes ` of a `nested ` can be specified for shadowing, unless the - `allow_probes ` attribute of the `Composition` is set to True. Note also that any - Node that shadows an `INPUT ` `Node ` of the Composition to which it + `Nodes ` of a `nested ` can be specified for shadowing. Note also that + any Node that shadows an `INPUT ` `Node ` of the Composition to which it belongs is itself also assigned the role of `INPUT ` Node. .. hint:: If an InputPort needs to be shadowed that belongs to a Mechanism in a `nested ` that is - not an `INPUT ` `Node ` of that Composition, this can be accomplished as - follows: 1) add a Mechanism to the nested Composition with an InputPort that shadows the one to be - shadowed; 2) specify `OUTPUT ` as a `required_role ` - for that Mechanism; 3) use that Mechanism as the `InputPort specification ` - for the shadowing InputPort. + not an `INPUT ` `Node ` of that Composition, this can be accomplished in + one of two ways: 1) by assigning it `INPUT ` as a `required NodeRole + ` where it is added to the nested Composition; and/or 2) by doing the + following: a) add a Mechanism to the nested Composition with an InputPort that shadows the one to be + shadowed; b) specify `INPUT ` in the **required_roles** argument of the Composition's + `Composition.add_node` method used to add that Mechanism to the Composition; c) use that Mechanism as the + `InputPort specification ` for the shadowing InputPort. + + .. _InputPort_Shadow_Inputs_Figures: + + **Examples of InputPort Shadowing** + + .. figure:: _static/input_port_shadowing_1.svg + :scale: 50 % + :alt: Simple Shadowing + + **Simple case of shadowing**. The figure above shows a simple case in which ``Shadowing Mech`` is configured + to shadow the input to ``Shadowed Mech``, as specified below:: + + >>> A = ProcessingMechanism(name='Mech') + >>> B = ProcessingMechanism(name='Shadowed Mech') + >>> C = ProcessingMechanism(name='Shadowing Mech', input_ports=B.input_port) + >>> ocomp = Composition(pathways=[[A, B], C], + ... show_graph_attributes={'direction':'LR'}) + >>> ocomp.show_graph(show_node_structure=True) + + .. figure:: _static/input_port_shadowing_2.svg + :alt: Shadowing Nested Mechanism + + **Shadowing a nested Mechanism**. This example shows a Composition in which the `InputPort` of + ``shadowing_mech`` is configured to shadow the input to ``mech`` in ``nested_comp``. Accordingly + ``shadowing_mech`` receives a Projection from the same Port of ``outer_comp``'s `input_CIM + ` as the `input_CIM ` of ``nested_comp`` that projects to + ``mech``. As a result, ``shadowing_mech`` will receive the same input as ``mech`` when ``outer_comp`` + is executed (as noted `above `, only the `INPUT ` `Nodes + ` of a `nested Composition ` can be shadowed):: + + >>> import psyneulink as pnl + >>> mech = pnl.ProcessingMechanism(name='Mech') + >>> shadowing_mech = pnl.ProcessingMechanism(name='Shadowing Mech', + ... input_ports=mech.input_port) + >>> nested_comp = pnl.Composition([mech], name='Nested Composition') + >>> outer_comp = pnl.Composition(nodes=[nested_comp, shadowing_mech], + ... name='Outer Composition') + ... show_graph_attributes={'direction':'LR'}) + >>> outer_comp.show_graph(show_node_structure=True, show_cim=True) .. _InputPort_Compatability_and_Constraints: @@ -355,10 +396,10 @@ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The `variable ` of an InputPort must be compatible with the item of its owner Mechanism's -`variable ` to which it is assigned (see `Mechanism_Variable_and_InputPorts`). This may -have consequences that must be taken into account when `specifying an InputPort by Components that project to it -`. These depend on the context in which the specification is made, and -possibly the value of other specifications. These considerations and how they are handled are described below, +`variable ` to which it is assigned (see `Mechanism `). +This may have consequences that must be taken into account when `specifying an InputPort by Components that project +to it `. These depend on the context in which the specification is made, +and possibly the value of other specifications. These considerations and how they are handled are described below, starting with constraints that are given the highest precedence: * **InputPort is** `specified in a Mechanism's constructor ` and the @@ -434,42 +475,56 @@ --------- Every InputPort is owned by a `Mechanism `. It can receive one or more `MappingProjections -` from other Mechanisms, as well as from the Process or System to which its owner belongs (if it -is the `ORIGIN` Mechanism for that Process or System). It has the following attributes, that includes ones specific -to, and that can be used to customize the InputPort: +` from other Mechanisms or itself (e.g., `RecurrentTransferMechanism`), as well as from the +Composition to which its owner belongs (if it is the `ORIGIN` Mechanism for that Process or System). It has the +following attributes, that includes ones specific to, and that can be used to customize the InputPort: -* `projections ` -- all of the `Projections ` received by the InputPort. +* `projections ` -- all of the `Projections ` received by the InputPort. .. _InputPort_Afferent_Projections: -* `path_afferents ` -- `MappingProjections ` that project to the InputPort, +* `path_afferents ` -- `MappingProjections ` that project to the InputPort, the `value `\\s of which are combined by the InputPort's `function `, - possibly modified by its `mod_afferents `, and assigned to the corresponding item of the - owner Mechanism's `variable `. + possibly `modulated ` by one or more `mod_afferent ` + `GatingProjections `, and assigned to the corresponding item of the owner Mechanism's + `variable `. -* `mod_afferents ` -- `GatingProjections ` that project to the InputPort, - the `value ` of which can modify the InputPort's `value ` (see the - descriptions of Modulation under `ModulatorySignals ` and `GatingSignals +* `mod_afferents ` -- `GatingProjections ` that project to the + InputPort, the `value ` of which can modify the InputPort's `value ` + (see the descriptions of Modulation under `ModulatorySignals ` and `GatingSignals ` for additional details). If the InputPort receives more than one GatingProjection, their values are combined before they are used to modify the `value ` of InputPort. + .. _InputPort_Internal_Only: + +* `internal_only ` -- specifies whether an InputPort that belongs to an `INPUT + ` `Node ` of a `Composition` receives `Projections ` *only from* + other `Nodes ` *within* the Composition to which its `owner ` belongs; such + InputPorts do not receive any `external inputs ` to that Composition when it is + `executed ` (see `Composition inputs ` + for additional information). + .. _InputPort_Variable: * `variable ` -- serves as the template for the `value ` of the `Projections ` received by the InputPort: each must be compatible with (that is, match both the - number and type of elements of) the InputPort's `variable ` (see `Mapping_Matrix` for additonal - details). In general, this must also be compatible with the item of the owner Mechanism's `variable + number and type of elements of) the InputPort's `variable ` (see `matrix ` + for additional details). In general, this must also be compatible with the item of the owner Mechanism's `variable ` to which the InputPort is assigned (see `above ` and - `Mechanism InputPort specification `). + `Mechanism InputPort specification `). The InputPort's `variable + ` is composed of the concatenated `values ` of its `path_afferent + ` Projections. If it has none, then the `variable ` is either assigned + None or its `default value `, as determined by its `default_input ` + setting. .. _InputPort_Function: * `function ` -- combines the `value ` of all of the `Projections ` received by the InputPort, and assigns the result to the InputPort's `value ` attribute. The default function is `LinearCombination` that performs an elementwise (Hadamard) - sums the values. However, the parameters of the `function ` -- and thus the `value + sums the values. However, the parameters of the `function ` -- and thus the `value ` of the InputPort -- can be modified by any `GatingProjections ` received by - the InputPort (listed in its `mod_afferents ` attribute. A custom function can also be + the InputPort (listed in its `mod_afferents ` attribute. A custom function can also be specified, so long as it generates a result that is compatible with the item of the Mechanism's `variable ` to which the `InputPort is assigned `. @@ -497,12 +552,16 @@ An InputPort cannot be executed directly. It is executed when the Mechanism to which it belongs is executed. When this occurs, the InputPort executes any `Projections ` it receives, calls its `function ` to combines the values received from any `MappingProjections ` it receives -(listed in its its `path_afferents ` attribute) and modulate them in response to any -`GatingProjections ` (listed in its `mod_afferents ` attribute), +(listed in its its `path_afferents ` attribute) and modulate them in response to any +`GatingProjections ` (listed in its `mod_afferents ` attribute), and then assigns the result to the InputPort's `value ` attribute. This, in turn, is assigned to the item of the Mechanism's `variable ` and `input_values ` -attributes corresponding to that InputPort (see `Mechanism Variable and InputPorts -` for additional details). +attributes corresponding to that InputPort (see `Mechanism Variable and InputPorts ` +for additional details). If an InputPort does not have any `path_afferent Projections `, +by default its value is set to None which, when executed, generates an error; however, if its `default_input +` attribute is *DEFAULT_VARIABLE*, then the `default value ` for the +InputPort's `variable ` is used as its value (see `default_input ` for +additional details). .. _InputPort_Class_Reference: @@ -510,11 +569,11 @@ --------------- """ +import collections import inspect import numbers import warnings -import collections import numpy as np import typecheck as tc @@ -525,15 +584,16 @@ from psyneulink.core.components.ports.port import PortError, Port_Base, _instantiate_port_list, port_type_keywords from psyneulink.core.globals.context import ContextFlags, handle_external_context from psyneulink.core.globals.keywords import \ - COMBINE, CONTROL_SIGNAL, EXPONENT, FUNCTION, GATING_SIGNAL, INPUT_PORT, INPUT_PORTS, INPUT_PORT_PARAMS, \ - LEARNING_SIGNAL, MAPPING_PROJECTION, MATRIX, NAME, OPERATION, OUTPUT_PORT, OUTPUT_PORTS, OWNER,\ + COMBINE, CONTROL_SIGNAL, DEFAULT_VARIABLE, EXPONENT, FUNCTION, GATING_SIGNAL, \ + INPUT_PORT, INPUT_PORTS, INPUT_PORT_PARAMS, \ + LEARNING_SIGNAL, MAPPING_PROJECTION, MATRIX, NAME, OPERATION, OUTPUT_PORT, OUTPUT_PORTS, OWNER, \ PARAMS, PRODUCT, PROJECTIONS, REFERENCE_VALUE, \ SENDER, SHADOW_INPUTS, SHADOW_INPUT_NAME, SIZE, PORT_TYPE, SUM, VALUE, VARIABLE, WEIGHT from psyneulink.core.globals.parameters import Parameter from psyneulink.core.globals.preferences.basepreferenceset import is_pref_set from psyneulink.core.globals.preferences.preferenceset import PreferenceLevel from psyneulink.core.globals.utilities import \ - append_type_to_name, convert_to_np_array, is_numeric, iscompatible, kwCompatibilityLength, convert_to_list + append_type_to_name, convert_to_np_array, is_numeric, iscompatible, kwCompatibilityLength, convert_to_list, parse_valid_identifier __all__ = [ 'InputPort', 'InputPortError', 'port_type_keywords', 'SHADOW_INPUTS', @@ -592,10 +652,16 @@ class InputPort(Port_Base): the value of the item of the owner Mechanism's `variable ` attribute to which the InputPort is assigned; used as the template for the InputPort's `value ` attribute. + default_input : None or DEFAULT_VARIABLE : default None + specifies value to use as variable if the InputPort has no `path_afferent ` + `Projections `. If None (the default), then None is returned; otherwise the `default value + ` for the InputPort's `variable ` is used (see `default_input + ` for additional details). + variable : number, list or np.ndarray specifies the shape of the InputPort's `variable `, which may be used to define the shape of the `matrix ` parameter of the `MappingProjection` that projects to the - Inputport (see `InputPort_Variable` for additional details). + Inputport (see `variable ` for additional details). function : Function or method : default LinearCombination(operation=SUM) specifies the function applied to the variable. The default value combines the `values @@ -606,16 +672,16 @@ class InputPort(Port_Base): receives more than one Projection (see `function `. combine : SUM or PRODUCT : default None - specifies the **operation** argument used by the default `LinearCombination` function, which determines how the - `value ` of the InputPort's `projections ` are combined. This is a - convenience argument, that allows the **operation** to be specified without having to specify the + specifies the **operation** argument used by the default `LinearCombination` function, which determines how + the `value ` of the InputPort's `projections ` are combined. + This is a convenience argument, that allows the **operation** to be specified without having to specify the LinearCombination function; it assumes that LinearCombination (the default) is used as the InputPort's function -- if it conflicts with a specification of **function** an error is generated. projections : list of Projection specifications specifies the `MappingProjection(s) `, `ControlProjection(s) ` and/or `GatingProjection(s) ` to be received by the InputPort, and that are listed in its - `path_afferents ` and `mod_afferents ` attributes, + `path_afferents ` and `mod_afferents ` attributes, respectively (see `InputPort_Compatability_and_Constraints` for additional details). If **projections** but neither **variable** nor **size** are specified, then the `value ` of the Projection(s) or their `senders ` specified in **projections** argument are used to determine the @@ -628,7 +694,7 @@ class InputPort(Port_Base): specifies the value of the `exponent ` attribute of the InputPort. internal_only : bool : False - specifies whether the InputPort requires external input when its `owner ` is the `INPUT` + specifies whether the InputPort requires external input when its `owner ` is the `INPUT` `Node ` of a `Composition (see `internal_only ` for details). Attributes @@ -641,20 +707,43 @@ class InputPort(Port_Base): **projections** is specified, then `variable ` is assigned the `value ` of the Projection(s) or its `sender `. + default_input : None or DEFAULT_VARIABLE + determines the value used as `variable ` if the InputPort has no `path_afferent + ` `Projections `. If None (the default), then None is used. This is the + default behavior, as it is useful for identifying "orphaned" InputPorts (i.e., ones that do not receive + any inputs) and the `Mechanisms ` to which they belong, as an error is returned if an InputPort + is executed and its variable is assigned None. If *default_input* is assigned *DEFAULT_VARIABLE*, then the + `default value ` for the InputPort's `variable ` is used as its value. + This is useful for assignment to a Mechanism that needs a fixed value as the input to its `function + `. + + .. note:: + If `default_input ` is assigned *DEFAULT_VARIABLE*, then its `internal_only + ` attribute is automatically assigned True. This is so that if the `Mechanism` + to which the InputPort belongs is assigned to a `Composition`, it is not treated as an `ORIGIN + ` `Node ` of that Composition (and automatically assigned a Projection + from its `input_CIM `. + + input_shape : 1d array + shows the shape of the input to the InputPort; that is, the shape of the `value ` + expected for any `path_afferent Projections `. + function : Function - If it is a `CombinationFunction`, it combines the `values ` of the `PathwayProjections - ` (e.g., `MappingProjections `) received by the InputPort (listed in - its `path_afferents ` attribute), under the possible influence of `GatingProjections - ` received by the InputPort (listed in its `mod_afferents ` attribute). - The result is assigned to the InputPort's `value ` attribute. For example, the default - (`LinearCombination` with *SUM* as it **operation**) performs an element-wise (Hadamard) sum of its Projection - `values `, and assigns to `value ` an array that is of the same length - as each of the Projection `values `. If the InputPort receives only one Projection, - then any other function can be applied and it will generate a value that is the same length as the Projection's - `value `. However, if the InputPort receives more than one Projection and uses a function - other than a CombinationFunction, a warning is generated and only the `value ` of the - first Projection list in `path_afferents ` is used by the function, which may generate - unexpected results when executing the Mechanism or Composition to which it belongs. + if it is a `CombinationFunction `, it combines the `values ` of + the `PathwayProjections ` (e.g., `MappingProjections `) received by the + InputPort (listed in its `path_afferents ` attribute), under the possible + influence of `GatingProjections ` received by the InputPort (listed in its `mod_afferents + ` attribute). The result is assigned to the InputPort's `value ` + attribute. For example, the the default (`LinearCombination` with *SUM* as it **operation**) performs an + element-wise (Hadamard) sum of its Projection `values `, and assigns to `value + ` an array that is of the same length as each of the Projection `values + `. If the InputPort receives only one Projection, then any other function can be + applied and it will generate a value that is the same length as the Projection's `value + `. However, if the InputPort receives more than one Projection and + uses a function other than a CombinationFunction, a warning is generated and only the `value + ` of the first Projection list in `path_afferents ` + is used by the function, which may generate unexpected results when executing the Mechanism or Composition + to which it belongs. value : value or ndarray the output of the InputPort's `function `, that is assigned to an item of the owner @@ -672,9 +761,9 @@ class InputPort(Port_Base): see `weight and exponent ` for description. internal_only : bool - determines whether `input from a Composition ` must be specified for this - InputPort from a Composition's `execution method ` if the InputPort's `owner - ` is an `INPUT` `Node ` of that Composition; if `True`, external input is + determines whether `input from a Composition ` must be specified for this + InputPort from a Composition's `execution method ` if the InputPort's `owner + ` is an `INPUT` `Node ` of that Composition; if `True`, external input is *not* required or allowed. shadow_inputs : InputPort @@ -731,6 +820,12 @@ class Parameters(Port_Base.Parameters): :default value: None :type: + default_input + see 'default_input ` + + :default value: None + :type: None or DEFAULT_VARIABLE + exponent see `exponent ` @@ -763,6 +858,8 @@ class Parameters(Port_Base.Parameters): :default value: None :type: """ + default_input = Parameter(None, stateful=False, loggable=True, read_only=True, structural=True, + constructor_argument='default_input') function = Parameter(LinearCombination(operation=SUM), stateful=False, loggable=False) weight = Parameter(None, modulable=True) exponent = Parameter(None, modulable=True) @@ -770,6 +867,10 @@ class Parameters(Port_Base.Parameters): internal_only = Parameter(False, stateful=False, loggable=False, pnl_internal=True) shadow_inputs = Parameter(None, stateful=False, loggable=False, read_only=True, pnl_internal=True, structural=True) + def _validate_default_input(self, default_input): + if default_input not in {None, DEFAULT_VARIABLE}: + return f"must be None or the keyword '{DEFAULT_VARIABLE.upper()}'." + #endregion @handle_external_context() @@ -779,6 +880,7 @@ def __init__(self, reference_value=None, variable=None, size=None, + default_input=None, function=None, projections=None, combine:tc.optional(tc.enum(SUM,PRODUCT))=None, @@ -798,7 +900,10 @@ def __init__(self, if combine: self.combine_function_args = (combine, function) - # If owner or reference_value has not been assigned, defer init to Port._instantiate_projection() + if default_input == DEFAULT_VARIABLE: + internal_only = True + + # If owner or reference_value has not been assigned, defer init to Port_Base._instantiate_projection() # if owner is None or (variable is None and reference_value is None and projections is None): if owner is None: # Temporarily name InputPort @@ -909,7 +1014,7 @@ def _validate_params(self, request_set, target_set=None, context=None): f"({ target_set[EXPONENT]}) must be an int or float.") def _validate_against_reference_value(self, reference_value): - """Validate that Port.value is compatible with reference_value + """Validate that Port_Base.value is compatible with reference_value reference_value is the item of the owner Mechanism's variable to which the InputPort is assigned """ @@ -951,14 +1056,13 @@ def _check_for_duplicate_projections(self, projection): Returns redundant Projection if found, otherwise False. """ + if self.initialization_status == ContextFlags.DEFERRED_INIT: + raise InputPortError(f"Attempt to assign Projection ('{projection.name}') " + f"using InputPort ('{self.name}') that is in deferred init") try: self.path_afferents except: - if self.initialization_status == ContextFlags.DEFERRED_INIT: - raise InputPortError(f"Attempt to assign Projection ('{projection}') " - f"to InputPort ('{self.name}') that is in deferred init") - else: - raise InputPortError(f"No 'path_afferents' for {self.name}") + raise InputPortError(f"No 'path_afferents' for {self.full_name}") # FIX: 7/22/19 - CHECK IF SENDER IS SPECIFIED AS MECHANISM AND, IF SO, CHECK ITS PRIMARY_OUTPUT_PORT duplicate = next(iter([proj for proj in self.path_afferents @@ -1003,6 +1107,12 @@ def _get_variable_from_projections(self, context=None): def _get_primary_port(self, mechanism): return mechanism.input_port + def _get_all_afferents(self): + return self.path_afferents + self.mod_afferents + + def _get_all_projections(self): + return self._get_all_afferents() + @tc.typecheck def _parse_port_specific_specs(self, owner, port_dict, port_specific_spec): """Get weights, exponents and/or any connections specified in an InputPort specification tuple @@ -1232,7 +1342,7 @@ def _parse_self_port_type_spec(self, owner, input_port, context=None): f"with non-InputPort specification ({input_port}).") sender_output_ports = [p.sender for p in input_port.path_afferents] - port_spec = {NAME: SHADOW_INPUT_NAME + input_port.owner.name, + port_spec = {NAME: SHADOW_INPUT_NAME + input_port.full_name, VARIABLE: np.zeros_like(input_port.variable), PORT_TYPE: InputPort, PROJECTIONS: sender_output_ports, @@ -1278,6 +1388,14 @@ def pathway_projections(self): def pathway_projections(self, assignment): self.path_afferents = assignment + @property + def path_afferents(self): + try: + return self._path_afferents + except: + self._path_afferents = [] + return self._path_afferents + @property def socket_width(self): return self.defaults.variable.shape[-1] @@ -1286,10 +1404,6 @@ def socket_width(self): def socket_template(self): return np.zeros(self.socket_width) - @property - def label(self): - return self.get_label() - def get_label(self, context=None): try: label_dictionary = self.owner.input_labels_dict @@ -1297,6 +1411,37 @@ def get_label(self, context=None): label_dictionary = {} return self._get_value_label(label_dictionary, self.owner.input_ports, context=context) + @property + def _input_shape_template(self): + try: + if self.function.changes_shape: + return VARIABLE + else: + return VALUE + except: + assert False, f"PROGRAM ERROR: Missing or unrecognized 'changes_shape' attribute for " \ + f"('{self.function.name}') of '{self.name}'." + + @property + def input_shape(self): + """Alias for default_input_shape_template""" + return self.default_input_shape + + @property + def default_input_shape(self): + if self._input_shape_template == VARIABLE: + return self.defaults.variable + elif self._input_shape_template == VALUE: + return self.defaults.value + assert False, f"PROGRAM ERROR: bad _input_shape_template assignment for '{self.name}'." + + def get_input_shape(self, context=None): + if self._input_shape_template == VARIABLE: + return self.get_input_variables(context) + elif self._input_shape_template == VALUE: + return self.get_input_values(context) + assert False, f"PROGRAM ERROR: bad _input_shape_template assignment for '{self.name}'." + @property def position_in_mechanism(self): if hasattr(self, "owner"): @@ -1331,6 +1476,15 @@ def _get_port_function_value(owner, function, variable): return Port_Base._get_port_function_value(owner=owner, function=function, variable=variable) + def as_mdf_model(self): + import modeci_mdf.mdf as mdf + + return mdf.InputPort( + id=parse_valid_identifier(self.name), + shape=str(self.defaults.variable.shape), + type=str(self.defaults.variable.dtype), + **self._mdf_metadata + ) def _instantiate_input_ports(owner, input_ports=None, reference_value=None, context=None): """Call Port._instantiate_port_list() to instantiate ContentAddressableList of InputPort(s) @@ -1412,16 +1566,18 @@ def _instantiate_input_ports(owner, input_ports=None, reference_value=None, cont return port_list def _parse_shadow_inputs(owner, input_ports): - """Parses any {SHADOW_INPUTS:[InputPort or Mechanism,...]} items in input_ports into InputPort specif. dict.""" + """Parse any {SHADOW_INPUTS:[InputPort or Mechanism,...]} items in input_ports into InputPort specification dict + Return InputPort specification dict for any shadowing InputPorts, and unmodified spec for any others. + """ input_ports = convert_to_list(input_ports) input_ports_to_shadow_specs=[] for spec_idx, spec in enumerate(input_ports): - # If {SHADOW_INPUTS:[InputPort or Mechaism,...]} is found: + # If {SHADOW_INPUTS:[InputPort or Mechanism,...]} is found: if isinstance(spec, dict) and SHADOW_INPUTS in spec: input_ports_to_shadow_in_spec=[] # For each item in list of items to shadow specified in that entry: - for item in list(spec[SHADOW_INPUTS]): + for item in convert_to_list(spec[SHADOW_INPUTS]): from psyneulink.core.components.mechanisms.mechanism import Mechanism # If an InputPort was specified, just used that if isinstance(item, InputPort): diff --git a/psyneulink/core/components/ports/modulatorysignals/controlsignal.py b/psyneulink/core/components/ports/modulatorysignals/controlsignal.py index 5bc8b48516a..a5e534579cc 100644 --- a/psyneulink/core/components/ports/modulatorysignals/controlsignal.py +++ b/psyneulink/core/components/ports/modulatorysignals/controlsignal.py @@ -64,7 +64,7 @@ `, the parameter(s) to be controlled must be specified. If other attributes of the ControlSignal need to be specified (e.g., one or more of its `cost functions `), then the Constructor for the ControlSignal can be used or a `port specification dictionary `, in which the parameter(s) to be -controlled in the **projections** argument or *PROJECTIONS* entry, respectively, using any of the forms below. +controlled are specified in the **control** argument or *CONTROL* entry, respectively, using any of the forms below. For convenience, the parameters can also be specified on their own in the **control_signals** argument of the ControlMechanism's constructor, in which case a default ControlSignal will be created for each. In all cases, any of the following can be use to specify the parameter(s) to be controlled: @@ -114,10 +114,10 @@ ~~~~~~~~~~~~~ When a ControlSignal is created, it can be assigned one or more `ControlProjections `, using either -the **projections** argument of its constructor, or in an entry of a dictionary assigned to the **params** argument -with the key *PROJECTIONS*. These will be assigned to its `efferents ` attribute. See +the **control** argument of its constructor, or in an entry of a dictionary assigned to the **params** argument +with the key *CONTROL*. These are assigned to its `efferents ` attribute. See `Port Projections ` for additional details concerning the specification of Projections when -creating a Port. +creating a Port, including `examples ` of ControlProjection specification. .. note:: Although a ControlSignal can be assigned more than one `ControlProjection`, all of those Projections will receive @@ -347,7 +347,7 @@ >>> from psyneulink import * >>> mech = ProcessingMechanism(name='my_mech') >>> ctl_mech_A = ControlMechanism(monitor_for_control=mech, - ... control_signals=ControlSignal(modulates=(INTERCEPT,mech), + ... control_signals=ControlSignal(control=(INTERCEPT,mech), ... cost_options=CostFunctions.INTENSITY)) >>> ctl_mech_B = ControlMechanism(monitor_for_control=mech, ... control_signals=ControlSignal(modulates=ctl_mech_A.control_signals[0], @@ -398,26 +398,28 @@ """ +import warnings + import numpy as np import typecheck as tc -import warnings # FIX: EVCControlMechanism IS IMPORTED HERE TO DEAL WITH COST FUNCTIONS THAT ARE DEFINED IN EVCControlMechanism # SHOULD THEY BE LIMITED TO EVC?? from psyneulink.core import llvm as pnlvm -from psyneulink.core.components.functions.nonstateful.combinationfunctions import Reduce from psyneulink.core.components.functions.function import is_function_type +from psyneulink.core.components.functions.nonstateful.combinationfunctions import Reduce +from psyneulink.core.components.functions.nonstateful.transferfunctions import Exponential, Linear, CostFunctions, \ + TransferWithCosts from psyneulink.core.components.functions.stateful.integratorfunctions import SimpleIntegrator -from psyneulink.core.components.functions.nonstateful.transferfunctions import Exponential, Linear, CostFunctions, TransferWithCosts from psyneulink.core.components.ports.modulatorysignals.modulatorysignal import ModulatorySignal from psyneulink.core.components.ports.outputport import _output_port_variable_getter from psyneulink.core.globals.context import ContextFlags from psyneulink.core.globals.defaults import defaultControlAllocation from psyneulink.core.globals.keywords import \ - ALLOCATION_SAMPLES, CONTROL_PROJECTION, CONTROL_SIGNAL, \ - INPUT_PORT, INPUT_PORTS, \ + ALLOCATION_SAMPLES, CONTROL, CONTROL_PROJECTION, CONTROL_SIGNAL, \ + INPUT_PORT, INPUT_PORTS, MODULATES, \ OUTPUT_PORT, OUTPUT_PORTS, OUTPUT_PORT_PARAMS, \ - PARAMETER_PORT, PARAMETER_PORTS, \ + PARAMETER_PORT, PARAMETER_PORTS, PROJECTIONS, \ RECEIVER, FUNCTION from psyneulink.core.globals.parameters import FunctionParameter, Parameter, get_validator_by_function from psyneulink.core.globals.preferences.basepreferenceset import is_pref_set @@ -457,7 +459,7 @@ class ControlSignal(ModulatorySignal): duration_cost_function=IntegratorFunction, \ combine_costs_function=Reduce(operation=SUM), \ allocation_samples=self.class_defaults.allocation_samples, \ - modulates=None, \ + control=None, \ projections=None) A subclass of `ModulatorySignal ` used by a `ControlMechanism ` to @@ -499,7 +501,7 @@ class ControlSignal(ModulatorySignal): specifies the values used by the ControlSignal's `owner ` to determine its `control_allocation ` (see `ControlSignal_Execution`). - modulates : list of Projection specifications + control : list of Projection specifications specifies the `ControlProjection(s) ` to be assigned to the ControlSignal, and that will be listed in its `efferents ` attribute (see `ControlSignal_Projections` for additional details). @@ -593,7 +595,29 @@ class ControlSignal(ModulatorySignal): #region CLASS ATTRIBUTES componentType = CONTROL_SIGNAL + componentName = 'ControlSignal' + errorType = ControlSignalError + paramsType = OUTPUT_PORT_PARAMS + portAttributes = ModulatorySignal.portAttributes | {ALLOCATION_SAMPLES, + COST_OPTIONS, + INTENSITY_COST_FUNCTION, + ADJUSTMENT_COST_FUNCTION, + DURATION_COST_FUNCTION, + COMBINE_COSTS_FUNCTION} + + connectsWith = [PARAMETER_PORT, INPUT_PORT, OUTPUT_PORT] + connectsWithAttribute = [PARAMETER_PORTS, INPUT_PORTS, OUTPUT_PORTS] + projectionSocket = RECEIVER + modulators = [] + projection_type = CONTROL_PROJECTION + + classPreferenceLevel = PreferenceLevel.TYPE + # Any preferences specified below will override those specified in TYPE_DEFAULT_PREFERENCES + # Note: only need to specify setting; level will be assigned to TYPE automatically + # classPreferences = { + # PREFERENCE_SET_NAME: 'OutputPortCustomClassPreferences', + # PREFERENCE_KEYWORD: ...} class Parameters(ModulatorySignal.Parameters): """ @@ -766,26 +790,6 @@ def _validate_allocation_samples(self, allocation_samples): # not iterable, so assume single value pass - portAttributes = ModulatorySignal.portAttributes | {ALLOCATION_SAMPLES, - COST_OPTIONS, - INTENSITY_COST_FUNCTION, - ADJUSTMENT_COST_FUNCTION, - DURATION_COST_FUNCTION, - COMBINE_COSTS_FUNCTION} - - connectsWith = [PARAMETER_PORT, INPUT_PORT, OUTPUT_PORT] - connectsWithAttribute = [PARAMETER_PORTS, INPUT_PORTS, OUTPUT_PORTS] - projectionSocket = RECEIVER - modulators = [] - projection_type = CONTROL_PROJECTION - - classPreferenceLevel = PreferenceLevel.TYPE - # Any preferences specified below will override those specified in TYPE_DEFAULT_PREFERENCES - # Note: only need to specify setting; level will be assigned to TYPE automatically - # classPreferences = { - # PREFERENCE_SET_NAME: 'OutputPortCustomClassPreferences', - # PREFERENCE_KEYWORD: ...} - #endregion @tc.typecheck @@ -802,7 +806,7 @@ def __init__(self, combine_costs_function:tc.optional(is_function_type)=None, allocation_samples=None, modulation:tc.optional(str)=None, - modulates=None, + control=None, params=None, name=None, prefs:is_pref_set=None, @@ -810,14 +814,36 @@ def __init__(self, try: if kwargs[FUNCTION] is not None: - raise TypeError( - f'{self.__class__.__name__} automatically creates a ' - 'TransferWithCosts function, and does not accept override. ' - 'TransferWithCosts uses the transfer_function parameter.' - ) + raise TypeError(f'{self.__class__.__name__} automatically creates a ' + 'TransferWithCosts function, and does not accept override. ' + 'TransferWithCosts uses the transfer_function parameter.') except KeyError: pass + # Deal with **modulates** if specified + if MODULATES in kwargs: + # Don't allow **control** and **modulates** to both be specified + if control: + raise ControlSignalError(f"Both '{CONTROL}' and '{MODULATES}' arguments are specified in the " + f"constructor for '{name if name else self.__class__.__name__}; " + f"Should use just '{CONTROL}'.") + # warnings.warn(f"The '{MODULATES}' argument (specified in the constructor for " + # f"'{name if name else self.__class__.__name__}') has been deprecated; " + # f"should use '{'control'}' going forward.") + + if PROJECTIONS in kwargs: + raise ControlSignalError(f"Both '{MODULATES}' and '{PROJECTIONS}' arguments are specified " + f"in the constructor for '{name if name else self.__class__.__name__}; " + f"Should use just '{PROJECTIONS}' (or '{CONTROL}') ") + control = kwargs.pop(MODULATES) + + elif PROJECTIONS in kwargs: + # Don't allow **control** and **modulates** to both be specified + if control: + raise ControlSignalError(f"Both '{CONTROL}' and '{PROJECTIONS}' arguments are specified " + f"in the constructor for '{name if name else self.__class__.__name__}; " + f"Must use just one or the other.") + # This is included in case ControlSignal was created by another Component (such as ControlProjection) # that specified ALLOCATION_SAMPLES in params if params and ALLOCATION_SAMPLES in params and params[ALLOCATION_SAMPLES] is not None: @@ -836,7 +862,7 @@ def __init__(self, size=size, transfer_function=transfer_function, modulation=modulation, - modulates=modulates, + modulates=control, cost_options=cost_options, intensity_cost_function=intensity_cost_function, adjustment_cost_function=adjustment_cost_function, @@ -1009,20 +1035,36 @@ def _parse_port_specific_specs(self, owner, port_dict, port_specific_spec): [TBI:] (Mechanism, parameter name, weight, exponent, projection_specs) Returns params dict with CONNECTIONS entries if any of these was specified. - """ + from psyneulink.core.components.projections.projection import _parse_connection_specs - from psyneulink.core.globals.keywords import PROJECTIONS params_dict = {} port_spec = port_specific_spec + dual_spec_error = self.errorType(f"Both 'PROJECTIONS' and '{owner.controlType.upper()}' entries found in " + f"specification dict for '{port_dict['port_type'].__name__}' of " + f"'{owner.name}'. Must use only one or the other.") if isinstance(port_specific_spec, dict): + # Note: if CONTROL is specified alone, it is moved to PROJECTIONS in Port._parse_ort_spec() + if owner.controlType in port_specific_spec: + # owner.controlType *and* PROJECTIONS can't both be used + if PROJECTIONS in port_specific_spec: + raise dual_spec_error + # Move owner.controlType entry to PROJECTIONS + port_specific_spec[PROJECTIONS] = port_specific_spec.pop(owner.controlType) return None, port_specific_spec elif isinstance(port_specific_spec, tuple): port_spec = None + # Resolve owner.controlType as synonym for PROJECTIONS: + if owner.controlType in params_dict: + # owner.controlType *and* PROJECTIONS can't both be used + if PROJECTIONS in params_dict: + raise dual_spec_error + # Move owner.controlType entry to PROJECTIONS + params_dict[PROJECTIONS] = params_dict.pop(owner.controlType) params_dict[PROJECTIONS] = _parse_connection_specs(connectee_port_type=self, owner=owner, connections=port_specific_spec) @@ -1078,7 +1120,10 @@ def compute_costs(self, intensity, context=None): self.parameters.duration_cost._set(duration_cost, context) all_costs = [intensity_cost, adjustment_cost, duration_cost] - combined_cost = self.combine_costs_function(all_costs, context=context) + + # Combine the costs. Convert to a float because reRedcu + combined_cost = self.combine_costs_function(all_costs, context=context).astype(float) + return max(0.0, combined_cost) def _gen_llvm_function(self, *, ctx:pnlvm.LLVMBuilderContext, @@ -1110,9 +1155,10 @@ def _gen_llvm_costs(self, *, ctx:pnlvm.LLVMBuilderContext, tags:frozenset): assert self.cost_options & ~CostFunctions.INTENSITY == 0 cfunc = ctx.import_llvm_function(self.function.combine_costs_fct) - cfunc_in = builder.alloca(cfunc.args[2].type.pointee) + cfunc_in = builder.alloca(cfunc.args[2].type.pointee, + name="combine_costs_func_in") - # Set to 0 be default + # Set to 0 by default builder.store(cfunc_in.type.pointee(None), cfunc_in) cost_funcs = 0 @@ -1125,8 +1171,12 @@ def _gen_llvm_costs(self, *, ctx:pnlvm.LLVMBuilderContext, tags:frozenset): ifunc_state = pnlvm.helpers.get_state_ptr(builder, self.function, func_state, "intensity_cost_fct") - # Port input is always struct { data input, modulations } - ifunc_in = builder.gep(arg_in, [ctx.int32_ty(0), ctx.int32_ty(0)]) + # Port input is struct { data input, modulations } if there are modulations, + # otherwise it's just data_input + if len(self.mod_afferents) > 0: + ifunc_in = builder.gep(arg_in, [ctx.int32_ty(0), ctx.int32_ty(0)]) + else: + ifunc_in = arg_in # point output to the proper slot in comb func input assert cost_funcs == 0, "Intensity should eb the first cost function!" ifunc_out = builder.gep(cfunc_in, [ctx.int32_ty(0), ctx.int32_ty(cost_funcs)]) @@ -1147,7 +1197,8 @@ def _gen_llvm_costs(self, *, ctx:pnlvm.LLVMBuilderContext, tags:frozenset): cfunc_state = pnlvm.helpers.get_state_ptr(builder, self.function, func_state, "combine_costs_fct") - cfunc_out = builder.alloca(cfunc.args[3].type.pointee) + cfunc_out = builder.alloca(cfunc.args[3].type.pointee, + name="combine_costs_func_out") builder.call(cfunc, [cfunc_params, cfunc_state, cfunc_in, cfunc_out]) diff --git a/psyneulink/core/components/ports/modulatorysignals/gatingsignal.py b/psyneulink/core/components/ports/modulatorysignals/gatingsignal.py index 8cba981e069..b24e5da5eb7 100644 --- a/psyneulink/core/components/ports/modulatorysignals/gatingsignal.py +++ b/psyneulink/core/components/ports/modulatorysignals/gatingsignal.py @@ -251,7 +251,7 @@ from psyneulink.core.globals.defaults import defaultGatingAllocation from psyneulink.core.globals.keywords import \ GATE, GATING_PROJECTION, GATING_SIGNAL, INPUT_PORT, INPUT_PORTS, \ - OUTPUT_PORT, OUTPUT_PORTS, OUTPUT_PORT_PARAMS, PROJECTIONS, RECEIVER + MODULATES, OUTPUT_PORT, OUTPUT_PORTS, OUTPUT_PORT_PARAMS, PROJECTIONS, RECEIVER from psyneulink.core.globals.parameters import Parameter from psyneulink.core.globals.preferences.basepreferenceset import is_pref_set from psyneulink.core.globals.preferences.preferenceset import PreferenceLevel @@ -297,6 +297,11 @@ class GatingSignal(ControlSignal): default_allocation : scalar, list or np.ndarray : defaultGatingAllocation specifies the template and default value used for `allocation `. + gate : list of Projection specifications + specifies the `GatingProjection(s) ` to be assigned to the GatingSignal, and that will be + listed in its `efferents ` attribute (see `GatingSignal_Projections` for additional + details). + function : Function or method : default Linear specifies the function used to determine the value of the GatingSignal from the value of its `owner `. @@ -342,8 +347,9 @@ class GatingSignal(ControlSignal): componentType = GATING_SIGNAL componentName = 'GatingSignal' - paramsType = OUTPUT_PORT_PARAMS + errorType = GatingSignalError + paramsType = OUTPUT_PORT_PARAMS portAttributes = ControlSignal.portAttributes | {GATE} connectsWith = [INPUT_PORT, OUTPUT_PORT] @@ -419,7 +425,7 @@ def __init__(self, size=None, transfer_function=None, modulation:tc.optional(str)=None, - modulates=None, + gate=None, params=None, name=None, prefs:is_pref_set=None, @@ -430,52 +436,45 @@ def __init__(self, # Consider adding self to owner.output_ports here (and removing from GatingProjection._instantiate_sender) # (test for it, and create if necessary, as per OutputPorts in GatingProjection._instantiate_sender), + + # Deal with **modulates** if specified + if MODULATES in kwargs: + # Don't allow **control** and **modulates** to both be specified + if gate: + raise GatingSignalError(f"Both 'gate' and '{MODULATES}' arguments are specified in the " + f"constructor for '{name if name else self.__class__.__name__}; " + f"Should use just 'gate'.") + # warnings.warn(f"The '{MODULATES}' argument (specified in the constructor for " + # f"'{name if name else self.__class__.__name__}') has been deprecated; " + # f"should use '{'control'}' going forward.") + + if PROJECTIONS in kwargs: + raise GatingSignalError(f"Both '{MODULATES}' and '{PROJECTIONS}' arguments are specified " + f"in the constructor for '{name if name else self.__class__.__name__}; " + f"Should use just '{PROJECTIONS}' (or 'gate') ") + gate = kwargs.pop(MODULATES) + + elif PROJECTIONS in kwargs: + # Don't allow **control** and **modulates** to both be specified + if gate: + raise GatingSignalError(f"Both 'gate' and '{PROJECTIONS}' arguments are specified " + f"in the constructor for '{name if name else self.__class__.__name__}; " + f"Must use just one or the other.") + + # Validate sender (as variable) and params super().__init__(owner=owner, reference_value=reference_value, default_allocation=default_allocation, size=size, modulation=modulation, - modulates=modulates, + control=gate, params=params, name=name, prefs=prefs, transfer_function=transfer_function, **kwargs) - def _parse_port_specific_specs(self, owner, port_dict, port_specific_spec): - """Get connections specified in a ParameterPort specification tuple - - Tuple specification can be: - (Port name, Mechanism) - [TBI:] (Mechanism, Port name, weight, exponent, projection_specs) - - Returns params dict with CONNECTIONS entries if any of these was specified. - - """ - from psyneulink.core.components.projections.projection import _parse_connection_specs - - params_dict = {} - port_spec = port_specific_spec - - if isinstance(port_specific_spec, dict): - return None, port_specific_spec - - elif isinstance(port_specific_spec, tuple): - port_spec = None - params_dict[PROJECTIONS] = _parse_connection_specs(connectee_port_type=self, - owner=owner, - connections=port_specific_spec) - elif port_specific_spec is not None: - raise GatingSignalError("PROGRAM ERROR: Expected tuple or dict for {}-specific params but, got: {}". - format(self.__class__.__name__, port_specific_spec)) - - if params_dict[PROJECTIONS] is None: - raise GatingSignalError("PROGRAM ERROR: No entry found in {} params dict for {} " - "with specification of {}, {} or GatingProjection(s) to it". - format(GATING_SIGNAL, INPUT_PORT, OUTPUT_PORT, owner.name)) - return port_spec, params_dict - def _instantiate_cost_functions(self, context): """Override ControlSignal as GatingSignal has not cost functions""" pass diff --git a/psyneulink/core/components/ports/modulatorysignals/modulatorysignal.py b/psyneulink/core/components/ports/modulatorysignals/modulatorysignal.py index 697ee0ef062..deb1e474258 100644 --- a/psyneulink/core/components/ports/modulatorysignals/modulatorysignal.py +++ b/psyneulink/core/components/ports/modulatorysignals/modulatorysignal.py @@ -410,7 +410,7 @@ from psyneulink.core.globals.context import ContextFlags from psyneulink.core.globals.defaults import defaultModulatoryAllocation from psyneulink.core.globals.keywords import \ - ADDITIVE_PARAM, DISABLE, MAYBE, MECHANISM, MODULATION, MODULATORY_SIGNAL, MULTIPLICATIVE_PARAM, \ + ADDITIVE_PARAM, CONTROL, DISABLE, MAYBE, MECHANISM, MODULATION, MODULATORY_SIGNAL, MULTIPLICATIVE_PARAM, \ OVERRIDE, PROJECTIONS, VARIABLE from psyneulink.core.globals.preferences.preferenceset import PreferenceLevel diff --git a/psyneulink/core/components/ports/outputport.py b/psyneulink/core/components/ports/outputport.py index ef2213aafc2..5c2be3a09bc 100644 --- a/psyneulink/core/components/ports/outputport.py +++ b/psyneulink/core/components/ports/outputport.py @@ -615,11 +615,12 @@ """ import copy -import numpy as np -import typecheck as tc import types import warnings +import numpy as np +import typecheck as tc + from psyneulink.core.components.component import Component, ComponentError from psyneulink.core.components.functions.function import Function from psyneulink.core.components.ports.port import Port_Base, _instantiate_port_list, port_type_keywords @@ -627,13 +628,14 @@ from psyneulink.core.globals.keywords import \ ALL, ASSIGN, CALCULATE, CONTEXT, CONTROL_SIGNAL, FUNCTION, GATING_SIGNAL, INDEX, INPUT_PORT, INPUT_PORTS, \ MAPPING_PROJECTION, MECHANISM_VALUE, NAME, OUTPUT_PORT, OUTPUT_PORTS, OUTPUT_PORT_PARAMS, \ - OWNER_VALUE, PARAMS, PARAMS_DICT, PROJECTION, PROJECTIONS, RECEIVER, REFERENCE_VALUE, STANDARD_OUTPUT_PORTS, PORT, VALUE, VARIABLE, \ + OWNER_VALUE, PARAMS, PARAMS_DICT, PROJECTION, PROJECTIONS, RECEIVER, REFERENCE_VALUE, STANDARD_OUTPUT_PORTS, PORT, \ + VALUE, VARIABLE, \ output_port_spec_to_parameter_name, INPUT_PORT_VARIABLES from psyneulink.core.globals.parameters import Parameter from psyneulink.core.globals.preferences.basepreferenceset import is_pref_set from psyneulink.core.globals.preferences.preferenceset import PreferenceLevel from psyneulink.core.globals.utilities import \ - convert_to_np_array, is_numeric, iscompatible, make_readonly_property, recursive_update + convert_to_np_array, is_numeric, iscompatible, make_readonly_property, recursive_update, parse_valid_identifier __all__ = [ 'OutputPort', 'OutputPortError', 'PRIMARY', 'SEQUENTIAL', 'StandardOutputPorts', 'StandardOutputPortsError', @@ -672,10 +674,7 @@ def parse_variable_spec(spec): return spec elif isinstance(spec, tuple): # Tuple indexing item of owner's attribute (e.g.,: OWNER_VALUE, int)) - try: - owner_param_name = output_port_spec_to_parameter_name[spec[0]] - except KeyError: - owner_param_name = spec[0] + owner_param_name = output_port_spec_to_parameter_name.get(spec[0], spec[0]) try: index = spec[1]() if callable(spec[1]) else spec[1] @@ -683,19 +682,14 @@ def parse_variable_spec(spec): # context is None during initialization, and we don't want to # incur the cost of .get during execution if context is None: - return getattr(owner.parameters, owner_param_name).get(context)[index] + val = getattr(owner.parameters, owner_param_name).get(context) else: - return getattr(owner.parameters, owner_param_name)._get(context)[index] - except TypeError: - if context is None: - if getattr(owner.parameters, owner_param_name).get(context) is None: - return None - elif getattr(owner.parameters, owner_param_name)._get(context) is None: - return None - else: - # raise OutputPortError("Can't parse variable ({}) for {} of {}". - # format(spec, output_port_name or OutputPort.__name__, owner.name)) - raise Exception + val = getattr(owner.parameters, owner_param_name)._get(context) + + if hasattr(val, '_get_by_time_scale'): + return val._get_by_time_scale(index) + + return val if val is None else val[index] except: raise OutputPortError(f"Can't parse variable ({spec}) for " f"{output_port_name or OutputPort.__name__} of {owner.name}.") @@ -764,6 +758,7 @@ def __init__(self, error_value): def __str__(self): return repr(self.error_value) + class OutputPort(Port_Base): """ OutputPort( \ @@ -1056,6 +1051,12 @@ def _check_for_duplicate_projections(self, projection): def _get_primary_port(self, mechanism): return mechanism.output_port + def _get_all_afferents(self): + return self.mod_afferents + + def _get_all_projections(self): + return self.mod_afferents + self.efferents + def _parse_arg_variable(self, default_variable): return _parse_output_port_variable(default_variable, self.owner) @@ -1263,15 +1264,19 @@ def pathway_projections(self): def pathway_projections(self, assignment): self.efferents = assignment + @property + def efferents(self): + try: + return self._efferents + except: + self._efferents = [] + return self._efferents + # For backward compatibility with INDEX and ASSIGN @property def calculate(self): return self.assign - @property - def label(self): - return self.get_label() - def get_label(self, context=None): try: label_dictionary = self.owner.output_labels_dict @@ -1279,16 +1284,25 @@ def get_label(self, context=None): label_dictionary = {} return self._get_value_label(label_dictionary, self.owner.output_ports, context=context) - @property - def _dict_summary(self): - return { - **super()._dict_summary, - **{ - 'shape': str(self.defaults.value.shape), - 'dtype': str(self.defaults.value.dtype) - } - } + def as_mdf_model(self): + import modeci_mdf.mdf as mdf + + owner_func_name = parse_valid_identifier(self.owner.function.name) + if self._variable_spec == OWNER_VALUE: + value = owner_func_name + elif isinstance(self._variable_spec, tuple) and self._variable_spec[0] == OWNER_VALUE: + if len(self.owner.defaults.value) == 1: + value = owner_func_name + else: + value = f'{owner_func_name}[{self._variable_spec[1]}]' + else: + raise ValueError(f'Unsupported variable spec for MDF: {self._variable_spec}') + return mdf.OutputPort( + id=parse_valid_identifier(self.name), + value=value, + **self._mdf_metadata + ) def _instantiate_output_ports(owner, output_ports=None, context=None): """Call Port._instantiate_port_list() to instantiate ContentAddressableList of OutputPort(s) @@ -1643,6 +1657,7 @@ def names(self): # def indices(self): # return [item[INDEX] for item in self.data] + def _parse_output_port_function(owner, output_port_name, function, params_dict_as_variable=False): """Parse specification of function as Function, Function class, Function.function, types.FunctionType or types.MethodType. diff --git a/psyneulink/core/components/ports/parameterport.py b/psyneulink/core/components/ports/parameterport.py index 69431683dba..c37514c3f58 100644 --- a/psyneulink/core/components/ports/parameterport.py +++ b/psyneulink/core/components/ports/parameterport.py @@ -796,6 +796,12 @@ def _check_for_duplicate_projections(self, projection): f'{self.owner.name} already exists; will ignore additional one specified ({projection.name}).') return duplicate + def _get_all_afferents(self): + return self.mod_afferents + + def _get_all_projections(self): + return self.mod_afferents + @tc.typecheck def _parse_port_specific_specs(self, owner, port_dict, port_specific_spec): """Get connections specified in a ParameterPort specification tuple @@ -962,10 +968,12 @@ def _get_variable_from_projections(self, context=None): """ Get backingfield ("base") value of param of function of Mechanism to which the ParameterPort belongs. """ - # FIX 3/6/19: source does not yet seem to have been assigned to owner.function return self.source._get(context) + def get_label(self, context=None): + raise ParameterPortError(f"{ParameterPort.__name__}s do not have labels.") + @property def pathway_projections(self): raise ParameterPortError("PROGRAM ERROR: Attempt to access {} for {}; {}s do not have {}s". @@ -976,6 +984,7 @@ def pathway_projections(self, value): raise ParameterPortError("PROGRAM ERROR: Attempt to assign {} to {}; {}s cannot accept {}s". format(PATHWAY_PROJECTION, self.name, PARAMETER_PORT, PATHWAY_PROJECTION)) + def _instantiate_parameter_ports(owner, function=None, context=None): """Call _instantiate_parameter_port for all modulable parameters to instantiate ParameterPorts for them diff --git a/psyneulink/core/components/ports/port.py b/psyneulink/core/components/ports/port.py index 811bcb49c77..cdc89dc7b0b 100644 --- a/psyneulink/core/components/ports/port.py +++ b/psyneulink/core/components/ports/port.py @@ -166,7 +166,7 @@ `: * *PROJECTIONS*:List[<`projection specification `>,...] - the list must contain a one or more `Projection specifications ` to or from + the list must contain one or more `Projection specifications ` to or from the Port, and/or `ModulatorySignals ` from which it should receive projections (see `Port_Projections` below). @@ -449,8 +449,7 @@ .. _port_value_Spec_Example: -For example, the following specifies the InputPort by a value to use as its `default_variable -` attribute:: +For example, the following specifies the InputPort by a value to use as its `variable ` attribute:: my_mech = pnl.TransferMechanism(input_ports=[[0,0]) @@ -584,20 +583,23 @@ print(control_signal.name) for control_projection in control_signal.efferents: print("\t{}: {}".format(control_projection.receiver.owner.name, control_projection.receiver)) - > MY DDM DRIFT RATE AND THREHOLD CONTROL SIGNAL + > MY DDM DRIFT RATE AND THRESHOLD CONTROL SIGNAL > MY DDM: (ParameterPort drift_rate) > MY DDM: (ParameterPort threshold) Note that a ControlMechanism uses a **control_signals** argument in place of an **output_ports** argument (since it -uses `ControlSignal ` for its `OutputPorts `. In the example above, -both ControlProjections are assigned to a single ControlSignal. However, they could each be assigned to their own by -specifying them in separate itesm of the **control_signals** argument:: +uses `ControlSignal ` for its `OutputPorts `. Note also that, for specifying Projections +of a ControlSignal (i.e., its ControlProjections), the keyword *CONTROL* can be used in place of the more generic +*PROJECTIONS* keyword (as shown in the example below). + +In the example above, both ControlProjections are assigned to a single ControlSignal. However, they could each be +assigned to their own by specifying them in separate items of the **control_signals** argument:: my_mech = pnl.DDM(name='MY DDM') my_ctl_mech = pnl.ControlMechanism(control_signals=[{pnl.NAME: 'DRIFT RATE CONTROL SIGNAL', - pnl.PROJECTIONS: [my_mech.parameter_ports[pnl.DRIFT_RATE]]}, + pnl.CONTROL: [my_mech.parameter_ports[pnl.DRIFT_RATE]]}, {pnl.NAME: 'THRESHOLD RATE CONTROL SIGNAL', - pnl.PROJECTIONS: [my_mech.parameter_ports[pnl.THRESHOLD]]}]) + pnl.CONTROL: [my_mech.parameter_ports[pnl.THRESHOLD]]}]) # Print ControlSignals and their ControlProjections... > DRIFT RATE CONTROL SIGNAL > MY DDM: (ParameterPort drift_rate) @@ -769,24 +771,23 @@ def test_multiple_modulatory_projections_with_mech_and_port_Name_specs(self): import sys import types import warnings - -from collections.abc import Iterable from collections import defaultdict +from collections.abc import Iterable import numpy as np import typecheck as tc from psyneulink.core import llvm as pnlvm from psyneulink.core.components.component import ComponentError, DefaultsFlexibility, component_keywords -from psyneulink.core.components.functions.nonstateful.combinationfunctions import CombinationFunction, LinearCombination from psyneulink.core.components.functions.function import Function, get_param_value_for_keyword, is_function_type +from psyneulink.core.components.functions.nonstateful.combinationfunctions import CombinationFunction, LinearCombination from psyneulink.core.components.functions.nonstateful.transferfunctions import Linear from psyneulink.core.components.shellclasses import Mechanism, Projection, Port from psyneulink.core.globals.context import ContextFlags, handle_external_context from psyneulink.core.globals.keywords import \ - ADDITIVE, ADDITIVE_PARAM, AUTO_ASSIGN_MATRIX, \ - CONTEXT, CONTROL_PROJECTION_PARAMS, CONTROL_SIGNAL_SPECS, DEFERRED_INITIALIZATION, DISABLE, EXPONENT, \ - FUNCTION, FUNCTION_PARAMS, GATING_PROJECTION_PARAMS, GATING_SIGNAL_SPECS, INPUT_PORTS, \ + ADDITIVE, ADDITIVE_PARAM, AUTO_ASSIGN_MATRIX, CONTEXT, CONTROL_PROJECTION_PARAMS, CONTROL_SIGNAL_SPECS, \ + DEFAULT_INPUT, DEFAULT_VARIABLE, DEFERRED_INITIALIZATION, DISABLE, \ + EXPONENT, FUNCTION, FUNCTION_PARAMS, GATING_PROJECTION_PARAMS, GATING_SIGNAL_SPECS, INPUT_PORTS, \ LEARNING_PROJECTION_PARAMS, LEARNING_SIGNAL_SPECS, \ MATRIX, MECHANISM, MODULATORY_PROJECTION, MODULATORY_PROJECTIONS, MODULATORY_SIGNAL, \ MULTIPLICATIVE, MULTIPLICATIVE_PARAM, \ @@ -854,7 +855,7 @@ def __str__(self): return repr(self.error_value) -# DOCUMENT: INSTANTATION CREATES AN ATTIRBUTE ON THE OWNER MECHANISM WITH THE PORT'S NAME + VALUE_SUFFIX +# DOCUMENT: INSTANTIATION CREATES AN ATTIRBUTE ON THE OWNER MECHANISM WITH THE PORT'S NAME + VALUE_SUFFIX # THAT IS UPDATED BY THE PORT'S value setter METHOD (USED BY LOGGING OF MECHANISM ENTRIES) class Port_Base(Port): """ @@ -1020,6 +1021,7 @@ def __init__(self, This is used by subclasses to implement the InputPort(s), OutputPort(s), and ParameterPort(s) of a Mechanism. + COMMENT: [OLD] Arguments: - owner (Mechanism): Mechanism with which Port is associated (default: NotImplemented) @@ -1050,6 +1052,7 @@ def __init__(self, NOTES: * these are used for dictionary specification of a Port in param declarations * they take precedence over arguments specified directly in the call to __init__() + COMMENT """ if kwargs: try: @@ -1076,7 +1079,6 @@ def __init__(self, if name is not None and DEFERRED_INITIALIZATION in name: name = self._assign_default_port_Name() - # Register Port with PortRegistry of owner (Mechanism to which the Port is being assigned) register_category(entry=self, base_class=Port_Base, @@ -1097,9 +1099,6 @@ def __init__(self, **kwargs ) - self.path_afferents = [] - self.mod_afferents = [] - # IMPLEMENTATION NOTE: MOVE TO COMPOSITION ONCE THAT IS IMPLEMENTED # INSTANTIATE PROJECTIONS SPECIFIED IN projections ARG OR params[PROJECTIONS:<>] if self.projections is not None: @@ -1110,7 +1109,7 @@ def __init__(self, # if params = NotImplemented or there is no param[PROJECTIONS] pass - self.projections = self.path_afferents + self.mod_afferents + self.efferents + self.projections = self._get_all_projections() if context.source == ContextFlags.COMMAND_LINE: owner.add_ports([self]) @@ -1792,6 +1791,22 @@ def _get_receiver_port(spec): self.owner.aux_components.append((projection, feedback)) return projection + def remove_projection(self, projection, context=None): + if projection in self.afferents_info: + del self.afferents_info[projection] + if projection in self.projections: + self.projections.remove(projection) + try: + if projection in self.mod_afferents or projection in self.path_afferents: + self._remove_projection_to_port(projection, context=context) + except(PortError): + pass + try: + if projection in self.efferents: + self._remove_projection_from_port(projection, context=context) + except(PortError): + pass + def _remove_projection_from_port(self, projection, context=None): """Remove Projection entry from Port.efferents.""" del self.efferents[self.efferents.index(projection)] @@ -1804,6 +1819,9 @@ def _remove_projection_to_port(self, projection, context=None): if projection in self.mod_afferents: del self.mod_afferents[self.mod_afferents.index(projection)] else: + # Do this first so that if it fails (i.e., miscalled for OutputPort) + # no changes are made to the Port's or its function's variable + del self.path_afferents[self.path_afferents.index(projection)] shape = list(self.defaults.variable.shape) # Reduce outer dimension by one # only if shape is already greater than 1 (ports keep @@ -1812,12 +1830,17 @@ def _remove_projection_to_port(self, projection, context=None): if shape[0] > 0: self.defaults.variable = np.resize(self.defaults.variable, shape) self.function.defaults.variable = np.resize(self.function.defaults.variable, shape) - del self.path_afferents[self.path_afferents.index(projection)] def _get_primary_port(self, mechanism): raise PortError("PROGRAM ERROR: {} does not implement _get_primary_port method". format(self.__class__.__name__)) + def _get_all_projections(self): + assert False, f"Subclass of Port ({self.__class__.__name__}) must implement '_get_all_projections()' method." + + def _get_all_afferents(self): + assert False, f"Subclass of Port ({self.__class__.__name__}) must implement '_get_all_afferents()' method." + def _parse_port_specific_specs(self, owner, port_dict, port_specific_spec): """Parse parameters in Port specification tuple specific to each subclass @@ -2116,6 +2139,8 @@ def _execute(self, variable=None, context=None, runtime_params=None): # return None, so that this port is ignored # KDM 8/2/19: double check the relevance of this branch if variable is None: + if hasattr(self, DEFAULT_INPUT) and self.default_input == DEFAULT_VARIABLE: + return self.defaults.variable return None return super()._execute( @@ -2209,6 +2234,15 @@ def find_label_value_match(self, key, labels_dict, context=None): return label return self.parameters.value.get(context) + @property + def labeled_value(self): + return self.get_label() + + @property + def value_label(self): + """Alias of labeled_value""" + return self.labeled_value + @property def owner(self): return self._owner @@ -2219,7 +2253,7 @@ def owner(self, assignment): @property def all_afferents(self): - return self.path_afferents + self.mod_afferents + return self._get_all_afferents() @property def afferents_info(self): @@ -2229,22 +2263,45 @@ def afferents_info(self): self._afferents_info = {} return self._afferents_info + # IMPLEMENTATION NOTE: + # Every Port subtype has mod_afferents + # path_afferents are specific to InputPorts + # efferents are specific to OutputPorts + @property - def efferents(self): + def mod_afferents(self): try: - return self._efferents + return self._mod_afferents except: - self._efferents = [] - return self._efferents + self._mod_afferents = [] + return self._mod_afferents + + @property + def path_afferents(self): + raise PortError(f"{self.__class__.__name__}s do not have 'path_afferents'; " + f"(access attempted for {self.full_name}).") + + @path_afferents.setter + def path_afferents(self, value): + raise PortError(f"{self.__class__.__name__}s are not allowed to have 'path_afferents' " + f"(assignment attempted for {self.full_name}).") + + @property + def efferents(self): + # assert False, f"{self.__class__.__name__} must implement 'efferents' property." + raise PortError(f"{self.__class__.__name__}s do not have 'efferents'; " + f"(access attempted for {self.full_name}).") @efferents.setter def efferents(self, proj): - assert False, f"Illegal attempt to directly assign {repr('efferents')} attribute of {self.name}" + # assert False, f"Illegal attempt to directly assign {repr('efferents')} attribute of {self.name}" + raise PortError(f"{self.__class__.__name__}s are not allowed to have 'efferents' " + f"(assignment attempted for {self.full_name}).") @property def full_name(self): """Return name relative to owner as: []""" - if self.owner: + if hasattr(self, OWNER) and self.owner: return f'{self.owner.name}[{self.name}]' else: return self.name @@ -2264,13 +2321,21 @@ def _get_input_struct_type(self, ctx): # Use function input type. The shape should be the same, # however, some functions still need input shape workarounds. func_input_type = ctx.get_input_struct_type(self.function) - # MODIFIED 4/4/20 NEW: [PER JAN] - if len(self.path_afferents) > 0: - assert len(func_input_type) == len(self.path_afferents), \ - "{} shape mismatch: {}\nport:\n\t{}\n\tfunc: {}\npath_afferents: {}".format( - self, func_input_type, self.defaults.variable, - self.function.defaults.variable, len(self.path_afferents)) - # MODIFIED 4/4/20 END + + # Not all ports have path_afferents property. + len_path_afferents = len(self._get_all_afferents()) - len(self.mod_afferents) + + # Check that either all inputs or none are delivered by projections. + if len_path_afferents > 0: + assert len(func_input_type) == len_path_afferents, \ + f"{self.name} shape mismatch: {func_input_type}\nport:\n\t{self.defaults.variable}" \ + f"\n\tfunc: {self.function.defaults.variable}\npath_afferents: {len(self.path_afferents)}." + + if len(self.mod_afferents) == 0: + # Not need to wrap inputs of non-modulated ports inside mechanisms + # This makes sure the port input matches port data input and avoids a copy + return func_input_type + input_types = [func_input_type] # Add modulation for mod in self.mod_afferents: @@ -2278,13 +2343,20 @@ def _get_input_struct_type(self, ctx): return pnlvm.ir.LiteralStructType(input_types) def _gen_llvm_function_body(self, ctx, builder, params, state, arg_in, arg_out, *, tags:frozenset): - state_f = ctx.import_llvm_function(self.function) + port_f = ctx.import_llvm_function(self.function) - # Create a local copy of the function parameters base_params = pnlvm.helpers.get_param_ptr(builder, self, params, "function") - f_params = builder.alloca(state_f.args[0].type.pointee) - builder.store(builder.load(base_params), f_params) + + if any(a.sender.modulation != OVERRIDE for a in self.mod_afferents): + # Create a local copy of the function parameters only if + # there are modulating projections of type other than OVERRIDE. + # LLVM is not eliminating the redundant copy. + f_params = builder.alloca(port_f.args[0].type.pointee, + name="modulated_port_params") + builder.store(builder.load(base_params), f_params) + else: + f_params = base_params # FIXME: Handle and combine multiple afferents assert len(self.mod_afferents) <= 1 @@ -2332,13 +2404,16 @@ def _gen_llvm_function_body(self, ctx, builder, params, state, arg_in, arg_out, builder.store(param_val, f_mod_param_ptr) # OutputPort returns 1D array even for scalar functions - if arg_out.type != state_f.args[3].type: + if arg_out.type != port_f.args[3].type: assert len(arg_out.type.pointee) == 1 arg_out = builder.gep(arg_out, [ctx.int32_ty(0), ctx.int32_ty(0)]) # Extract the data part of input - f_input = builder.gep(arg_in, [ctx.int32_ty(0), ctx.int32_ty(0)]) + if len(self.mod_afferents) == 0: + f_input = arg_in + else: + f_input = builder.gep(arg_in, [ctx.int32_ty(0), ctx.int32_ty(0)]) f_state = pnlvm.helpers.get_state_ptr(builder, self, state, "function") - builder.call(state_f, [f_params, f_state, f_input, arg_out]) + builder.call(port_f, [f_params, f_state, f_input, arg_out]) return builder @staticmethod @@ -2357,20 +2432,15 @@ def _get_port_function_value(owner, function, variable, context=None): @property def _dependent_components(self): - return list(itertools.chain( - super()._dependent_components, - self.efferents, - )) - - @property - def _dict_summary(self): - return { - **super()._dict_summary, - **{ - 'shape': str(self.defaults.variable.shape), - 'dtype': str(self.defaults.variable.dtype) - } - } + try: + return list(itertools.chain( + super()._dependent_components, + self.efferents, + )) + except PortError: + return list(itertools.chain( + super()._dependent_components, + )) def _instantiate_port_list(owner, @@ -2491,9 +2561,15 @@ def _instantiate_port_list(owner, port_spec=port_spec, # name=name, context=context) - # automatically generate projections (e.g. when an InputPort is specified by the OutputPort of another mech) - for proj in port.path_afferents: - owner.aux_components.append(proj) + # automatically generate any Projections to InputPort or ParameterPort + # (e.g. if InputPort was specified using the OutputPort of another Mechanism, + # or a ParameterPort was specified using the ControlSignal of a ControlMechanism) + try: + for proj in port.path_afferents: + owner.aux_components.append(proj) + except PortError: + # OutputPort that has no path_afferents + pass # KDM 12/3/19: this depends on name setting for InputPorts that # ensures there are no duplicates. If duplicates exist, ports diff --git a/psyneulink/core/components/projections/modulatory/gatingprojection.py b/psyneulink/core/components/projections/modulatory/gatingprojection.py index 7b810775f4b..1c852bbea2c 100644 --- a/psyneulink/core/components/projections/modulatory/gatingprojection.py +++ b/psyneulink/core/components/projections/modulatory/gatingprojection.py @@ -110,7 +110,7 @@ from psyneulink.core.components.shellclasses import Mechanism, Process_Base from psyneulink.core.globals.context import ContextFlags from psyneulink.core.globals.keywords import \ - FUNCTION_OUTPUT_TYPE, GATING, GATING_MECHANISM, GATING_PROJECTION, GATING_SIGNAL, \ + FUNCTION_OUTPUT_TYPE, GATE, GATING_MECHANISM, GATING_PROJECTION, GATING_SIGNAL, \ INPUT_PORT, OUTPUT_PORT from psyneulink.core.globals.parameters import Parameter from psyneulink.core.globals.preferences.basepreferenceset import is_pref_set @@ -120,8 +120,8 @@ 'GATING_SIGNAL_PARAMS', 'GatingProjection', 'GatingProjectionError', ] -parameter_keywords.update({GATING_PROJECTION, GATING}) -projection_keywords.update({GATING_PROJECTION, GATING}) +parameter_keywords.update({GATING_PROJECTION, GATE}) +projection_keywords.update({GATING_PROJECTION, GATE}) GATING_SIGNAL_PARAMS = 'gating_signal_params' class GatingProjectionError(Exception): diff --git a/psyneulink/core/components/projections/projection.py b/psyneulink/core/components/projections/projection.py index 40fe7d7d67c..6999bca6702 100644 --- a/psyneulink/core/components/projections/projection.py +++ b/psyneulink/core/components/projections/projection.py @@ -133,7 +133,7 @@ as its the ControlProjection's `sender `. See `ControlMechanism_ControlSignals` for additional details. - * *GATING_PROJECTION* (or *GATING*) -- this can be used when specifying an `InputPort + * *GATING_PROJECTION* (or *GATE*) -- this can be used when specifying an `InputPort ` or an `OutputPort `, to create a default `GatingProjection` to the `Port `. If the GatingProjection's `sender ` cannot be inferred from the context in which this specification occurs, then its `initialization is deferred @@ -156,7 +156,7 @@ .. _Projection_Specification_Dictionary: - * **Specification dictionary** -- can contain an entry specifying the type of Projection, and/or entries + * **Projection specification dictionary** -- can contain an entry specifying the type of Projection, and/or entries specifying the value of parameters used to instantiate it. These should take the following form: * *PROJECTION_TYPE*: ** -- @@ -402,17 +402,19 @@ import typecheck as tc from psyneulink.core import llvm as pnlvm -from psyneulink.core.components.functions.nonstateful.transferfunctions import LinearMatrix from psyneulink.core.components.functions.function import get_matrix -from psyneulink.core.components.shellclasses import Mechanism, Process_Base, Projection, Port +from psyneulink.core.components.mechanisms.processing.processingmechanism import ProcessingMechanism +from psyneulink.core.components.functions.nonstateful.transferfunctions import LinearMatrix from psyneulink.core.components.ports.modulatorysignals.modulatorysignal import _is_modulatory_spec from psyneulink.core.components.ports.port import PortError +from psyneulink.core.components.shellclasses import Mechanism, Process_Base, Projection, Port from psyneulink.core.globals.context import ContextFlags +from psyneulink.core.globals.json import _get_variable_parameter_name from psyneulink.core.globals.keywords import \ - CONTROL, CONTROL_PROJECTION, CONTROL_SIGNAL, EXPONENT, FUNCTION_PARAMS, GATING, GATING_PROJECTION, GATING_SIGNAL, \ + CONTROL, CONTROL_PROJECTION, CONTROL_SIGNAL, EXPONENT, FUNCTION_PARAMS, GATE, GATING_PROJECTION, GATING_SIGNAL, \ INPUT_PORT, LEARNING, LEARNING_PROJECTION, LEARNING_SIGNAL, \ MAPPING_PROJECTION, MATRIX, MATRIX_KEYWORD_SET, MECHANISM, \ - MODEL_SPEC_ID_RECEIVER_MECH, MODEL_SPEC_ID_RECEIVER_PORT, MODEL_SPEC_ID_SENDER_MECH, MODEL_SPEC_ID_SENDER_PORT, \ + MODEL_SPEC_ID_RECEIVER_MECH, MODEL_SPEC_ID_RECEIVER_PORT, MODEL_SPEC_ID_SENDER_MECH, MODEL_SPEC_ID_SENDER_PORT, MODEL_SPEC_ID_METADATA, \ NAME, OUTPUT_PORT, OUTPUT_PORTS, PARAMS, PATHWAY, PROJECTION, PROJECTION_PARAMS, PROJECTION_SENDER, PROJECTION_TYPE, \ RECEIVER, SENDER, STANDARD_ARGS, PORT, PORTS, WEIGHT, ADD_INPUT_PORT, ADD_OUTPUT_PORT, \ PROJECTION_COMPONENT_CATEGORY @@ -420,7 +422,7 @@ from psyneulink.core.globals.preferences.preferenceset import PreferenceLevel from psyneulink.core.globals.registry import register_category, remove_instance_from_registry from psyneulink.core.globals.socket import ConnectionInfo -from psyneulink.core.globals.utilities import ContentAddressableList, is_matrix, is_numeric +from psyneulink.core.globals.utilities import ContentAddressableList, is_matrix, is_numeric, parse_valid_identifier __all__ = [ 'Projection_Base', 'projection_keywords', 'PROJECTION_SPEC_KEYWORDS', @@ -443,7 +445,7 @@ CONTROL: CONTROL_PROJECTION, CONTROL_SIGNAL: CONTROL_PROJECTION, CONTROL_PROJECTION: CONTROL_PROJECTION, - GATING: GATING_PROJECTION, + GATE: GATING_PROJECTION, GATING_SIGNAL: GATING_PROJECTION, GATING_PROJECTION: GATING_PROJECTION } @@ -976,6 +978,18 @@ def _activate_for_compositions(self, composition): def _activate_for_all_compositions(self): self._activate_for_compositions(ConnectionInfo.ALL) + def _deactivate_for_compositions(self, composition): + try: + self.receiver.afferents_info[self].remove_composition(composition) + except KeyError: + warnings.warn(f'{self} was not active for {composition}') + + def _deactivate_for_all_compositions(self): + self._deactivate_for_all_compositions(ConnectionInfo.ALL) + + def is_active_in_composition(self, composition): + return self.receiver.afferents_info[self].is_active_in_composition(composition) + def _delete_projection(projection, context=None): """Delete Projection, its entries in receiver and sender Ports, and in ProjectionRegistry""" projection.sender._remove_projection_from_port(projection) @@ -1039,34 +1053,115 @@ def _model_spec_parameter_blacklist(self): {'variable'} ) - @property - def _dict_summary(self): + def as_mdf_model(self, simple_edge_format=True): + import modeci_mdf.mdf as mdf + + from psyneulink.core.components.mechanisms.processing.compositioninterfacemechanism import CompositionInterfaceMechanism + # these may occur during deferred init if not isinstance(self.sender, type): - sender_name = self.sender.name - sender_mech = self.sender.owner.name + sender_name = parse_valid_identifier(self.sender.name) + if isinstance(self.sender.owner, CompositionInterfaceMechanism): + sender_mech = parse_valid_identifier(self.sender.owner.composition.name) + else: + sender_mech = parse_valid_identifier(self.sender.owner.name) else: sender_name = None sender_mech = None if not isinstance(self.receiver, type): - receiver_name = self.receiver.name - receiver_mech = self.receiver.owner.name + try: + num_path_afferents = len(self.receiver.path_afferents) + except PortError: + # ParameterPort as receiver + num_path_afferents = 0 + + if num_path_afferents > 1: + receiver_name = parse_valid_identifier(f'input_port_{self.name}') + else: + receiver_name = parse_valid_identifier(self.receiver.name) + + if isinstance(self.receiver.owner, CompositionInterfaceMechanism): + receiver_mech = parse_valid_identifier(self.receiver.owner.composition.name) + else: + receiver_mech = parse_valid_identifier(self.receiver.owner.name) else: receiver_name = None receiver_mech = None socket_dict = { - MODEL_SPEC_ID_SENDER_PORT: sender_name, - MODEL_SPEC_ID_RECEIVER_PORT: receiver_name, + MODEL_SPEC_ID_SENDER_PORT: f'{sender_mech}_{sender_name}', + MODEL_SPEC_ID_RECEIVER_PORT: f'{receiver_mech}_{receiver_name}', MODEL_SPEC_ID_SENDER_MECH: sender_mech, MODEL_SPEC_ID_RECEIVER_MECH: receiver_mech } - return { - **super()._dict_summary, - **socket_dict - } + parameters = self._mdf_model_parameters + if self.defaults.weight is None: + parameters[self._model_spec_id_parameters]['weight'] = 1 + + if simple_edge_format and not self.function._is_identity(defaults=True): + edge_node = ProcessingMechanism( + name=f'{self.name}_dummy_node', + default_variable=self.defaults.variable, + function=self.function + ) + edge_function = edge_node.function + edge_node = edge_node.as_mdf_model() + + func_model = [f for f in edge_node.functions if f.id == parse_valid_identifier(edge_function.name)][0] + var_name = _get_variable_parameter_name(edge_function) + + # 2d variable on LinearMatrix will be incorrect on import back to psyneulink + func_model.metadata[var_name] = func_model.metadata[var_name][-1] + + pre_edge = mdf.Edge( + id=parse_valid_identifier(f'{self.name}_dummy_pre_edge'), + # assume weight applied before function + **{ + self._model_spec_id_parameters: { + 'weight': parameters[self._model_spec_id_parameters]['weight'] + }, + MODEL_SPEC_ID_SENDER_PORT: f'{sender_mech}_{sender_name}', + MODEL_SPEC_ID_RECEIVER_PORT: edge_node.input_ports[0].id, + MODEL_SPEC_ID_SENDER_MECH: sender_mech, + MODEL_SPEC_ID_RECEIVER_MECH: edge_node.id + } + ) + + for name, value in parameters[self._model_spec_id_parameters].items(): + if name not in {'weight'}: + edge_node.parameters.append(mdf.Parameter(id=name, value=value)) + edge_node.metadata.update(self._mdf_metadata[MODEL_SPEC_ID_METADATA]) + + post_edge = mdf.Edge( + id=parse_valid_identifier(f'{self.name}_dummy_post_edge'), + **{ + MODEL_SPEC_ID_SENDER_PORT: edge_node.output_ports[0].id, + MODEL_SPEC_ID_RECEIVER_PORT: f'{receiver_mech}_{receiver_name}', + MODEL_SPEC_ID_SENDER_MECH: edge_node.id, + MODEL_SPEC_ID_RECEIVER_MECH: receiver_mech + } + ) + return pre_edge, edge_node, post_edge + else: + metadata = self._mdf_metadata + try: + metadata[MODEL_SPEC_ID_METADATA]['functions'] = mdf.Function.to_dict_format( + self.function.as_mdf_model(), + ordered=False + ) + except AttributeError: + # projection is in deferred init, special handling here? + pass + + return mdf.Edge( + id=parse_valid_identifier(self.name), + **socket_dict, + **parameters, + **metadata + ) + @tc.typecheck def _is_projection_spec(spec, proj_type:tc.optional(type)=None, include_matrix_spec=True): diff --git a/psyneulink/core/compositions/composition.py b/psyneulink/core/compositions/composition.py index 2e4bed59130..836454b9c0f 100644 --- a/psyneulink/core/compositions/composition.py +++ b/psyneulink/core/compositions/composition.py @@ -339,21 +339,31 @@ .. _Composition_Probes: -* *Probes* -- Nodes that are not `OUTPUT ` of a nested Composition but project to ones in an - outer Composition are assigned `PROBE ` in addition to their other `roles ` in the +* *Probes* -- Nodes that are not `OUTPUT ` of a nested Composition, but project to ones in an + outer Composition, are assigned `PROBE ` in addition to their other `roles ` in the nested Composition. The only difference between `PROBE ` and `OUTPUT ` Nodes is whether their output is included in the `output_values ` and `results - ` attributes of the outermost Composition to which they project; this is determined by the + ` attributes of the *outermost* Composition to which they project; this is determined by the `include_probes_in_output ` attribute of the latter. If `include_probes_in_output ` is False (the default), then the output of any - `PROBE ` Nodes in any Composition nested within it are *not* included in - the `output_values ` or `results ` for the Composition to which - they project. In this respect, they can be thought of as "probing" - that is, providing access to "latent variables" - of -- the Composition to which they belong -- the values of which that are not otherwise reported as part of the - Composition's output or results. If `include_probes_in_output ` is True, - then any `PROBE ` Nodes of any nested Compositions are treated the same as `OUTPUT ` - Nodes: their outputs are included in the `output_values ` and `results - ` of that Composition. + `PROBE ` Nodes are *not* included in the `output_values ` or `results + ` for the outermost Composition to which they project (although they *are* still included + in those attributes of the nested Compositions; see note below). In this respect, they can be thought of as + "probing" - that is, providing access to "latent variables" of -- the nested Composition to which they belong -- + the values of which that are not otherwise reported as part of the outermost Composition's output or results. If + `include_probes_in_output ` is True, then any `PROBE ` Nodes + of any nested Compositions are treated the same as `OUTPUT ` Nodes: their outputs are included in + the `output_values ` and `results ` of the outermost Composition. + `PROBE ` Nodes can be visualized, along with any Projections treated differently from those of + `OUTPUT ` Nodes (i.e., when `include_probes_in_output ` is + False), using the Composition's `show_graph ` method, which displays them in their own color + (pink by default). + + .. hint:: + `PROBE ` Nodes are useful for `model-based optimization using an + `, in which the value of one or more Nodes in a nested Composition + may need to be `monitored ` without being considered as + part of the output or results of the Composition being optimized. .. note:: The specification of `include_probes_in_output ` only applies to a @@ -370,8 +380,8 @@ *Inputs for nested Compositions*. If a nested Composition is an `INPUT` Node of all of the Compositions within which it is nested, including the outermost one, then when the latter is `executed `, the `inputs specified ` to its `execution method ` must -include the InputPorts of the nested Composition. These can be accessed using the Composition's `exernal_input_ports -` attribute. +include the InputPorts of the nested Composition. These can be accessed using the Composition's +`external_input_ports_of_all_input_nodes ` attribute. .. _Composition_Nested_Results: @@ -379,7 +389,7 @@ which it is nested, including the outermost one, then when the latter is `executed `, both the `output_values ` and `results ` of the nested Composition are also included in those attributes of any intervening and the outermost Composition. If `allow_probes -` is set, then the Composition's `include_probes_in_output +` is set (which it is by default), then the Composition's `include_probes_in_output ` attribute determines whether their values are also included in the `output_values ` and `results ` of the outermost Composition (see `above `). @@ -458,7 +468,7 @@ Second, they can be the receiver of a Projection, as in the case of a MappingProjection that receives a `LearningProjection` used to modify its `matrix ` parameter. Nevertheless, since they define the connections and therefore dependencies among the Composition's Nodes, they determine the structure of its -graph. Subsets of Nodes connected by Projections are often defined as a `Pathway ` as decribed under +graph. Subsets of Nodes connected by Projections can be defined as a `Pathway ` as decribed under `Composition_Pathways` below). .. _Composition_Graph_Projection_Vertices: @@ -469,13 +479,28 @@ Although individual Projections are directed, pairs of Nodes can be connected with Projections in each direction (forming a local `cycle `), and the `AutoAssociativeProjection` class of Projection can even -connect a Node with itself. Projections can also connect the Node(s) of a Composition to one(s) `nested within it -`. In general, these are to the `INPUT ` Nodes and from the `OUTPUT +connect a Node with itself. Projections can also connect the Node(s) of a Composition to one(s) `nested within +it `. In general, these are to the `INPUT ` Nodes and from the `OUTPUT ` Nodes of a `nested Composition `, but if the Composition's `allow_probes ` attribute is not False, then Projections can be received from any Nodes within a nested Composition (see `Probes ` for additional details). A ControlMechanism can also control (i.e., send a `ControlProjection`) to any Node within a nested Composition. +Projections can be specified between `Mechanisms ` before they are added to a Composition. If both +Mechanisms are later added to the same Composition, and the Projection between them is legal for the Composition, +then the Projection between them is added to it and is used during its `execution `. +However, if the Projection is not legal for the Composition (e.g., the Mechanisms are not assigned as `INTERNAL +` `Nodes ` of two different `nested Compositions `), +the Projection will still be associated with the two Mechanisms (i.e., listed in their `afferents +` and `efferents ` attributes, respectively), but it is not +added to the Composition and not used during its execution. + + .. hint:: + Projections that are associated with the `Nodes ` of a Composition but are not in the + Composition itself (and, accordingly, *not* listed it is `projections ` attribute) + can still be visualized using the Composition's `show_graph ` method, by specifying its + **show_projections_not_in_composition** argument as True; Projections not in the Composition appear in red. + .. technical_note:: .. _Composition_Projections_to_CIMs: @@ -813,7 +838,7 @@ It also assigns the following item to the list of `learning_components` for the pathway: .. _OUTPUT_MECHANISM: - * *OUTPUT_MECHANISM* -- the final `Node ` in the learning Pathway, the target `value + * *OUTPUT_MECHANISM* -- the final `Node ` in the learning Pathway, the target `value ` for which is specified as input to the `TARGET_MECHANISM`; the Node is assigned the `NodeRoles ` `OUTPUT` in the Composition. @@ -980,6 +1005,8 @@ - `Execution Methods ` - `Composition_Execution_Inputs` + • `Composition_Input_Dictionary` + • `Composition_Programmatic_Inputs` - `Composition_Execution_Factors` • `Composition_Runtime_Params` • `Composition_Cycles_and_Feedback` @@ -1049,21 +1076,21 @@ - `Composition_Input_Dictionary` - `Composition_Programmatic_Inputs` -All `methods of executing a Composition require specification of an **inputs** -argument (and a **targets** argument for `learn ` method), which designates the values assigned -to the `INPUT ` `(and, for learning, the `TARGET `) Nodes ` +All `methods of executing ` a Composition require specification of an **inputs** +argument (and a **targets** argument for the `learn ` method), which designates the values assigned +to the `INPUT ` (and, for learning, the `TARGET `) `Nodes ` of the Composition. These are provided to the Composition each time it is executed; that is, for each `TRIAL `. A `TRIAL ` is defined as the opportunity for every Node in the Composition to execute the current set of inputs. The inputs for each `TRIAL ` can be specified using an `input dictionary `; for the `run ` and `learn ` methods, they can also be specified `programmatically `. Irrespective of format, the same number of inputs must be specified for every `INPUT` Node, unless only one value is specified for a Node (in which -case that value is provided as the input to that Node for every `TRIAL `\\s executed). If the -**inputs** argument is not specified for the `run ` or `execute ` methods, -the `default_variable ` for each `INPUT` Node is used as its input on `TRIAL `. +case that value is repeated as the input to that Node for every `TRIAL `\\s executed). If the +**inputs** argument is not specified for the `run ` or `execute ` methods, the +`default_variable ` for each `INPUT` Node is used as its input on `TRIAL `. If it is not specified for the `learn ` method, an error is generated unless its **targets** argument is specified (see `below `). The Composition's `get_input_format() -` method can be used to show a template for how inputs should be formatted for the +` method can be used to show an example for how inputs should be formatted for the Composition, as well as the `INPUT ` Nodes to which they are assigned. The formats are described in more detail below. @@ -1085,24 +1112,30 @@ format can be used for the `execute ` method, since it executes only one `TRIAL ` at a time, and therefore can only accept inputs for asingle `TRIAL `. +.. _Composition_Input_External_InputPorts: + *Inputs and input_ports*. All formats must specify the inputs to be assigned, on each `TRIAL `, to -the InputPorts of the Composition's `INPUT` `Nodes ` that require external inputs. These are listed -in the `external_input_ports ` attribute of the Composition's `INPUT` -`Mechanisms `, and the corresponding attribute (`external_input_ports `) -of any `nested Composition ` that is an `INPUT` Node of the Composition being executed -(see `above `). The format required can also be seen using the -`get_input_format() ` method. +*all* of the **external InputPorts** of the Composition's `INPUT` `Nodes `. These are InputPorts +belonging to its `INPUT` `Nodes ` at *all levels of nesting*, that are not designated as +`internal_only `. They are listed in the Composition's `external_input_ports_of_all_input_nodes +` attribute, as well as the `external_input_ports +` attribute of each `Mechanism` that is an `INPUT ` +`Node ` of the Composition or any `nested Composition ` within it +The format required can also be seen using the `get_input_format() ` method. + +.. _Composition_Input_Internal_Only: .. note:: - Most Mechanisms have only a single `InputPort`, and thus require only a single input to be specified for them - for each `TRIAL `. However some Mechanisms have more than one InputPort (for example, a - `ComparatorMechanism`), in which case an input must be specified for each InputPort of that Mechanism. Conversely, - some Mechanisms have input_ports that are marked as `internal_only ` (for example, - the `input_port ` for a `RecurrentTransferMechanism`, if its `has_recurrent_input_port - ` is True), in which case no input should be specified for - that input_port. Similar considerations extend to the `external_input_ports ` - of a `nested Composition `, based on the Mechanisms (and/or additionally nested Compositions) - that comprise its set of `INPUT` `Nodes `. + Most Mechanisms have only a single `InputPort`, and thus require only a single input to be specified for + them for each `TRIAL `. However some Mechanisms have more than one InputPort (for example, + a `ComparatorMechanism`), in which case inputs can be specified for some or all of them (see `below + `). Conversely, some Mechanisms have InputPorts that are designated + as `internal_only ` (for example, the `input_port ` for a + `RecurrentTransferMechanism`, if its `has_recurrent_input_port ` + attribute is True), in which case no input should be specified for those input_ports. Similar considerations + extend to the `external_input_ports_of_all_input_nodes ` of a + `nested Composition `, based on the Mechanisms (and/or additionally nested Compositions) that + comprise its set of `INPUT` `Nodes `. The factors above determine the format of each entry in an `inputs dictionary `, or the return value of the function or generator used for `programmatic specification ` of @@ -1114,39 +1147,147 @@ *Input Dictionary* ================== +.. _Composition_Input_Dictionary_Entries: + The simplest way to specificy inputs (including targets for learning) is using a dict, in which each entry specifies -the inputs to a given `INPUT` `Node `. The key of each entry is a Node, and the value is a list of -the inputs to that Node, one for each `TRIAL ` to be executed (i.e., the i-th item of the list -represents the input to the Node on `TRIAL ` i). The same number of input values must be specified -in each entry, unless only a single input value is specified is in an entry, in which case that input is presented to -the corresonding Node in every `TRIAL `. - -.. _Composition_Execution_Input_Dict_Fig: - -.. figure:: _static/Composition_input_dict_spec.svg - :alt: Example input dict specification showing inputs specified for each Node and its InputPorts - - Example input dict specification, in which the first entry is for Mechanism ``a`` with one `InputPort` that takes - an array of length 2 as its input, and for which two `TRIAL `\\s worth of input are specified - (``[1.0, 2.0]`` and ``[3,0, 4.0]``); the second entry is for Mechanism ``b`` with two InputPorts, one of which - takes an array of length 1 as its input and the other an array of length 2, and for which two `TRIAL - `\\s worth of input are also specified (``[[1.0], [2.0, 3.0]]`` and ``[[4.0], [5.0, 6.0]]``); - and, finaly, a third entry is for Mechanism ``c`` with only one InputPort that takes an array of length 1 as its - input, and for which only one input is specified (``[1.0]``), which is therefore provided as the input to - Mechanism ``c`` on every `TRIAL `. - -The input specified for each `Node ` must be compatible with the number of `InputPorts ` -that receive external input for that Node. These are listed in its ``external_input_ports`` attribute (`here -` if it is Mechanism, or `here ` if it is a -Composition). More specifically, the shape of the input value must be compatible with the shape of the Node's -`external_input_values` attribute (`here ` if it is Mechanism, -or `here ` if it is a Composition). While these are always 2d arrays, the number -and size of the items (corresponding to each InputPort) may vary; in some case shorthand notations are allowed, -as illustrated in the `examples ` below. +the inputs to a given `INPUT ` `Node `. The key for each entry of the dict is +either an `INPUT ` `Node ` or the `InputPort` of one, and the value is the input +to be provided to it for each `TRIAL ` of execution. A diciontary can have entries for *either* an +INPUT Node or one or more of its InputPorts, but *not both*. Entries can be for any `INPUT ` Node +(or the Inputport(s) of one) at any level of nesting within the Composition, so long it is nested under INPUT Nodes +at all levels of nesting (that is, an INPUT Node of a nested Composition can only be included if the nested Composition +is a INPUT Node of the Composition to which it belongs). Any INPUT Nodes for which no input is specified (that is, for +which there are no entries in the inputs dictionary) are assigned their `default_external_inputs +` on each `TRIAL ` of execution; similarly, if the dictionary +contains entries for some but not all of the InputPorts of a Node, the remaining InputPorts are assigned their +`default_input ` on each `TRIAL ` of execution. See below for additional +information concerning `entries for Nodes ` and `entries for InputPorts +`). + +.. _Composition_Input_Dictionary_Input_Values: + +*Input values*. The value of each entry is an ndarray or nested list containing the inputs to that Node or InputPort. +For Nodes, the value is a 3d array (or correspondingly nested list), in which the outermost items are 2d arrays +containing the 1d array of input values to each of the Node's InputPorts for a given `TRIAL `. For +entries specifying InputPorts, the value is a 2d array, containing 1d arrays with the input to the InputPort for each +`TRIAL `. A given entry can specify either a single `TRIAL `\\'s worth of input +(i.e., a single item in its outermost dimension), or inputs for every `TRIAL ` to be executed (in +which the i-th item represents the input to the `INPUT ` Node, or one of its InputPorts, on `TRIAL +` i). All entries that contain more than a single trial's worth of input must contain exactly the +same number of values -- i.e.,inputs for the same number of trials. For entries that contain a single input value, +that value will be provided repeatedly as the input to the specified Component for every `TRIAL ` +when the Composition is executed (as determined by the number of input values specified for other entries and/or the +**num_trials** argument of the Composition's `run ` method (see `number of trials +` above). + +.. _Composition_Input_Dictionary_Node_Entries: + +*Node entries*. The key must be an `INPUT ` `Node ` of the Composition, or the name of +one (i.e., the str in its `name ` attribute), and the value must specify the input to *all* of its +InputPorts (other than those designated as `internal_only `; see `note +` above) for one or all `TRIAL `\\s of execution. The values +for each `TRIAL ` must be compatible with each of the corresponding InputPorts (listed in the +`external_input_ports ` attribute of a Mechanism, and similarly in the +`external_input_ports_of_all_input_nodes ` attribute of a +Composition). More specifically, the shape of each item in the outer dimension (i.e., the input for each `TRIAL +`, as described `above `) must be compatible with the +shape of the Node's `external_input_shape ` attribute if it is Mechanism, and +similarly the `external_input_shape ` attribute of a Composition). While these are +always 2d arrays, the number and size of the 1d arrays within them (corresponding to each InputPort) may vary; in some +case shorthand notations are allowed, as illustrated in the `examples ` below. + + .. _Composition_Execution_Input_Dict_Fig: + + .. figure:: _static/Composition_input_dict_spec.svg + :alt: Example input dict specification showing inputs specified for each Node and its InputPorts + + Example input dict specification, in which the first entry is for Mechanism ``a`` with one `InputPort` that takes + an array of length 2 as its input, and for which two `TRIAL `\\s worth of input are specified + (``[1.0, 2.0]`` and ``[3,0, 4.0]``); the second entry is for Mechanism ``b`` with two InputPorts, one of which + takes an array of length 1 as its input and the other an array of length 2, and for which two `TRIAL + `\\s worth of input are also specified (``[[1.0], [2.0, 3.0]]`` and ``[[4.0], [5.0, 6.0]]``); + and, finaly, a third entry is for Mechanism ``c`` with only one InputPort that takes an array of length 1 as its + input, and for which only one input is specified (``[1.0]``), which is therefore provided as the input to + Mechanism ``c`` on every `TRIAL `. + +.. _Composition_Input_Dictionary_InputPort_Entries: + +*InputPort Entries*. The key must be an `external InputPort ` for an +`INPUT ` `Node ` of the Composition, or the `full_name ` of one, +and the value must specify the input for one or all `TRIAL `\\s of execution. Any or all of the +InputPorts for an`INPUT ` `Node ` can be specified, but an inputs dictionary cannot +have specifications for both the Node and any of its InputPorts. If the name of an InputPort is used as the key, its +the str in its `full_name ` attribute must be used, to ensure disambiguation from any similarly +named InputPorts of other Nodes. Specifying InputPorts individually (instead of specifying all of them in a single +entry for a Node) can be if only some InputPorts should receive inputs, or the input for some needs to remain constant +across `TRIAL `\\s (by providing it with only one input value) while the input to others vary +(i.e., by providing input_values for every `TRIAL `). The value of each entry must be a 2d array +or nested list containing the input for either a single `TRIAL ` or all `TRIAL `\\s, +each of which must match the `input_shape ` of the InputPort. As with Nodes, if there are +entries for some but not all of a Node's InputPorts, the ones not specified are assigned their `default_input +` values for every `TRIAL ` of execution. + +COMMENT: + Example of input dictionary show various ways of specifying inputs for Nodes and InputPorts:: + + >>> A = ComparatorMechanism(name='A') + >>> B = ProcessingMechanism(name='B', default_variable=[0,0,0]) + >>> inner_nested_comp = Composition(nodes=[A, B]) + + >>> C = ComparatorMechanism(name='C', size=3) + >>> nested_comp_1 = Composition(nodes=[C, inner_nested_comp]) + + >>> D = ComparatorMechanism(name='D', size=3) + >>> E = ComparatorMechanism(name='E', size=3) + >>> nested_comp_2 = Composition([D, E]) + + >>> F = ComparatorMechanism(name='F') + >>> G = ProcessingMechanism(name='G') + >>> nested_comp_3 = Composition([F, G]) + + >>> H = ComparatorMechanism(name='H') + >>> I = ProcessingMechanism(name='I') + >>> outer_comp = Composition(pathways=[nested_comp_1, nested_comp_2], nodes=[H, I, nested_comp_3]]) + + >>> input_dict = {A.input_ports['SAMPLE']:[[.5]], # Note: only a signle TRIAL of input is specified + ... A['TARGET']:[[1],[2]], # Note: name of InputPort is used as key + ... B:[[[3,4,5]]], # Note: only a signle TRIAL of input is specified + ... "C":[[[.5],[1]]], # Note: name of Node is used as key + ... D:[[[6,7,8]],[[9,10,11]]], + ... nested_comp_3: [[[12]],[[13]], # Note: full input nested Composition is provide + ... [[14]],[[15]]]} # for each TRIAL of execution + >>> outer_comp.get_input_format() + >>> outer_comp.external_input_shape + >>> outer_comp.external_input_ports_of_all_input_nodes + >>> outer_comp.run(inputs=inputs) + Add output here + + Show example of get_input_format() + Show example of get_external_inputs + + In this example, `ComparatorMechanism` ``A`` has two `InputPorts ` that are specified inidividually, + one of which (``SAMPLE``) has only one `TRIAL ` of input specified, while the other + (``TARGET``) has two `TRIAL `\\s of input specified; ``B`` has only one `TRIAL ` + specified, the length of which matches the shape of its `default_variable `; + + - Add show_graph() + - A & B are both INPUT Nodes of inner_nested_comp, which is an INPUT node of nested_comp_1, which is an INPUT Node + of outer_comp, so they count as INPUT Nodes + - D is an INPUT Node of nested_comp_2, but since nested_comp_2 is *not* an INPUT Node of outer_comp, it is not + D is not an INPUT Node of outer_comp and thus neiter D nor nested_comp_2 can be listed in the inputs_dict + - nested_comp_3 is an INPUT Node of outer_comp, so it (as shown in this example) or its INPUT Nodes (F, G) or their + InputPorts can be included as entries in the inputs dict for outer_comp. + - inputs for nested_comp_3 must contain all of the InputPorts for all of its InputNodes (F and G): two for F and + one for G; all have to have the same number of trials (here two) as each other and all other entries in the + inputs dictionary. + - H and I are both INPUT Nodes of outer_comp + - 'C' is specified by its name +COMMENT .. _Composition_Input_Labels: -In general, the value of inputs should be numeric arrays; however, some Mechanisms have an `input_labels_dict +*Input Labels*. In general, the value of inputs should be numeric arrays; however, some Mechanisms have an +`input_labels_dict ` that specifies a mapping from strings (labels) to numeric values, in which those strings can be used to specify inputs to that Mechanism (these are translated to their numeric values on execution). However, such labels are specific to a given Mechanism; use of strings as input to a Mechanism that does not have an @@ -1155,8 +1296,8 @@ .. _Composition_Target_Inputs: -For learning, inputs must also be specified for the `TARGET_MECHANISM ` of each -`learning Pathway ` in the Composition. This can be done in either the **inputs** +*Target Inputs for learning*. Inputs must also be specified for the `TARGET_MECHANISM ` +of each `learning Pathway ` in the Composition. This can be done in either the **inputs** argument or **targets** argument of the `learn ` method. If the **inputs** argument is used, it must include an entry for each `TARGET_MECHANISM `; if the **targets** argument is used, it must be assigned a dictionary containing entries in which the key is either an `OUTPUT_MECHANISM @@ -1350,10 +1491,10 @@ def input_function(env, result): Runtime parameter values for a Composition are specified in a dictionary assigned to the **runtime_params** argument of a Composition's `execution method `. The key of each entry is a Node of the Composition, and the value is a subdictionary specifying the **runtime_params** argument that will be passed to the -Node when it is executed. The format of the dictionary for each `Node ` follows that for a Mechanism's -`runtime specification dictionary `, except that in addition to specifying the -value of a parameter directly (in which case, the value will apply throughout the execution), its value can also be -placed in a tuple together with a `Condition` specifying when that value should be applied, as follows: +Node when it is executed. The format of the dictionary for each `Node ` follows that for a +Mechanism's `runtime specification dictionary `, except that in addition to +specifying the value of a parameter directly (in which case, the value will apply throughout the execution), its value +can also be placed in a tuple together with a `Condition` specifying when that value should be applied, as follows: * Dictionary assigned to **runtime_parms** argument: {: Runtime Parameter Specification Dictionary} - *key* - Node @@ -1639,10 +1780,10 @@ def input_function(env, result): COMMENT: ?? OR JUST THEIR `previous_value ` ?? COMMENT - of its `StatefulFunction`. If it is called without any arguments, it calls the `reset ` method - for every `Node ` in the Composition that has a `StatefulFunction`. It can also be called with a - dictionary that specifies a subsset of Nodes to reset (see format descdribed for **reset_stateful_functions_when** - below). + of its `StatefulFunction`. If it is called without any arguments, it calls the `reset ` + method for every `Node ` in the Composition that has a `StatefulFunction`. + It can also be called with a dictionary that specifies a subsset of Nodes to reset (see format descdribed for + **reset_stateful_functions_when** below). * **reset_stateful_functions_when** and **reset_stateful_functions_to** -- these are arguments of the Composition's `run ` and `learn ` methods, that can be used to specify the `Conditions @@ -1813,7 +1954,7 @@ def input_function(env, result): XXX - ADD DISCUSSION OF show_controller AND show_learning COMMENT -The `show_graph ` method generates a display of the graph structure of `Nodes +The `show_graph ` method generates a display of the graph structure of `Nodes ` and `Projections ` in the Composition based on the Composition's `graph ` (see `Visualization` for additional details). @@ -1987,17 +2128,22 @@ def input_function(env, result): >>> comp.run(inputs=input_dictionary) -Since the specification of the `default_variable ` for Mechanism ``a`` is a single array of -length 2, it is constructed with a single `InputPort` (see `Mechanism_InputPorts`) that takes an array of that +Since the specification of the `default_variable ` for Mechanism ``a`` is a single array +of length 2, it is constructed with a single `InputPort` (see `Mechanism_InputPorts`) that takes an array of that shape as its input; therefore, the input value specified for each `TRIAL ` is a length 2 array (``[1.0, 1.0]``). In contrast, since the `default_variable ` for Mechanism ``b`` is two length 1 arrays, so it is constructed with two InputPorts, each of which takes a length 1 array as its input; therefore, the input specified for each `TRIAL ` must be two length 1 arrays. See `figure ` for an illustration of the format for an input dictionary. +COMMENT: MODIFIED 2/4/22 OLD: +# FIX: 2/4/22 - ADD NOTE THAT external_input_values IS NOT NECESSARILY SAME AS external_input_variables + AS SOME InputPorts CAN HAVE FUNCTIONS THAT CHANGE THE SHAPE OF variable->value (e.g., Reduce) + # Furthermore, Mechanisms can also have InputPorts with a `function ` that changes + # the size of its input when generatings its `value `, in which case its `e .. note:: A `Node's ` `external_input_values` attribute is always a 2d list in which the index i - element is the value of the i'th element of the Node's `external_input_ports` attribute. For Mechanisms, + element is the variable of the i'th element of the Node's `external_input_ports` attribute. For Mechanisms, the `external_input_values ` is often the same as its `variable `. However, some Mechanisms may have InputPorts marked as `internal_only ` which are excluded from its `external_input_ports ` @@ -2005,6 +2151,19 @@ def input_function(env, result): input value. The same considerations extend to the `external_input_ports ` and `external_input_values ` of a Composition, based on the Mechanisms and/or `nested Compositions ` that comprise its `INPUT` Nodes. +MODIFIED 2/4/22 NEW: +COMMENT +.. note:: + A `Node's ` `external_input_variables` attribute is always a 2d list in which the index i + element is the variable of the i'th element of the Node's `external_input_ports` attribute. For Mechanisms, + the `external_input_variables ` is often the same as its `variable + `. However, some Mechanisms may have InputPorts marked as `internal_only + ` which are excluded from its `external_input_ports ` + and therefore its `external_input_variables `, and so should not receive + an input value. The same considerations extend to the `external_input_ports_of_all_input_nodes + ` and `external_input_variables + ` of a Composition, based on the Mechanisms and/or `nested Compositions + ` that comprise its `INPUT` Nodes. If num_trials is not in use, the number of inputs provided determines the number of `TRIAL `\\s in the run. For example, if five inputs are provided for each `INPUT` `Node `, and num_trials is not @@ -2562,6 +2721,7 @@ def input_function(env, result): from psyneulink.core import llvm as pnlvm from psyneulink.core.components.component import Component, ComponentsMeta +from psyneulink.core.components.functions.fitfunctions import make_likelihood_function from psyneulink.core.components.functions.function import is_function_type from psyneulink.core.components.functions.nonstateful.combinationfunctions import LinearCombination, \ PredictionErrorDeltaFunction @@ -2570,8 +2730,7 @@ def input_function(env, result): from psyneulink.core.components.functions.nonstateful.transferfunctions import Identity from psyneulink.core.components.mechanisms.mechanism import Mechanism_Base, MechanismError, MechanismList from psyneulink.core.components.mechanisms.modulatory.control.controlmechanism import ControlMechanism -from psyneulink.core.components.mechanisms.modulatory.control.optimizationcontrolmechanism import AGENT_REP, \ - RANDOMIZATION_CONTROL_SIGNAL +from psyneulink.core.components.mechanisms.modulatory.control.optimizationcontrolmechanism import AGENT_REP, OptimizationControlMechanism from psyneulink.core.components.mechanisms.modulatory.learning.learningmechanism import \ LearningMechanism, ACTIVATION_INPUT_INDEX, ACTIVATION_OUTPUT_INDEX, ERROR_SIGNAL, ERROR_SIGNAL_INDEX from psyneulink.core.components.mechanisms.modulatory.modulatorymechanism import ModulatoryMechanism_Base @@ -2582,7 +2741,7 @@ def input_function(env, result): from psyneulink.core.components.ports.modulatorysignals.controlsignal import ControlSignal from psyneulink.core.components.ports.outputport import OutputPort from psyneulink.core.components.ports.parameterport import ParameterPort -from psyneulink.core.components.ports.port import Port +from psyneulink.core.components.ports.port import Port, PortError from psyneulink.core.components.projections.modulatory.controlprojection import ControlProjection from psyneulink.core.components.projections.modulatory.learningprojection import LearningProjection from psyneulink.core.components.projections.modulatory.modulatoryprojection import ModulatoryProjection_Base @@ -2598,23 +2757,23 @@ def input_function(env, result): from psyneulink.core.globals.context import Context, ContextFlags, handle_external_context from psyneulink.core.globals.keywords import \ AFTER, ALL, ALLOW_PROBES, ANY, BEFORE, COMPONENT, COMPOSITION, CONTROL, CONTROL_SIGNAL, CONTROLLER, DEFAULT, \ - FEEDBACK, FUNCTION, HARD_CLAMP, IDENTITY_MATRIX, INPUT, INPUT_PORTS, INPUTS, INPUT_CIM_NAME, \ + DICT, FEEDBACK, FULL, FUNCTION, HARD_CLAMP, IDENTITY_MATRIX, INPUT, INPUT_PORTS, INPUTS, INPUT_CIM_NAME, \ LEARNED_PROJECTIONS, LEARNING_FUNCTION, LEARNING_MECHANISM, LEARNING_MECHANISMS, LEARNING_PATHWAY, \ MATRIX, MATRIX_KEYWORD_VALUES, MAYBE, \ - MODEL_SPEC_ID_COMPOSITION, MODEL_SPEC_ID_NODES, MODEL_SPEC_ID_PROJECTIONS, MODEL_SPEC_ID_PSYNEULINK, \ - MODEL_SPEC_ID_RECEIVER_MECH, MODEL_SPEC_ID_SENDER_MECH, \ - MONITOR, MONITOR_FOR_CONTROL, NAME, NESTED, NO_CLAMP, OBJECTIVE_MECHANISM, ONLINE, OUTCOME, \ + MODEL_SPEC_ID_METADATA, \ + MONITOR, MONITOR_FOR_CONTROL, NAME, NESTED, NO_CLAMP, NODE, OBJECTIVE_MECHANISM, ONLINE, OUTCOME, \ OUTPUT, OUTPUT_CIM_NAME, OUTPUT_MECHANISM, OUTPUT_PORTS, OWNER_VALUE, \ - PARAMETER, PARAMETER_CIM_NAME, PROCESSING_PATHWAY, PROJECTION, PROJECTION_TYPE, PROJECTION_PARAMS, PULSE_CLAMP, \ + PARAMETER, PARAMETER_CIM_NAME, PORT, \ + PROCESSING_PATHWAY, PROJECTION, PROJECTION_TYPE, PROJECTION_PARAMS, PULSE_CLAMP, \ SAMPLE, SHADOW_INPUTS, SOFT_CLAMP, SSE, \ - TARGET, TARGET_MECHANISM, VARIABLE, WEIGHT, OWNER_MECH + TARGET, TARGET_MECHANISM, TEXT, VARIABLE, WEIGHT, OWNER_MECH from psyneulink.core.globals.log import CompositionLog, LogCondition from psyneulink.core.globals.parameters import Parameter, ParametersBase from psyneulink.core.globals.preferences.basepreferenceset import BasePreferenceSet from psyneulink.core.globals.preferences.preferenceset import PreferenceLevel, _assign_prefs from psyneulink.core.globals.registry import register_category from psyneulink.core.globals.utilities import \ - ContentAddressableList, call_with_pruned_args, convert_to_list, convert_to_np_array, is_numeric + ContentAddressableList, call_with_pruned_args, convert_to_list, nesting_depth, convert_to_np_array, is_numeric, parse_valid_identifier from psyneulink.core.scheduling.condition import All, AllHaveRun, Always, Any, Condition, Never from psyneulink.core.scheduling.scheduler import Scheduler, SchedulingMode from psyneulink.core.scheduling.time import Time, TimeScale @@ -2750,7 +2909,7 @@ class Graph(object): maps `Component` in the graph to the `Vertices ` that represent them. vertices : List[Vertex] - the `Vertices ` contained in this Graph; each can be a `Node ` or a + the `Vertices ` contained in this Graph; each can be a `Node ` or a `Projection `. dependency_dict : Dict[`Component` : Set(`Component`)] @@ -3031,8 +3190,9 @@ class NodeRole(enum.Enum): programmatically. INTERNAL - A `Node ` that is neither `ORIGIN` nor `TERMINAL`. This role cannot be modified - programmatically. + A `Node ` that is neither `INPUT` nor `OUTPUT`. Note that it *can* also be `ORIGIN`, + `TERMINAL` or `SINGLETON`, if it has no `afferent ` or `efferent + ` Projections or neither, respectively. This role cannot be modified programmatically. CYCLE A `Node ` that belongs to a cycle. This role cannot be modified programmatically. @@ -3212,7 +3372,7 @@ class Composition(Composition_Base, metaclass=ComponentsMeta): ` for additional details). show_graph_attributes : dict : None - specifies features of how the Composition is displayed when its `show_graph ` + specifies features of how the Composition is displayed when its `show_graph ` method is called or **animate** is specified in a call to its `run ` method (see `ShowGraph` for list of attributes and their values). @@ -3349,12 +3509,32 @@ class Composition(Composition_Base, metaclass=ComponentsMeta): `, then from any `Nodes ` in the outer composition that project to the nested Composition (either itself, as a Node in the outer Composition, or to any of its own Nodes). + external_input_ports_of_all_input_nodes : list[InputPort] + a list of all `external InputPort ` of all `INPUT ` + `Nodes ` of the Composition, including any that in `nested Compositions + ` within it (i.e., within `INPUT ` Nodes at all levels of nesting). + Note that the InputPorts listed are those of the actual Mechanisms projected to by the ones listed + in `external_input_ports `. + + external_input_shape : list[1d array] + a list of the `input_shape `\\s of all of the InputPorts listed in + `external_input_ports ` (and are the same as the shapes of those listed in + `external_input_ports_of_all_input_nodes `); any input + to the Composition must be compatible with these, whether received from the **inputs** argument of one of the + Composition's `execution methods ` or, if it is a `nested Composition + `, from the enclosing Composition. + + external_input_variables : list[2d array] + a list of the `variable `\\s associated with the `InputPorts ` listed in + `external_input_ports `. + + external_input_values : list[1d array] + a list of the values of associated of the `InputPorts ` listed in `external_input_ports + `. + external_input_values : list[InputPort] a list of the values of associated with the `InputPorts ` listed in `external_input_ports - `; any input to the Composition must be compatible with the shape of this, - whether received from the **input_ports** argument of oneo f the Composition's`execution methods - ` or, if it is a `nested Composition `, from the outer - Composition. + `. output_CIM : `CompositionInterfaceMechanism` aggregates output values from the OUTPUT nodes of the Composition. If the Composition is nested, then the @@ -3524,7 +3704,7 @@ class Parameters(ParametersBase): """ results = Parameter([], loggable=False, pnl_internal=True) simulation_results = Parameter([], loggable=False, pnl_internal=True) - retain_old_simulation_data = Parameter(False, stateful=False, loggable=False) + retain_old_simulation_data = Parameter(False, stateful=False, loggable=False, pnl_internal=True) input_specification = Parameter(None, stateful=False, loggable=False, pnl_internal=True) @@ -3559,7 +3739,7 @@ def __init__( name=name, ) - # core attribute + # core attributes self.graph = Graph() # Graph of the Composition self._graph_processing = None self.nodes = ContentAddressableList(component_type=Component) @@ -3606,6 +3786,8 @@ def __init__( self.needs_update_graph_processing = True # Tracks if the processing graph is current with the full graph self.needs_update_scheduler = True # Tracks if the scheduler needs to be regenerated self.needs_update_controller = True # Tracks if controller needs to update its state_input_ports + self.needs_determine_node_roles = False # Set in add_node and add_projection to insure update of NodeRoles + self._need_check_for_unused_projections = True self.nodes_to_roles = collections.OrderedDict() self.cycle_vertices = set() @@ -3649,10 +3831,9 @@ def __init__( # Controller self.controller = None self._controller_initialization_status = ContextFlags.INITIALIZED + self.enable_controller = enable_controller if controller: self.add_controller(controller) - else: - self.enable_controller = enable_controller self.controller_mode = controller_mode self.controller_time_scale = controller_time_scale self.controller_condition = controller_condition @@ -3699,11 +3880,12 @@ def scheduler(self): """ if self.needs_update_scheduler or not isinstance(self._scheduler, Scheduler): old_scheduler = self._scheduler - self._scheduler = Scheduler(composition=self) - if old_scheduler is not None: - self._scheduler.add_condition_set(old_scheduler.conditions) + orig_conds = old_scheduler._user_specified_conds + else: + orig_conds = None + self._scheduler = Scheduler(composition=self, conditions=orig_conds) self.needs_update_scheduler = False return self._scheduler @@ -3772,8 +3954,9 @@ def _analyze_graph(self, context=None): self._create_CIM_ports(context=context) # Call after above so shadow_projections have relevant organization self._update_shadow_projections(context=context) - # Call again to accomodate any changes from _update_shadow_projections - self._determine_node_roles(context=context) + # # FIX: 12/29/21 / 3/30/22: MOVE TO _update_shadow_projections + # # Call again to accommodate any changes from _update_shadow_projections + # self._determine_node_roles(context=context) self._check_for_projection_assignments(context=context) self.needs_update_graph = False @@ -3831,11 +4014,16 @@ def add_node(self, node, required_roles=None, context=None): pathway_arg_str = " in " + context.string raise CompositionError(f"Attempt to add Composition as a Node to itself{pathway_arg_str}.") + required_roles = convert_to_list(required_roles) + if isinstance(node, Composition): # IMPLEMENTATION NOTE: include_probes_in_output=False is not currently supported for nested Nodes # (they require get_output_value() to return value of all output_ports of output_CIM) node.include_probes_in_output = True - + else: + if required_roles and NodeRole.INTERNAL in required_roles: + for input_port in node.input_ports: + input_port.internal_only = True try: node._analyze_graph(context = context) except AttributeError: @@ -3880,6 +4068,16 @@ def add_node(self, node, required_roles=None, context=None): if isinstance(node, ControlMechanism): self._handle_allow_probes_for_control(node) + self._need_check_for_unused_projections = True + + # # MODIFIED 1/27/22 NEW - FIX - BREAKS test_learning_output_shape() in ExecuteMode.LLVM + # [3/25/22] STILL NEEDED (e.g., FOR test_inputs_key_errors() + # if context.source != ContextFlags.METHOD: + # # Call _analyze_graph with ContextFlags.METHOD to avoid recursion + # self._analyze_graph(context=Context(source=ContextFlags.METHOD)) + # MODIFIED 1/27/22 END + self.needs_determine_node_roles = True + def add_nodes(self, nodes, required_roles=None, context=None): """ Add a list of `Nodes ` to the Composition. @@ -3914,37 +4112,67 @@ def add_nodes(self, nodes, required_roles=None, context=None): f"({node}) must be a {Mechanism.__name__}, {Composition.__name__}, " f"or a tuple containing one of those and a {NodeRole.__name__} or list of them") + def remove_node(self, node): + self._remove_node(node) + + def _remove_node(self, node, analyze_graph=True): + for proj in node.afferents + node.efferents: + self.remove_projection(proj) + + for param_port in node.parameter_ports: + for proj in param_port.mod_afferents: + self.remove_projection(proj) + + # deactivate any shadowed projections + for shadow_target, shadow_port_original in self.shadowing_dict.items(): + if shadow_port_original in node.input_ports: + for shadow_proj in shadow_target.all_afferents: + if shadow_proj.sender.owner.composition is self: + self.remove_projection(shadow_proj) + + # NOTE: deactivation should be sufficient but + # asserts in OCM _update_state_input_port_names + # need target input ports of shadowed + # projections to be active or not present at all + try: + self.controller.state_input_ports.remove(shadow_target) + except AttributeError: + pass + + self.graph.remove_component(node) + del self.nodes_to_roles[node] + + # Remove any entries for node in required_node_roles or excluded_node_roles + node_role_pairs = [item for item in self.required_node_roles if item[0] is node] + for item in node_role_pairs: + self.required_node_roles.remove(item) + node_role_pairs = [item for item in self.excluded_node_roles if item[0] is node] + for item in node_role_pairs: + self.excluded_node_roles.remove(item) + + del self.nodes[node] + self.node_ordering.remove(node) + + for p in self.pathways: + try: + p.pathway.remove(node) + except ValueError: + pass + + self.needs_update_graph_processing = True + self.needs_update_scheduler = True + + if analyze_graph: + self._analyze_graph() + def remove_nodes(self, nodes): if not isinstance(nodes, (list, Mechanism, Composition)): assert False, 'Argument of remove_nodes must be a Mechanism, Composition or list containing either or both' nodes = convert_to_list(nodes) for node in nodes: - for proj in node.afferents + node.efferents: - try: - del self.projections[proj] - except ValueError: - # why are these not present? - pass - - try: - self.graph.remove_component(proj) - except CompositionError: - # why are these not present? - pass - - self.graph.remove_component(node) - del self.nodes_to_roles[node] + self._remove_node(node, analyze_graph=False) - # Remove any entries for node in required_node_roles or excluded_node_roles - node_role_pairs = [item for item in self.required_node_roles if item[0] is node] - for item in node_role_pairs: - self.required_node_roles.remove(item) - node_role_pairs = [item for item in self.excluded_node_roles if item[0] is node] - for item in node_role_pairs: - self.excluded_node_roles.remove(item) - - del self.nodes[node] - self.node_ordering.remove(node) + self._analyze_graph() @handle_external_context() def _add_required_node_role(self, node, role, context=None): @@ -4141,6 +4369,87 @@ def _get_input_nodes_by_CIM_input_order(self): return [{cim[0]:n for n, cim in self.input_CIM_ports.items()}[input_port].owner for input_port in self.input_CIM.input_ports] + def _get_input_receivers(self, + comp=None, + type:Union[PORT,NODE]=PORT, + comp_as_node:Union[bool,ALL]=False): + """Return all INPUT Nodes [or their InputPorts] of comp, [including those for any nested Compositions]. + If type is PORT, return all InputPorts for all INPUT Nodes, including for nested Compositions. + If type is NODE, return all INPUT Nodes, including for nested Compositions as determined by comp_as_node: + if an INPUT Node is a Composition, and comp_as_node is: + - False, include the nested Composition's INPUT Nodes, but not the Composition + - True, include the nested Composition but not its INPUT Nodes + - ALL, include the nested Composition AND its INPUT Nodes + """ + + # FIX: 3/16/22 - CAN THIS BE REPLACED BY: + # return [self._get_destination(output_port.efferents[0])[0] + # for _,output_port in self.input_CIM.port_map.values()] + + assert not (type == PORT and comp_as_node), f"PROGRAM ERROR: _get_input_receivers() can't be called " \ + f"for 'ports' and 'nodes' at the same time." + comp = comp or self + input_items = [] + _update_cim = False + + if comp.needs_determine_node_roles: + comp._determine_node_roles() + _update_cim = True + + if type==PORT: + # Return all InputPorts of all INPUT Nodes + _input_nodes = comp._get_nested_nodes_with_same_roles_at_all_levels(comp=comp, + include_roles=NodeRole.INPUT) + if _input_nodes: + for node in _input_nodes: + # Exclude internal_only and shadowers of input (since the latter get inputs for the shadowed item) + input_items.extend([input_port for input_port in node.input_ports + if not (input_port.internal_only or input_port.shadow_inputs)]) + # Ensure correct number of InputPorts have been identified + # (i.e., number of InputPorts on comp's input_CIM) + if _update_cim: + context = Context() + self._determine_pathway_roles(context=context) + self._determine_pathway_roles(context) + self._create_CIM_ports(context) + _update_cim = False + assert len(input_items) == len(comp.input_CIM_ports) + else: + # Return all INPUT Nodes + _input_nodes = comp.get_nodes_by_role(NodeRole.INPUT) + for node in _input_nodes: + if isinstance(node, Composition): + if comp_as_node: + input_items.append(node) + if comp_as_node in {False, ALL}: + input_items.extend(self._get_input_receivers(comp=node, type=type, comp_as_node=comp_as_node)) + else: + input_items.append(node) + + return input_items + + def _get_external_cim_input_port(self, port:InputPort, outer_comp=None): + """Get input_CIM.input_port of outer(most) Composition that projects to port in nested Composition. + **port** must be an InputPort that receives a single path_afferent Projection from an input_CIM. + Search up nesting hierarchy to find the input_CIM of comp nested in outer_comp or of the outermost Composition. + Return tuple with: + input_CIM.input_port of the input_CIM of comp nested in outer_comp or of the outermost Composition + input_CIM.output_port corresponding to input_CIM.input_port (for ease of tracking Node to which it projects) + """ + assert len(port.path_afferents) == 1, \ + f"PROGRAM ERROR: _get_external_cim_input_ports called for {port} " \ + f"that has either no or more than one path_afferent projections." + input_CIM = port.path_afferents[0].sender.owner + assert isinstance(input_CIM, CompositionInterfaceMechanism), \ + f"PROGRAM ERROR: _get_external_cim_input_ports called for {port} that is not an INPUT Node " \ + f"(i.e., does not receive a path_afferent projection from an input_CIM of its enclosing Composition." + input_CIM_input_port = input_CIM.port_map[port][0] + if (outer_comp and input_CIM.composition in outer_comp.nodes) or not input_CIM_input_port.path_afferents: + # input_CIM_input_port belongs to outermost Composition, so return + return input_CIM.port_map[port] + # input_CIM_input_port belongs to a nested Composition, so continue to search up the nesting hierarchy + return self._get_external_cim_input_port(input_CIM_input_port, outer_comp) + def _get_nested_nodes(self, nested_nodes=NotImplemented, root_composition=NotImplemented, @@ -4182,7 +4491,7 @@ def _handle_allow_probes_for_control(self, node): def _get_nested_compositions(self, nested_compositions=NotImplemented, visited_compositions=NotImplemented): - """Recursive search for and return all nested compositions. + """Recursively search for and return all nested compositions. :return @@ -4208,6 +4517,18 @@ def _get_all_nodes(self): """ return [k[0] for k in self._get_nested_nodes()] + list(self.nodes) + def _is_in_composition(self, component, nested=True): + """Return True if component is in Composition, including any nested Compositions if **nested** is True + Include input_CIM and output_CIM for self and all nested Compositions + """ + if isinstance(component, Port): + component = component.owner + + if component in self._all_nodes: + return True + if nested: + return any(component in comp._all_nodes for comp in self._get_nested_compositions()) + def _determine_origin_and_terminal_nodes_from_consideration_queue(self): """Assigns NodeRole.ORIGIN to all nodes in the first entry of the consideration queue and NodeRole.TERMINAL to all nodes in the last entry of the consideration queue. The ObjectiveMechanism of a Composition's @@ -4309,8 +4630,8 @@ def _add_node_aux_components(self, node, context=None): sender_node = proj_spec[0].sender.owner.owner_mech if isinstance(receiver_node, AutoAssociativeProjection): receiver_node = proj_spec[0].receiver.owner.owner_mech - if sender_node in self.nodes and \ - receiver_node in self.nodes: + if sender_node in self._all_nodes and \ + receiver_node in self._all_nodes: self.add_projection(projection=proj_spec[0], feedback=proj_spec[1]) else: @@ -4319,6 +4640,12 @@ def _add_node_aux_components(self, node, context=None): feedback=proj_spec[1]) del node.aux_components[node.aux_components.index(proj_spec)] + # MODIFIED 12/29/21 NEW: + # # Finally, check for any deferred_init Projections + invalid_aux_components.extend([p for p in node.projections + if p._initialization_status & ContextFlags.DEFERRED_INIT]) + # MODIFIED 12/29/21 END + return invalid_aux_components def _get_invalid_aux_components(self, node): @@ -4396,19 +4723,15 @@ def _complete_init_of_partially_initialized_nodes(self, context=None): completed_nodes.append(node) self._partially_added_nodes = list(set(self._partially_added_nodes) - set(completed_nodes)) - # Don't instantiate unless flagged for updating (if nodes have been added to the graph); - # this avoids unnecessary calls on repeated calls to run(). - if (self.controller - and self.needs_update_controller - and context.flags & (ContextFlags.COMPOSITION | ContextFlags.COMMAND_LINE)): - if hasattr(self.controller, 'state_input_ports'): + if self.controller: + # Avoid unnecessary updating on repeated calls to run() + if self.needs_update_controller and hasattr(self.controller, 'state_input_ports'): self.controller._update_state_input_ports_for_controller(context=context) - # self._instantiate_controller_shadow_projections(context=context) - self.controller._validate_monitor_for_control(self._get_all_nodes()) - self._instantiate_control_projections(context=context) - # FIX: 11/15/21 - CAN'T SET TO FALSE HERE, AS THIS IS CALLED BY _analyze_graph() FROM add_node() - # BEFORE PROJECTIONS TO THE NODE HAS BEEN ADDED (AFTER CALL TO add_node()) - self.needs_update_controller = False + + # Make sure all is in order at run time + if context.flags & ContextFlags.PREPARING: + self.controller._validate_monitor_for_control(self._get_all_nodes()) + self._instantiate_control_projections(context=context) def _determine_node_roles(self, context=None): """Assign NodeRoles to Nodes in Composition @@ -4531,6 +4854,9 @@ def _determine_node_roles(self, context=None): # INPUT for node in self.get_nodes_by_role(NodeRole.ORIGIN): + # Don't allow INTERNAL Nodes to be INPUTS + if NodeRole.INTERNAL in self.get_roles_by_node(node): + continue self._add_node_role(node, NodeRole.INPUT) # CYCLE @@ -4650,6 +4976,8 @@ def _determine_node_roles(self, context=None): if self.controller is not None: self.nodes_to_roles[self.controller] = {NodeRole.CONTROLLER} + self.needs_determine_node_roles = False + def _set_node_roles(self, node, roles): self._clear_node_roles(node) for role in roles: @@ -4781,17 +5109,17 @@ def _create_CIM_ports(self, context=None): input_nodes = self.get_nodes_by_role(NodeRole.INPUT) for node in input_nodes: - # loop through all external input ports on input nodes (i.e. ports that are projected to from other nodes) + # loop through all external InputPorts on INPUT Nodes (i.e. Ports that are Projected to from other Nodes) for input_port in node.external_input_ports: - # add it to set of current input ports + # add it to set of current InputPorts current_input_node_input_ports.add(input_port) # if there is not a corresponding CIM InputPort/OutputPort pair, add them if input_port not in set(self.input_CIM_ports.keys()): - # instantiate the input port on the input CIM to correspond to the node's input port + # instantiate the InputPort on the input CIM to correspond to the Node's InputPort interface_input_port = InputPort(owner=self.input_CIM, - variable=input_port.defaults.value, + variable=np.atleast_2d(input_port.defaults.variable)[0], reference_value=input_port.defaults.value, name= INPUT_CIM_NAME + "_" + node.name + "_" + input_port.name, context=context) @@ -4799,36 +5127,36 @@ def _create_CIM_ports(self, context=None): if NodeRole.TARGET in self.get_roles_by_node(node): interface_input_port.parameters.require_projection_in_composition.set(False, override=True) - # add port to the input CIM + # add Port to the input CIM self.input_CIM.add_ports([interface_input_port], context=context) - # instantiate the output port on the input CIM to correspond to the node's input port + # instantiate the OutputPort on the input CIM to correspond to the Node's InputPort interface_output_port = OutputPort(owner=self.input_CIM, variable=(OWNER_VALUE, functools.partial(self.input_CIM.get_input_port_position, interface_input_port)), function=Identity, name=INPUT_CIM_NAME + "_" + node.name + "_" + input_port.name, context=context) - # add port to the input CIM + # add Port to the input CIM self.input_CIM.add_ports([interface_output_port], context=context) - # add entry to input_CIM_ports dict, so that we can retrieve the CIM ports that correspond to a given - # input node's input port + # add entry to input_CIM_ports dict, so that the CIM ports that correspond to a given + # input node's InputPort can be retrieved self.input_CIM_ports[input_port] = (interface_input_port, interface_output_port) - # create projection from the output port on the input CIM to the input port on the input node + # create Projection from the output port on the input CIM to the input port on the input node projection = MappingProjection(sender=interface_output_port, receiver=input_port, matrix=IDENTITY_MATRIX, name="(" + interface_output_port.name + ") to (" + input_port.owner.name + "-" + input_port.name + ")") - # activate the projection + # activate the Projection projection._activate_for_compositions(self) - # if the node is a nested Composition, activate the projection for the nested Composition as well + # if the node is a nested Composition, activate the Projection for the nested Composition as well if isinstance(node, Composition): projection._activate_for_compositions(node) @@ -4871,7 +5199,7 @@ def _create_CIM_ports(self, context=None): self.output_CIM.add_ports([interface_input_port], context=context) - # instantiate the output port on the output CIM to correspond to the node's output port + # instantiate the OutputPort on the output CIM to correspond to the node's OutputPort interface_output_port = OutputPort( owner=self.output_CIM, variable=(OWNER_VALUE, functools.partial(self.output_CIM.get_input_port_position, @@ -4885,13 +5213,13 @@ def _create_CIM_ports(self, context=None): self.output_CIM.add_ports([interface_output_port], context=context) - # add entry to output_CIM_ports dict, so that we can retrieve the CIM ports that correspond to a given - # output node's output port + # add entry to output_CIM_ports dict, so that CIM ports that correspond to a given + # output node's OutputPort can be retrieved self.output_CIM_ports[output_port] = (interface_input_port, interface_output_port) proj_name = "(" + output_port.name + ") to (" + interface_input_port.name + ")" - # create projection from the output port of the output node to input port on the output CIM + # create Projection from the OutputPort of the output Node to InputPort on the output CIM proj = MappingProjection( sender=output_port, receiver=interface_input_port, @@ -4904,7 +5232,7 @@ def _create_CIM_ports(self, context=None): # activate the projection proj._activate_for_compositions(self) - # if the node is a nested Composition, activate the projection for the nested Composition as well + # if the Node is a nested Composition, activate the Projection for the nested Composition as well if isinstance(node, Composition): proj._activate_for_compositions(node) @@ -4939,6 +5267,7 @@ def _create_CIM_ports(self, context=None): variable=receiver.defaults.value, reference_value=receiver.defaults.value, name= PARAMETER_CIM_NAME + "_" + owner.name + "_" + receiver.name, + # default_input=DEFAULT_VARIABLE, context=context) self.parameter_CIM.add_ports([interface_input_port], context=context) # control signal for parameter CIM that will project directly to inner Composition's parameter @@ -5013,6 +5342,7 @@ def _create_CIM_ports(self, context=None): if x in cim_prt_tpl), len(self.nodes))) + # KDM 4/3/20: should reevluate this some time - is it # acceptable to consider _update_default_variable as # happening outside of this normal context? This is here as @@ -5023,9 +5353,10 @@ def _create_CIM_ports(self, context=None): # otherwise, CIM ports will not be initialized properly orig_eid = context.execution_id context.execution_id = None + context_string = context.string new_default_variable = [ - deepcopy(input_port.defaults.value) + deepcopy(input_port.default_input_shape) for input_port in cim.input_ports ] @@ -5039,6 +5370,7 @@ def _create_CIM_ports(self, context=None): # no input ports in CIM, so assume Composition is blank context.execution_id = orig_eid + context.string = context_string # verify there is exactly one automatically instantiated input port for each automatically instantiated # output port @@ -5108,7 +5440,10 @@ def try_assigning_as_probe(node, role, comp): # Check if Node is an INPUT or INTERNAL if any(role for role in comp.nodes_to_roles[node] if role in {NodeRole.INPUT, NodeRole.INTERNAL}): comp._add_required_node_role(node, NodeRole.PROBE) - self._analyze_graph() + # Ignore warning since a Projection to the PROBE will not yet have been instantiated + # self._analyze_graph(context=Context(string='IGNORE_NO_AFFERENTS_WARNING')) + self._analyze_graph(context=Context(source=ContextFlags.COMPOSITION, + string='IGNORE_NO_AFFERENTS_WARNING')) return # Failed to assign node as PROBE, so get ControlMechanisms that may be trying to monitor it @@ -5328,26 +5663,17 @@ def add_projection(self, else: receiver_check = receiver # If either the sender or receiver are not in Composition and are not CompositionInterfaceMechanisms - # remove the Projection and inclusion in relevant Ports + # remove the Projection and its inclusion in any relevant Port attributes if ((not isinstance(sender_check, CompositionInterfaceMechanism) and sender_check not in self.nodes) or (not isinstance(receiver_check, CompositionInterfaceMechanism) and receiver_check not in self.nodes)): for proj in existing_projections: self.remove_projection(proj) - for port in receiver_check.input_ports + sender_check.output_ports: - if proj in port.afferents_info: - del port.afferents_info[proj] - if proj in port.projections: - port.projections.remove(proj) - if proj in port.path_afferents: - port.path_afferents.remove(proj) - if proj in port.mod_afferents: - port.mod_afferents.remove(proj) - if proj in port.efferents: - port.efferents.remove(proj) + for port in sender_check.output_ports + receiver_check.input_ports: + port.remove_projection(proj, context=context) else: - # Need to do stuff at end, so can't just return + # Need to do stuff at end, so can't just return if self.prefs.verbosePref: warnings.warn(f"Several existing projections were identified between " f"{sender.name} and {receiver.name}: {[p.name for p in existing_projections]}; " @@ -5489,6 +5815,7 @@ def add_projection(self, # self.feedback_senders.add(sender_mechanism) # self.feedback_receivers.add(receiver_mechanism) + self.needs_determine_node_roles = True return projection def _add_projection(self, projection): @@ -5503,7 +5830,32 @@ def remove_projection(self, projection): if projection in self.projections: self.projections.remove(projection) - # step 3 - TBI? remove Projection from afferents & efferents lists of any node + # step 3 - deactivate Projection in this Composition + projection._deactivate_for_compositions(self) + + # step 4 - deactivate any learning to this Projection + for param_port in projection.parameter_ports: + for proj in param_port.mod_afferents: + self.remove_projection(proj) + if isinstance(proj.sender.owner, LearningMechanism): + for path in self.pathways: + # TODO: make learning_components values consistent type + try: + learning_mechs = path.learning_components['LEARNING_MECHANISMS'] + except KeyError: + continue + + if isinstance(learning_mechs, LearningMechanism): + learning_mechs = [learning_mechs] + + if proj.sender.owner in learning_mechs: + for mech in learning_mechs: + self.remove_node(mech) + self.remove_node(path.learning_components['objective_mechanism']) + self.remove_node(path.learning_components['TARGET_MECHANISM']) + + # step 5 - TBI? remove Projection from afferents & efferents lists of any node + def _validate_projection(self, projection, @@ -5513,15 +5865,15 @@ def _validate_projection(self, learning_projection, ): - # FIX: [JDC 6/8/19] SHOULDN'T THERE BE A CHECK FOR THEM LearningProjections? OR ARE THOSE DONE ELSEWHERE? + # FIX: [JDC 6/8/19] SHOULDN'T THERE BE A CHECK FOR THEM IN LearningProjections? OR ARE THOSE DONE ELSEWHERE? # Skip this validation on learning projections because they have non-standard senders and receivers if not learning_projection: if projection.sender.owner != graph_sender: - raise CompositionError("{}'s sender assignment [{}] is incompatible with the positions of these " - "Components in the Composition.".format(projection, sender)) + raise CompositionError(f"Sender ('{sender.name}') assigned to '{projection.name} is " + f"incompatible with the positions of these Components in '{self.name}'.") if projection.receiver.owner != graph_receiver: - raise CompositionError("{}'s receiver assignment [{}] is incompatible with the positions of these " - "Components in the Composition.".format(projection, receiver)) + raise CompositionError(f"Receiver ('{receiver.name}') assigned to '{projection.name} is " + f"incompatible with the positions of these Components in '{self.name}'.") def _instantiate_projection_from_spec(self, projection, sender=None, receiver=None, name=None): if isinstance(projection, dict): @@ -5746,6 +6098,7 @@ def _get_sender_at_right_level(shadowed_proj): if correct_sender: original_senders.add(correct_sender) shadow_found = False + # Look for existing shadow_projections from correct_sender to shadowing input_port for shadow_projection in input_port.path_afferents: if shadow_projection.sender == correct_sender: shadow_found = True @@ -5755,28 +6108,38 @@ def _get_sender_at_right_level(shadowed_proj): new_projection = MappingProjection(sender=correct_sender, receiver=input_port) self.add_projection(new_projection, sender=correct_sender, receiver=input_port) + else: + raise CompositionError(f"Unable to find port specified to be shadowed by '{input_port.owner.name}' " + f"({shadowed_projection.receiver.owner.name}" + f"[{shadowed_projection.receiver.name}]) within the same Composition " + f"('{self.name}'), nor in any nested within it. " + f"'{shadowed_projection.receiver.owner.name}' may be in another " + f"Composition at the same level within '{self.name}' or in an outer " + f"Composition, neither of which are supported by shadowing.") return original_senders - for shadowing_port, shadowed_port in self.shadowing_dict.items(): - senders = _instantiate_missing_shadow_projections(shadowing_port, - shadowed_port.path_afferents) - for shadow_projection in shadowing_port.path_afferents: - if shadow_projection.sender not in senders: - self.remove_projection(shadow_projection) - Projection_Base._delete_projection(shadow_projection) - if not shadow_projection.sender.efferents: - if isinstance(shadow_projection.sender.owner, CompositionInterfaceMechanism): - ports = shadow_projection.sender.owner.port_map.pop(shadow_projection.receiver) - shadow_projection.sender.owner.remove_ports(list(ports)) - else: - shadow_projection.sender.owner.remove_ports(shadow_projection.sender) + if self.shadowing_dict.items: + for shadowing_port, shadowed_port in self.shadowing_dict.items(): + senders = _instantiate_missing_shadow_projections(shadowing_port, + shadowed_port.path_afferents) + for shadow_projection in shadowing_port.path_afferents: + if shadow_projection.sender not in senders: + self.remove_projection(shadow_projection) + Projection_Base._delete_projection(shadow_projection) + if not shadow_projection.sender.efferents: + if isinstance(shadow_projection.sender.owner, CompositionInterfaceMechanism): + ports = shadow_projection.sender.owner.port_map.pop(shadow_projection.receiver) + shadow_projection.sender.owner.remove_ports(list(ports)) + else: + shadow_projection.sender.owner.remove_ports(shadow_projection.sender) + self._determine_node_roles(context=context) def _check_for_projection_assignments(self, context=None): """Check that all Projections and Ports with require_projection_in_composition attribute are configured. - Validate that all InputPorts with require_projection_in_composition == True have an afferent Projection. - Validate that all OuputStates with require_projection_in_composition == True have an efferent Projection. + Validate that all OutputPorts with require_projection_in_composition == True have an efferent Projection. Validate that all Projections have senders and receivers. + Issue warning if any Projections are to/from nodes not in Composition.projections """ projections = self.projections.copy() @@ -5785,9 +6148,10 @@ def _check_for_projection_assignments(self, context=None): projections.append(node) continue - if context.source != ContextFlags.INITIALIZING: + if context.source != ContextFlags.INITIALIZING and context.string != 'IGNORE_NO_AFFERENTS_WARNING': for input_port in node.input_ports: - if input_port.require_projection_in_composition and not input_port.path_afferents: + if input_port.require_projection_in_composition \ + and not input_port.path_afferents and not input_port.default_input: warnings.warn(f"{InputPort.__name__} ('{input_port.name}') of '{node.name}' " f"doesn't have any afferent {Projection.__name__}s.") for output_port in node.output_ports: @@ -5801,6 +6165,29 @@ def _check_for_projection_assignments(self, context=None): if not projection.receiver: warnings.warn(f'{Projection.__name__} {projection.name} is missing a receiver.') + def _check_for_unused_projections(self, context): + """Warn if there are any Nodes in the Composition, or any nested within it, that are not used. + """ + unused_projections = [] + for node in self.nodes: + if isinstance(node, Composition): + node._check_for_unused_projections(context) + if isinstance(node, Mechanism): + for proj in [p for p in node.projections if p not in self.projections]: + proj_deferred = proj._initialization_status & ContextFlags.DEFERRED_INIT + proj_name = proj._name if proj_deferred else proj.name + if proj in node.afferents: + first_item = '' if proj_deferred else f" (to '{node.name}'" + second_item = '' if proj_deferred else f" from '{proj.sender.owner.name}')." + if proj in node.efferents: + first_item = '' if proj_deferred else f" (from '{node.name}'" + second_item = '' if proj_deferred else f" to '{proj.receiver.owner.name}')." + unused_projections.append(f"{proj_name}{first_item}{second_item}") + if unused_projections: + warning = f"\nThe following Projections were specified but are not being used by Nodes in '{self.name}':" + warnings.warn(warning + "\n\t" + "\n\t".join(unused_projections)) + self._need_check_for_unused_projections = False + def get_feedback_status(self, projection): """Return True if **projection** is designated as a `feedback Projection ` in the Composition, else False. @@ -5846,6 +6233,7 @@ def _check_for_existing_projections(self, err_msg = f"Can't create a {Projection.__name__} from '{sender.name}' to '{receiver.name}': " + err_msg raise CompositionError(err_msg) + # Check for existing Projections from specified sender existing_projections = [proj for proj in sender.efferents if proj.receiver is receiver] existing_projections_in_composition = [proj for proj in existing_projections if proj in self.projections] assert len(existing_projections_in_composition) <= 1, \ @@ -5898,20 +6286,51 @@ def _check_for_nesting_with_absolute_conditions(self, scheduler, termination_con if len(cond.absolute_fixed_points) > 0: fixed_point_conds.add(cond) - warn_str = f'{self} contains a nested Composition, which may cause unexpected behavior in absolute time conditions or failure to terminate execution.' + warn_str = f'{self} contains a nested Composition, which may cause unexpected behavior ' \ + f'in absolute time conditions or failure to terminate execution.' warn = False if len(interval_conds) > 0: warn_str += '\nFor repeating intervals:\n\t' - warn_str += '\n\t'.join([f'{cond.owner}: {cond}\n\t\tintervals: {cond.absolute_intervals}' for cond in interval_conds]) + warn_str += '\n\t'.join([f'{cond.owner}: {cond}\n\t\tintervals: {cond.absolute_intervals}' + for cond in interval_conds]) warn = True if len(fixed_point_conds) > 0: warn_str += '\nIn EXACT_TIME SchedulingMode, strict time points:\n\t' - warn_str += '\n\t'.join([f'{cond.owner}: {cond}\n\t\tstrict time points: {cond.absolute_fixed_points}' for cond in fixed_point_conds]) + warn_str += '\n\t'.join([f'{cond.owner}: {cond}\n\t\tstrict time points: {cond.absolute_fixed_points}' + for cond in fixed_point_conds]) warn = True if warn: warnings.warn(warn_str) + def _get_source(self, projection): + """Return tuple with port, node and comp of sender for **projection** (possibly in a nested Composition).""" + # Note: if Projection is shadowing the input to a Node, the information returned will be for + # the output_port of the input_CIM that projects to the shadowed Node. + port = projection.sender + if port.owner in self.nodes: + return (port, port.owner, self) + elif isinstance(port.owner, CompositionInterfaceMechanism): + return port.owner._get_source_info_from_output_CIM(port) + else: + # Get info for nested node + node, comp = next((item for item in self._get_nested_nodes() if item[0] is port.owner), (None, None)) + if node: + return(port, node, comp) + else: + raise CompositionError(f"No source found for {projection.name} in {self.name}.") + + def _get_destination(self, projection): + """Return tuple with port, node and comp of receiver for **projection** (possibly in a nested Composition).""" + port = projection.receiver + if isinstance(port.owner, CompositionInterfaceMechanism): + if isinstance(projection.sender.owner, ModulatoryMechanism_Base): + return port.owner._get_modulated_info_from_parameter_CIM(port) + else: + return port.owner._get_destination_info_from_input_CIM(port) + else: + return (port, port.owner, self) + # endregion PROJECTIONS # ****************************************************************************************************************** @@ -6136,10 +6555,10 @@ def add_linear_processing_pathway(self, pathway, name:str=None, context=None, *a receivers = receivers or convert_to_list(receiver) if len(senders) > 1 and len(receivers) > 1: raise CompositionError(f"Pathway specified with two contiguous Compositions, the first of " - f"which {sender.name} has more than one OUTPUT Node and second of" - f"which {receiver.name} has more than one INPUT Node, making the " - f"configuration of Projections between them ambigous. Please " - f"specify those Projections explicity.") + f"which ({sender.name}) has more than one OUTPUT Node, and second " + f"of which ({receiver.name}) has more than one INPUT Node, making " + f"the configuration of Projections between them ambiguous; please " + f"specify those Projections explicitly.") proj = {self.add_projection(sender=s, receiver=r, allow_duplicates=False) for r in receivers for s in senders} else: @@ -7341,7 +7760,7 @@ def _create_non_terminal_backprop_learning_components(self, receiver=learning_mechanism.error_signal_input_ports[i]) error_projections.append(error_projection) - self.add_node(learning_mechanism, required_roles=NodeRole.LEARNING) + self.add_node(learning_mechanism, required_roles=NodeRole.LEARNING, context=context) try: act_in_projection = MappingProjection(sender=input_source.output_ports[0], receiver=learning_mechanism.input_ports[0]) @@ -7501,7 +7920,7 @@ def _get_deeply_nested_aux_projections(self, node): aux_projections[i] = i nested_nodes = self._get_nested_nodes() for spec, proj in aux_projections.items(): - # FIX: TREATMENT OF RECEIVERS SEEMS TO DEAL WITH ONLY RECEIVERS IN COMPS NESTED MORE THAN ON LEVEL DEEP + # FIX: TREATMENT OF RECEIVERS SEEMS TO DEAL WITH ONLY RECEIVERS IN COMPS NESTED MORE THAN ONE LEVEL DEEP # REMOVING "if not i[1] in self.nodes" crashes in test_multilevel_control if ((proj.sender.owner not in self.nodes and proj.sender.owner in [i[0] for i in nested_nodes]) @@ -7563,17 +7982,16 @@ def add_controller(self, controller:ControlMechanism, context=None): return # Warn for request to assign ControlMechanism that is already the controller of another Composition - if hasattr(controller, COMPOSITION) and controller.composition is not self: - warnings.warn(f"{controller} has already been assigned as the {CONTROLLER} " - f"for another {COMPOSITION} ({controller.composition.name}); assignment ignored.") + if hasattr(controller, 'composition') and controller.composition is not self: + warnings.warn(f"'{controller.name}' has already been assigned as the {CONTROLLER} " + f"for '{controller.composition.name}'; assignment to '{self.name}' ignored.") return # Remove existing controller if there is one if self.controller: # Warn if current one is being replaced - if self.prefs.verbosePref: - warnings.warn(f"The existing {CONTROLLER} for {self.name} ({self.controller.name}) " - f"is being replaced by {controller.name}.") + warnings.warn(f"The existing {CONTROLLER} for '{self.name}' ('{self.controller.name}') " + f"is being replaced by '{controller.name}'.") # Remove Projections for old one for proj in self.projections.copy(): if (proj in self.controller.afferents or proj in self.controller.efferents): @@ -7584,6 +8002,17 @@ def add_controller(self, controller:ControlMechanism, context=None): # Assign mutual references between Composition and controller controller.composition = self self.controller = controller + + # # MODIFIED 12/30/21 NEW: FIX: THIS IS NOT CORRECT, BECAUSE WITH REGARD TO EXECUTION SEQUENCING, + # # CONTROLLER IS NOT THE CONTROLLER OF THE AGENT_REP, + # # IT JUST EXECUTES IT. + # # Deal with agent_rep of controller that is in a nested Composition + # if (hasattr(self.controller, AGENT_REP) + # and self.controller.agent_rep != self + # and self.controller.agent_rep in self._get_nested_compositions()): + # self.controller.agent_rep.controller = self.controller + # MODIFIED 12/30/21 END + # Having controller in nodes is not currently supported (due to special handling of scheduling/execution); # its NodeRole assignment is handled directly by the get_nodes_by_role and get_roles_by_node methods. # self._add_node_role(controller, NodeRole.CONTROLLER) @@ -7592,6 +8021,8 @@ def add_controller(self, controller:ControlMechanism, context=None): invalid_aux_components = self._get_invalid_aux_components(controller) if invalid_aux_components: self._controller_initialization_status = ContextFlags.DEFERRED_INIT + # Need update here so state_features remains up to date + self._analyze_graph(context=context) return # ADD MONITORING COMPONENTS ----------------------------------------------------- @@ -7612,15 +8043,12 @@ def add_controller(self, controller:ControlMechanism, context=None): # needs to be set here to insure call at run time (to catch any new nodes that may have been added) self.needs_update_controller = True - # Confirm that controller has input, and if not then disable it - if not (isinstance(self.controller.input_ports, ContentAddressableList) - and self.controller.input_ports): - # If controller was enabled, warn that it has been disabled - if self.enable_controller: - warnings.warn(f"{self.controller.name} for {self.name} has no input_ports, " - f"so controller will be disabled.") - self.enable_controller = False - return + # Warn if controller is enabled but has no inputs + if (self.enable_controller + and not (isinstance(self.controller.input_ports, ContentAddressableList) + and self.controller.input_ports + and self.controller.afferents)): + warnings.warn(f"{self.controller.name} for {self.name} is enabled but has no inputs.") # ADD MODULATORY COMPONENTS ----------------------------------------------------- @@ -7632,18 +8060,6 @@ def add_controller(self, controller:ControlMechanism, context=None): for node in self.nodes: self._instantiate_deferred_init_control(node, context) - if RANDOMIZATION_CONTROL_SIGNAL not in self.controller.output_ports.names: - try: - self.controller._create_randomization_control_signal(context) - except AttributeError: - # ControlMechanism does not use RANDOMIZATION_CONTROL_SIGNAL - pass - else: - self.controller.function.parameters.randomization_dimension._set( - self.controller.output_ports.names.index(RANDOMIZATION_CONTROL_SIGNAL), - context - ) - # ACTIVATE FOR COMPOSITION ----------------------------------------------------- self.node_ordering.append(controller) @@ -7727,6 +8143,21 @@ def _get_control_signals_for_composition(self): control_signal_specs.extend(node._get_parameter_port_deferred_init_control_specs()) return control_signal_specs + def _get_controller(self, comp=None, context=None): + """Get controller for which the current Composition is an agent_rep. + Recursively search enclosing Compositions for controller if self does not have one. + Use context.composition if there is no controller. + This is needed for agent_rep that is nested within the Composition to which the controller belongs. + """ + comp = comp or self + context = context or Context(source=ContextFlags.COMPOSITION, composition=None) + if comp.controller: + return comp.controller + elif context.composition: + return context.composition._get_controller(context=context) + else: + assert False, f"PROGRAM ERROR: Can't find controller for {comp.name}." + def reshape_control_signal(self, arr): current_shape = np.shape(arr) @@ -7807,11 +8238,11 @@ def _route_control_projection_through_intermediary_pcims(self, graph_receiver.add_projection(p, receiver=p.receiver, sender=control_signal) try: sender._remove_projection_to_port(projection) - except ValueError: + except (ValueError, PortError): pass try: receiver._remove_projection_from_port(projection) - except ValueError: + except (ValueError, PortError): pass receiver = interface_input_port return MappingProjection(sender=sender, receiver=receiver) @@ -7843,18 +8274,21 @@ def _check_controller_initialization_status(self, context=None): else: owner = component.receiver.owner warnings.warn( - f"The controller of {self.name} has been specified to project to {owner.name}, " - f"but {owner.name} is not in {self.name} or any of its nested Compositions. " - f"This projection will be deactivated until {owner.name} is added to {self.name} " + f"The controller of '{self.name}' has been specified to project to '{owner.name}', " + f"but '{owner.name}' is not in '{self.name}' or any of its nested Compositions. " + f"This projection will be deactivated until '{owner.name}' is added to' {self.name}' " f"in a compatible way." ) + # FIX: It seems this may never get called, as any specification of a Mechanism in the constructor + # for a ControlMechanism automatically instantiates a Projection that triggers the warning above. elif isinstance(component, Mechanism): warnings.warn( - f"The controller of {self.name} has a specification that includes the Mechanism " - f"{component.name}, but {component.name} is not in {self.name} or any of its " - f"nested Compositions. This Mechanism will be deactivated until {component.name} is " - f"added to {self.name} or one of its nested Compositions in a compatible way." + f"The controller of '{self.name}' has a specification that includes the Mechanism " + f"'{component.name}', but '{component.name}' is not in '{self.name}' or any of its " + f"nested Compositions. This Mechanism will be deactivated until '{component.name}' is " + f"added to '{self.name}' or one of its nested Compositions in a compatible way." ) + assert False, "WARNING MESSAGE" # If Composition is not preparing to execute, allow deferred_inits to persist without warning if context and ContextFlags.PREPARING not in context.execution_phase: @@ -7865,10 +8299,11 @@ def _check_controller_initialization_status(self, context=None): for projection in node.projections: if projection.initialization_status == ContextFlags.DEFERRED_INIT: if isinstance(projection, ControlProjection): - warnings.warn(f"The {projection.receiver.name} parameter of {projection.receiver.owner.name} \n" - f"is specified for control, but {self.name} does not have a controller. Please \n" - f"add a controller to {self.name} or the control specification will be \n" - f"ignored.") + warnings.warn(f"The '{projection.receiver.name}' parameter of " + f"'{projection.receiver.owner.name}' is specified for control, " + f"but the {COMPOSITION} it is in ('{self.name}') does not have a controller; " + f"if a controller is not added to {self.name} " + f"the control specification will be ignored.") def _check_nodes_initialization_status(self, context=None): @@ -7894,73 +8329,47 @@ def _check_nodes_initialization_status(self, context=None): f"or a composition nested within it." ) - # FIX: 11/3/21 ??GET RID OF THIS AND CALL TO IT ONCE PROJECTIONS HAVE BEEN IMPLEMENTED FOR SHADOWED INPUTS - # CHECK WHETHER state_input_ports ADD TO OR REPLACE shadowed_inputs - def _build_predicted_inputs_dict(self, predicted_input): - """Get inputs for evaluate method used to execute simulations of Composition. - - Get values of state_input_ports which receive projections from items providing relevant input (and any - processing of those values specified - """ - inputs = {} - no_predicted_input = (predicted_input is None or not len(predicted_input)) - if no_predicted_input: - warnings.warn(f"{self.name}.evaluate() called without any inputs specified; default values will be used") - - nested_nodes = dict(self._get_nested_nodes()) - # FIX: 11/3/21 NEED TO MODIFY IF OUTCOME InputPorts ARE MOVED - shadow_inputs_start_index = self.controller.num_outcome_input_ports - for j in range(len(self.controller.input_ports) - shadow_inputs_start_index): - input_port = self.controller.input_ports[j + shadow_inputs_start_index] - if no_predicted_input: - shadowed_input = input_port.defaults.value - else: - shadowed_input = predicted_input[j] - - if hasattr(input_port, SHADOW_INPUTS) and input_port.shadow_inputs is not None: - shadow_input_owner = input_port.shadow_inputs.owner - if self._controller_initialization_status == ContextFlags.DEFERRED_INIT \ - and shadow_input_owner not in nested_nodes \ - and shadow_input_owner not in self.nodes: - continue - if shadow_input_owner not in nested_nodes: - if isinstance(shadow_input_owner, CompositionInterfaceMechanism): - shadow_input_owner = shadow_input_owner.composition - inputs[shadow_input_owner] = shadowed_input - else: - comp = nested_nodes[shadow_input_owner] - if comp not in inputs: - inputs[comp]=[[shadowed_input]] - else: - inputs[comp]=np.concatenate([[shadowed_input],inputs[comp][0]]) - return inputs - def _get_total_cost_of_control_allocation(self, control_allocation, context, runtime_params): total_cost = 0. if control_allocation is not None: # using "is not None" in case the control allocation is 0. - base_control_allocation = self.reshape_control_signal(self.controller.parameters.value._get(context)) + def get_controller(comp): + """Get controller for which the current Composition is an agent_rep. + Recursively search enclosing Compositions for controller if self does not have one. + Use context.composition to find controller. + This is needed for agent_rep that is nested within the Composition to which the controller belongs. + """ + if comp.controller: + return comp.controller + elif context.composition: + return get_controller(context.composition) + else: + assert False, f"PROGRAM ERROR: Can't find controller for {self.name}." + + controller = self._get_controller(context=context) + base_control_allocation = self.reshape_control_signal(controller.parameters.value._get(context)) candidate_control_allocation = self.reshape_control_signal(control_allocation) # Get reconfiguration cost for candidate control signal reconfiguration_cost = 0. - if callable(self.controller.compute_reconfiguration_cost): - reconfiguration_cost = self.controller.compute_reconfiguration_cost([candidate_control_allocation, + if callable(controller.compute_reconfiguration_cost): + reconfiguration_cost = controller.compute_reconfiguration_cost([candidate_control_allocation, base_control_allocation]) - self.controller.reconfiguration_cost.set(reconfiguration_cost, context) + controller.reconfiguration_cost.set(reconfiguration_cost, context) # Apply candidate control signal - self.controller._apply_control_allocation(candidate_control_allocation, + controller._apply_control_allocation(candidate_control_allocation, context=context, runtime_params=runtime_params, ) # Get control signal costs - other_costs = self.controller.parameters.costs._get(context) or [] + other_costs = controller.parameters.costs._get(context) or [] all_costs = convert_to_np_array(other_costs + [reconfiguration_cost]) # Compute a total for the candidate control signal(s) - total_cost = self.controller.combine_costs(all_costs) + total_cost = controller.combine_costs(all_costs) + return total_cost # endregion CONTROL @@ -7985,8 +8394,8 @@ def evaluate( """Run Composition and compute `net_outcomes ` Runs the `Composition` in simulation mode (i.e., excluding its `controller `) - using the **predicted_input** and specified **control_allocation** for each run. The Composition is - run for ***num_trials**. + using the **predicted_input** (state_feature_values and specified **control_allocation** for each run. + The Composition is run for ***num_trials**. If **predicted_input** is not specified, and `block_simulate` is set to True, the `controller ` attempts to use the entire input set provided to the `run ` @@ -8011,8 +8420,7 @@ def evaluate( an array with the results of each run is also returned. """ - # Apply candidate control to signal(s) for the upcoming simulation and determine its cost - total_cost = self._get_total_cost_of_control_allocation(control_allocation, context, runtime_params) + controller = self._get_controller(context=context) # Build input dictionary for simulation input_spec = self.parameters.input_specification.get(context) @@ -8022,15 +8430,17 @@ def evaluate( elif isinstance(input_spec, dict): inputs = input_spec else: - inputs = self._build_predicted_inputs_dict(predicted_input) + inputs = predicted_input if hasattr(self, '_input_spec') and block_simulate and isgenerator(input_spec): warnings.warn(f"The evaluate method of {self.name} is attempting to use block simulation, but the " f"supplied input spec is a generator. Generators can not be used as inputs for block " f"simulation. This evaluation will not use block simulation.") + # Apply candidate control to signal(s) for the upcoming simulation and determine its cost + total_cost = self._get_total_cost_of_control_allocation(control_allocation, context, runtime_params) - # Set up aniimation for simulation + # Set up animation for simulation # HACK: _animate attribute is set in execute method, but Evaluate can be called on a Composition that has not # yet called the execute method, so we need to do a check here too. # -DTS @@ -8045,6 +8455,9 @@ def evaluate( buffer_animate_state = self._animate # Run Composition in "SIMULATION" context + # # MODIFIED 3/28/22 NEW: + # context.source = ContextFlags.COMPOSITION + # MODIFIED 3/28/22 END context.add_flag(ContextFlags.SIMULATION_MODE) context.remove_flag(ContextFlags.CONTROL) @@ -8077,22 +8490,22 @@ def evaluate( # COMPUTE net_outcome and aggregate in net_outcomes # Update input ports in order to get correct value for "outcome" (from objective mech) - self.controller._update_input_ports(runtime_params, context) + controller._update_input_ports(runtime_params, context) # FIX: REFACTOR TO CREATE ARRAY OF INPUT_PORT VALUES FOR OUTCOME_INPUT_PORTS - outcome_is_array = self.controller.num_outcome_input_ports > 1 + outcome_is_array = controller.num_outcome_input_ports > 1 if not outcome_is_array: - outcome = self.controller.input_port.parameters.value._get(context) + outcome = controller.input_port.parameters.value._get(context) else: outcome = [] - for i in range(self.controller.num_outcome_input_ports): - outcome.append(self.controller.parameters.input_ports._get(context)[i].parameters.value._get(context)) + for i in range(controller.num_outcome_input_ports): + outcome.append(controller.parameters.input_ports._get(context)[i].parameters.value._get(context)) if outcome is None: net_outcome = 0.0 else: # Compute net outcome based on the cost of the simulated control allocation (usually, net = outcome - cost) - net_outcome = self.controller.compute_net_outcome(outcome, total_cost) + net_outcome = controller.compute_net_outcome(outcome, total_cost) if return_results: return net_outcome, result @@ -8174,7 +8587,7 @@ def _recursive_update(d, u): # 3) Resize inputs to be of the form [[[]]], # where each level corresponds to: > > - inputs, num_inputs_sets = self._parse_dict(inputs) + inputs, num_inputs_sets = self._parse_input_dict(inputs) return inputs, num_inputs_sets @@ -8238,7 +8651,7 @@ def _parse_list(self, inputs): raise CompositionError( f"Inputs to {self.name} must be specified in a dictionary with a key for each of its " f"{len(input_nodes)} INPUT nodes ({[n.name for n in input_nodes]}).") - input_dict, num_inputs_sets = self._parse_dict(_inputs) + input_dict, num_inputs_sets = self._parse_input_dict(_inputs) return input_dict, num_inputs_sets def _parse_string(self, inputs): @@ -8267,7 +8680,7 @@ def _parse_string(self, inputs): raise CompositionError( f"Inputs to {self.name} must be specified in a dictionary with a key for each of its " f"{len(input_nodes)} INPUT nodes ({[n.name for n in input_nodes]}).") - input_dict, num_inputs_sets = self._parse_dict(_inputs) + input_dict, num_inputs_sets = self._parse_input_dict(_inputs) return input_dict, num_inputs_sets def _parse_function(self, inputs): @@ -8286,24 +8699,27 @@ def _parse_function(self, inputs): num_trials = 1 return inputs, num_trials - def _validate_single_input(self, node, input): - """ - validates a single input for a single node. if the input is specified without an outer list (i.e. - Composition.run(inputs = [1, 1]) instead of Composition.run(inputs = [[1], [1]]), add an extra dimension - to the input + def _validate_single_input(self, receiver, input): + """Validate a single input for a single receiver. + If the input is specified without an outer list (i.e. Composition.run(inputs = [1, 1]) instead of + Composition.run(inputs = [[1], [1]]), add an extra dimension to the input Returns ------- `None` or `np.ndarray` or `list` : The input, with an added dimension if necessary, if the input is valid. `None` if the input is not valid. - """ - # Validate that a single input is properly formatted for a node. + + # Validate that a single input is properly formatted for a receiver. _input = [] - node_variable = [input_port.defaults.value for input_port in node.input_ports if not input_port.internal_only] - match_type = self._input_matches_variable(input, node_variable) - # match_type = self._input_matches_variable(input, node_variable) + if isinstance(receiver, InputPort): + input_shape = receiver.default_input_shape + elif isinstance(receiver, Mechanism): + input_shape = receiver.external_input_shape + elif isinstance(receiver, Composition): + input_shape = receiver.input_CIM.external_input_shape + match_type = self._input_matches_variable(input, input_shape) if match_type == 'homogeneous': # np.atleast_2d will catch any single-input ports specified without an outer list _input = convert_to_np_array(input, 2) @@ -8313,142 +8729,63 @@ def _validate_single_input(self, node, input): _input = None return _input - def _validate_input_shapes(self, inputs): + def _parse_input_dict(self, inputs, context=None): """ - Validates that all inputs provided in input dict are valid + Validate and parse a dict provided as input to a Composition into a standardized form to be used throughout + its execution Returns ------- - `dict` : - The input dict, with shapes corrected if necessary. - - """ - # Loop over all dictionary entries to validate their content and adjust any convenience notations: - - # (1) Replace any user provided convenience notations with values that match the following specs: - # a - all dictionary values are lists containing an input value for each trial (even if only one trial) - # b - each input value is a 2d array that matches variable - # example: { Mech1: [Fully_specified_input_for_mech1_on_trial_1, Fully_specified_input_for_mech1_on_trial_2 … ], - # Mech2: [Fully_specified_input_for_mech2_on_trial_1, Fully_specified_input_for_mech2_on_trial_2 … ]} - # (2) Verify that all nodes provide the same number of inputs (check length of each dictionary value) - _inputs = {} - input_lengths = set() - inputs_to_duplicate = [] - # loop through input dict - for node, stimulus in inputs.items(): - # see if the entire stimulus set provided is a valid input for the node (i.e. in the case of a call with a - # single trial of provided input) - node_input = self._validate_single_input(node, stimulus) - if node_input is not None: - node_input = [node_input] - else: - # if node_input is None, it means there are multiple trials of input in the stimulus set, so loop - # through and validate each individual input - node_input = [self._validate_single_input(node, single_trial_input) for single_trial_input in stimulus] - if True in [i is None for i in node_input]: - incompatible_stimulus = stimulus[node_input.index(None)] - node_name = node.name - node_variable = [input_port.defaults.value for input_port in node.input_ports - if not input_port.internal_only] - err_msg = f"Input stimulus ({incompatible_stimulus}) for {node_name} is incompatible with " \ - f"its external_input_values ({node_variable})." - # 8/3/17 CW: I admit the error message implementation here is very hacky; - # but it's at least not a hack for "functionality" but rather a hack for user clarity - if "KWTA" in str(type(node)): - err_msg = err_msg + " For KWTA mechanisms, remember to append an array of zeros " \ - "(or other values) to represent the outside stimulus for " \ - "the inhibition InputPort, and for Compositions, put your inputs" - raise RunError(err_msg) - _inputs[node] = node_input - input_length = len(node_input) - if input_length == 1: - inputs_to_duplicate.append(node) - # track input lengths. stimulus sets of length 1 can be duplicated to match another stimulus set length. - # there can be at maximum 1 other stimulus set length besides 1. - input_lengths.add(input_length) - if 1 in input_lengths: - input_lengths.remove(1) - if len(input_lengths) > 1: - raise CompositionError(f"The input dictionary for {self.name} contains input specifications of different " - f"lengths ({input_lengths}). The same number of inputs must be provided for each " - f"node in a Composition.") - elif len(input_lengths) > 0: - num_trials = list(input_lengths)[0] - for mechanism in inputs_to_duplicate: - # hacky, but need to convert to list to use * syntax to duplicate element - if type(_inputs[mechanism]) == np.ndarray: - _inputs[mechanism] = _inputs[mechanism].tolist() - _inputs[mechanism] *= num_trials - return _inputs - - def _flatten_nested_dicts(self, inputs): - """ - Converts inputs provided in the form of a dict for a nested Composition to a list corresponding to the - Composition's input CIM ports - - Returns - ------- + Parsed and standardized input dict - `dict` : - The input dict, with nested dicts corresponding to nested Compositions converted to lists + `int` : + Number of input sets (i.e., trials' worths of inputs) in dict for each input node in the Composition """ - # Inputs provided for nested compositions in the form of a nested dict need to be converted into a list, - # to be provided to the outer Composition's input port that corresponds to the nested Composition - _inputs = {} - for node, inp in inputs.items(): - if node.componentType == 'Composition' and type(inp) == dict: - # If there are multiple levels of nested dicts, we need to convert them starting from the deepest level, - # so recurse down the chain here - inp, num_trials = node._parse_dict(inp) - translated_stimulus_dict = {} - - # first time through the stimulus dictionary, assemble a dictionary in which the keys are input CIM - # InputPorts and the values are lists containing the first input value - for nested_input_node, values in inp.items(): - first_value = values[0] - for i in range(len(first_value)): - input_port = nested_input_node.external_input_ports[i] - input_cim_input_port = node.input_CIM_ports[input_port][0] - translated_stimulus_dict[input_cim_input_port] = [first_value[i]] - # then loop through the stimulus dictionary again for each remaining trial - for trial in range(1, num_trials): - translated_stimulus_dict[input_cim_input_port].append(values[trial][i]) - - adjusted_stimulus_list = [] - for trial in range(num_trials): - trial_adjusted_stimulus_list = [] - for port in node.external_input_ports: - trial_adjusted_stimulus_list.append(translated_stimulus_dict[port][trial]) - adjusted_stimulus_list.append(trial_adjusted_stimulus_list) - _inputs[node] = adjusted_stimulus_list - else: - _inputs.update({node:inp}) - return _inputs + # parse a user-provided input dict to format it properly for execution. + # compute number of input sets and return that as well + _inputs = self._parse_names_in_inputs(inputs) + _inputs = self._parse_labels(_inputs) + self._validate_input_dict_keys(_inputs) + _inputs = self._instantiate_input_dict(_inputs) + _inputs = self._flatten_nested_dicts(_inputs) + _inputs = self._validate_input_shapes(_inputs) + num_inputs_sets = len(next(iter(_inputs.values()),[])) + return _inputs, num_inputs_sets def _parse_names_in_inputs(self, inputs): names = [] + # Get keys that are names rather than Components for key in inputs: if isinstance(key, str): names.append(key) - named_nodes = [(node, node.name) for node in self.get_nodes_by_role(NodeRole.INPUT) if node.name in names] - for node, name in named_nodes: + # named_entries = [(node, node.name) for node in self.get_nodes_by_role(NodeRole.INPUT) if node.name in names] + named_entries = [] + for node in self.get_nodes_by_role(NodeRole.INPUT): + if node.name in names: + named_entries.append((node, node.name)) + else: + for port in node.input_ports: + if port.full_name in names: + named_entries.append((port, port.full_name)) + # Replace name with node itself in key + for node, name in named_entries: inputs[node] = inputs.pop(name) return inputs - def _parse_labels(self, inputs, mech=None, context=None): + def _parse_labels(self, inputs, mech=None, port=None, context=None): """ - Traverse input dict and replace any inputs that are in the form of their input or output label representations - to their numeric representations + Traverse input dict and resolve any input or output labels to their numeric values + If **port** is passed, inputs is only for a single port, so manage accordingly Returns ------- `dict` : - The input dict, with inputs with their label representations replaced by their numeric representations - + The input dict, with inputs with labels replaced by corresponding numeric values """ + # the nested list comp below is necessary to retrieve target nodes of learning pathways, # because the PathwayRole enum is not importable into this module target_to_output = {path.target: path.output for path in self.pathways @@ -8464,23 +8801,40 @@ def _parse_labels(self, inputs, mech=None, context=None): for k,v in inputs.items(): if isinstance(k, Mechanism) and \ (target_to_output[k].output_labels_dict if k in target_to_output else k.input_labels_dict): - _inputs.update({k:self._parse_labels(v, k)}) + _inputs.update({k:self._parse_labels(v, k)}) # Full node's worth of inputs, so don't pass port else: # Call _parse_labels for any Nodes with input_labels_dicts in nested Composition(s) if (isinstance(k, Composition) and any(n.input_labels_dict for n in k._get_nested_nodes_with_same_roles_at_all_levels(k,NodeRole.INPUT))): - for i, port in enumerate(k.input_CIM.input_ports): - _, mech_with_labels, __ = k.input_CIM._get_destination_node_for_input_port(port) - v[i] = k._parse_labels(inputs[k][i],mech_with_labels) + if nesting_depth(v) == 2: + # Enforce that even single trial specs user outer trial dimension (for consistency below) + v = [v] + for t in range(len(v)): + for i, cim_port in enumerate(k.input_CIM.input_ports): + port, mech_with_labels, __ = k.input_CIM._get_destination_info_from_input_CIM(cim_port) + # Get only a port's worth of input, so signify by passing port with input, + # which is also need since it is not bound to owning Mechanism in input_CIM, + # so its index can't be determined in recursive call to _parse_labels below + v[t][i] = k._parse_labels(v[t][i],mech_with_labels, port) _inputs.update({k:v}) else: _inputs.update({k:v}) elif type(inputs) == list or type(inputs) == np.ndarray: _inputs = [] - for i in range(len(inputs)): - port = 0 if len(labels) == 1 else i - stimulus = inputs[i] + for i in range(len(inputs)): # One for each port if full node's worth, else inputs = input for port + if port: + # port passed in, since it is not bound to owner in input_CIM, so index can't be determined locally + # also signifies input is to be treated as just for that port (not entire node), so 1 dim less + port_index = mech.input_ports.index(port) + if not isinstance(inputs[0], str): + # If input for port is not a string, no further processing need, so just return as is + _inputs = inputs + break + else: + # No port passed in, so use primary InputPort if only one input, or i if inputs for multiple ports + port_index = 0 if len(labels) == 1 else i + stimulus = inputs[i] # input for port if type(stimulus) == list or type(stimulus) == np.ndarray: _inputs.append(self._parse_labels(inputs[i], mech)) elif type(stimulus) == str: @@ -8488,65 +8842,338 @@ def _parse_labels(self, inputs, mech=None, context=None): raise CompositionError(f"Inappropriate use of str ({repr(stimulus)}) as a stimulus for " f"{mech.name} in {self.name}: it does not have an input_labels_dict.") try: - _inputs.append(labels[port][stimulus]) + if len(inputs) == 1: + _inputs = np.atleast_1d(labels[port_index][stimulus]) + else: + _inputs.append(labels[port_index][stimulus]) except KeyError as e: raise CompositionError(f"Inappropriate use of {repr(stimulus)} as a stimulus for {mech.name} " f"in {self.name}: it is not a label in its input_labels_dict.") else: _inputs.append(stimulus) + return _inputs - def _parse_dict(self, inputs, context=None): + def _validate_input_dict_keys(self, inputs): + """Validate that keys of inputs are all legal: + - they are all InputPorts, Mechanisms or Compositions; + - they are all (or InputPorts of) INPUT Nodes of Composition at any level of nesting; + - an InputPort and the Mechanism to which it belongs are not *both* specified; + - an InputPort of an input_CIM and the Composition to which it belongs are not *both* specified; + - an InputPort or Mechanism and any Composition under which it is nested are not *both* specified. + """ + + # Validate that keys for inputs are all legal *types* + bad_entries = [key for key in inputs if not isinstance(key, (InputPort, Mechanism, Composition))] + if bad_entries: + bad_entry_names = [repr(key.full_name) if isinstance(key, Port) else repr(key.name) for key in bad_entries] + raise RunError(f"The following items specified in the 'inputs' arg of the run() method for " + f"'{self.name}' that are not a Mechanism, Composition, or an InputPort of one: " + f"{', '.join(bad_entry_names)}.") + + # Validate that keys for inputs all are or belong to *INPUT Nodes* of Composition (at any level of nesting) + all_allowable_entries = self._get_input_receivers(type=PORT) \ + + self._get_input_receivers(type=NODE, comp_as_node=ALL) + bad_entries = [key for key in inputs if key not in all_allowable_entries] + if bad_entries: + bad_entry_names = [repr(key.full_name) if isinstance(key, Port) else repr(key.name) for key in bad_entries] + raise RunError(f"The following items specified in the 'inputs' arg of the run() method for '{self.name}' " + f"are not INPUT Nodes of that Composition (nor InputPorts of them): " + f"{', '.join(bad_entry_names)}.") + + # Validate that an InputPort *and* its owner are not *both* specified in inputs + bad_entries = [key.full_name for key in inputs if isinstance(key, InputPort) and key.owner in inputs] + if bad_entries: + raise RunError(f"The 'inputs' arg of the run() method for '{self.name}' includes specifications of the " + f"following InputPorts *and* the Mechanisms to which they belong; only one or the other " + f"can be specified as inputs to run(): {', '.join(bad_entries)}.") + + # Validate that an InputPort of an input_CIM *and* its Composition are not *both* specified in inputs + # (this is unlikely but possible) + bad_entries = [key.full_name for key in inputs + if (isinstance(key, InputPort) + and isinstance(key.owner, CompositionInterfaceMechanism) + and key.owner.composition in inputs)] + if bad_entries: + raise RunError(f"The 'inputs' arg of the run() method for '{self.name}' includes specifications of the " + f"following InputPort(s) of a CompositionInterfaceMechanism *and* the Composition to which " + f"they belong; only one or the other can be specified as inputs to run(): " + f"{', '.join(bad_entries)}.") + + # # Validate that InputPort or Mechanism and the Composition(s) under which it is nested are not both specified + def check_for_items_in_nested_comp(comp): + bad_entries = [] + for node in comp._all_nodes: # note: this only includes nodes as top level of comp + if isinstance(node, Composition) and node in inputs: + all_nested_items = node._get_input_receivers(type=PORT) \ + + node._get_input_receivers(type=NODE, comp_as_node=ALL) + bad_entries.extend([(entry, node) for entry in inputs if entry in all_nested_items]) + bad_entries.extend(check_for_items_in_nested_comp(node)) + return bad_entries + bad_entries = check_for_items_in_nested_comp(self) + if bad_entries: + bad_entry_names = [(key.full_name, comp.name) if isinstance(key, Port) else (key.name, comp.name) + for key,comp in bad_entries] + raise RunError(f"The 'inputs' arg of the run() method for '{self.name}' includes specifications of the " + f"following InputPorts or Mechanisms *and* the Composition within which they are nested: " + # f"{', '.join(bad_entry_names)}.") + f"{bad_entry_names}.") + + def _instantiate_input_dict(self, inputs): + """Implement dict with all INPUT Node of Composition as keys and their assigned inputs or defaults as values + **inputs** can contain specifications for inputs to InputPorts, Mechanisms and/or nested Compositions, + that can be at any level of nesting within self. + Consolidate any entries of **inputs** with InputPorts as keys to Mechanism or Composition entries + If any INPUT Nodes of Composition are not included, add them to the input_dict using their default values. + InputPort entries must specify either a single trial or the same number as all other InPorts for that Node: + - preprocess InputPorts for a Node to determine maximum number of trials specified, and use to set mech_shape + - if more than one trial is specified for any InputPort, assign fillers to ones that specify only one trial + (this does not apply to Mechanism or Composition specifications, as they are tested in validate_input_shapes) + + Return input_dict, with added entries for any INPUT Nodes or InputPorts for which input was not provided + """ + + input_dict = {} + input_nodes = self.get_nodes_by_role(NodeRole.INPUT) + remaining_inputs = set(inputs) + + # Construct input_dict from input_nodes of self + for INPUT_Node in input_nodes: + + # If entry is for an INPUT_Node of self, assign the entry directly to input_dict and proceed to next + if INPUT_Node in inputs: + input_dict[INPUT_Node] = inputs[INPUT_Node] + remaining_inputs.remove(INPUT_Node) + continue + + # If INPUT_Node is a Composition, get its input_CIM as mech + mech = INPUT_Node if isinstance(INPUT_Node, Mechanism) else INPUT_Node.input_CIM + INPUT_input_ports = mech.input_ports + input_port_entries = {} + inputs_to_remove = set() + + # Look for entries of inputs dict with keys that are input_ports of mech, or Composition's input_CIM + # Note: need to cycle through all inputs before constructing entries for INPUT Node + # since there may be multiple Port entries for a given INPUT Node that may differ in their specs, + # so need to process all of them to determine proper shape for input + for input_recvr in remaining_inputs: + + # Get input spec and standardize port spec as 2d to deal with any specs in time series format + port_inputs = np.atleast_2d(inputs[input_recvr]) + + # Entry is InputPort of INPUT_Node itself (usually of a standard Mechanism, but could be of input_CIM) + if input_recvr in mech.input_ports: + input_port_entries[input_recvr] = port_inputs + inputs_to_remove.add(input_recvr) + + # If INPUT_Node is a Composition, check if input_recvr is for an INPUT Node nested under it; + # if so, get the input_port(s) of mech.input_CIM to which its inputs correspond + elif (isinstance(INPUT_Node, Composition) + and ((input_recvr.owner if isinstance(input_recvr, Port) else input_recvr) in + INPUT_Node._get_nested_nodes_with_same_roles_at_all_levels(INPUT_Node, NodeRole.INPUT))): + if isinstance(input_recvr, Port): + # Spec is for Port so assign to entry for corresponding input_CIM_input_port of INPUT_Node + input_ports = [input_recvr] + else: + # Spec is for Mechanism or Composition so get its input_ports + input_ports = (input_recvr.input_ports if isinstance(input_recvr, Mechanism) + else input_recvr.input_CIM.input_ports) + # For each port in input_ports of Mech or Compositions input_CIM + for i, input_port in enumerate(input_ports): + # Get corresponding InputPort of input_CIM for INPUT_Node + input_CIM_input_port, _ = self._get_external_cim_input_port(input_port, self) + assert input_CIM_input_port.owner == mech, \ + f"PROGRAM ERROR: Unexpected input_CIM_input_port retrieved for entry ({input_recvr}) " \ + f"in inputs to '{self.name}'." + # Assign spec for InputPort to entry for corresponding InputPort on input_CIM of INPUT_Node + input_port_entries[input_CIM_input_port] = port_inputs[i] + inputs_to_remove.add(input_recvr) + + # Get max number of trials across specified input_ports of INPUT_Node + max_num_trials = 1 + for port in input_port_entries: + assert mech == port.owner + port_input = input_port_entries[port] + # Get number of trials of input specified for Port + num_trials = len(port_input) + if max_num_trials != 1 and num_trials not in {1, max_num_trials}: + raise CompositionError(f"Number of trials of input specified for {port.full_name} of {node.name} " + f"({num_trials}) is different from the number ({max_num_trials}) " + f"specified for one or more others.") + max_num_trials = max(num_trials, max_num_trials) + + # Construct node_input_shape based on max_num_trials across all input_ports for mech + # - shape as 3d by adding outer dim = max_num trials to accommodate potential trial-series input + node_input = np.empty(tuple([max_num_trials] + + list(np.array(mech.external_input_shape).shape)), + dtype='object').tolist() + # - move ports to outer access for processing below + node_input = np.swapaxes(np.atleast_3d(np.array(node_input, dtype=object)),0,1).tolist() + + # Assign specs to ports of INPUT_Node, using ones in input_port_entries or defaults + for i, port in enumerate(INPUT_input_ports): + if port in input_port_entries: + # Assume input is for all trials + port_spec = np.atleast_2d(input_port_entries[port]).tolist() + if len(port_spec) < max_num_trials: + # If input is not for all trials, ensure that it is only for a single trial + assert len(port_spec) == 1, f"PROGRAM ERROR: Length of port_spec for '{port.full_name}' " \ + f"in input to '{self.name}' ({len(port_spec)}) should now be " \ + f"1 or {max_num_trials}." + # Assign the input for the single trial over all trials + port_spec = [np.array(port_spec[0]).tolist()] * max_num_trials + else: + # Assign default input to Port for all trials + port_spec = [np.array(port.default_input_shape).tolist()] * max_num_trials + node_input[i] = port_spec + + # Put trials back in outer axis + input_dict[INPUT_Node] = np.swapaxes(np.atleast_3d(np.array(node_input, dtype=object)),0,1).tolist() + remaining_inputs = remaining_inputs - inputs_to_remove + + if remaining_inputs: + assert False, f"PROGRAM ERROR: the following items specified in the 'inputs' arg of the run() method " \ + f"for '{self.name}' are not INPUT Nodes of that Composition (nor InputPorts of them): " \ + f"{remaining_inputs} -- SHOULD HAVE RAISED ERROR IN composition._validate_input_dict_keys()" + + # If any INPUT Nodes of the Composition are not specified, add them and assign default_external_input_values + for node in input_nodes: + if node not in input_dict: + input_dict[node] = node.external_input_shape + + return input_dict + + def _flatten_nested_dicts(self, inputs): """ - Validates and parses a dict provided as input to a Composition into a standardized form to be used throughout - its execution + Converts inputs provided in the form of a dict for a nested Composition to a list corresponding to the + Composition's input CIM ports Returns ------- - `dict` : - Parsed and standardized input dict - `int` : - Number of input sets in dict for each input node in the Composition + `dict` : + The input dict, with nested dicts corresponding to nested Compositions converted to lists """ - # parse a user-provided input dict to format it properly for execution. - # compute number of input sets and return that as well - _inputs = self._parse_names_in_inputs(inputs) - _inputs = self._parse_labels(_inputs) - _inputs = self._validate_input_dict_node_roles(_inputs) - _inputs = self._flatten_nested_dicts(_inputs) - _inputs = self._validate_input_shapes(_inputs) - num_inputs_sets = len(next(iter(_inputs.values()))) - return _inputs, num_inputs_sets + # Inputs provided for nested compositions in the form of a nested dict need to be converted into a list, + # to be provided to the outer Composition's input port that corresponds to the nested Composition + _inputs = {} + for node, inp in inputs.items(): + if node.componentType == 'Composition' and type(inp) == dict: + # If there are multiple levels of nested dicts, we need to convert them starting from the deepest level, + # so recurse down the chain here + inp, num_trials = node._parse_input_dict(inp) + translated_stimulus_dict = {} + + # first time through the stimulus dictionary, assemble a dictionary in which the keys are input CIM + # InputPorts and the values are lists containing the first input value + for nested_input_node, values in inp.items(): + first_value = values[0] + for i in range(len(first_value)): + input_port = nested_input_node.external_input_ports[i] + input_cim_input_port = node.input_CIM_ports[input_port][0] + translated_stimulus_dict[input_cim_input_port] = [first_value[i]] + # then loop through the stimulus dictionary again for each remaining trial + for trial in range(1, num_trials): + translated_stimulus_dict[input_cim_input_port].append(values[trial][i]) + + adjusted_stimulus_list = [] + for trial in range(num_trials): + trial_adjusted_stimulus_list = [] + for port in node.external_input_ports: + trial_adjusted_stimulus_list.append(translated_stimulus_dict[port][trial]) + adjusted_stimulus_list.append(trial_adjusted_stimulus_list) + _inputs[node] = adjusted_stimulus_list + else: + _inputs.update({node:inp}) + return _inputs - def _validate_input_dict_node_roles(self, inputs): + def _validate_input_shapes(self, inputs): """ - Validates that all nodes included in input dict are input nodes. Additionally, if any input nodes are not - included, adds them to the input dict using their default values as entries + Validates that all inputs provided in input dict are valid Returns ------- `dict` : - The input dict, with added entries for any input nodes for which input was not provided + The input dict, with shapes corrected if necessary. """ - # STEP 1A: Check that all of the nodes listed in the inputs dict are INPUT nodes in the composition - input_nodes = self.get_nodes_by_role(NodeRole.INPUT) - for node in inputs.keys(): - if node not in input_nodes: - if not isinstance(node, (Mechanism, Composition)): - raise CompositionError(f'{node} in "inputs" dict for {self.name} is not a ' - f'{Mechanism.__name__} or {Composition.__name__}.') - else: - raise CompositionError(f"{node.name} in inputs dict for {self.name} is not one of its INPUT nodes.") + # Loop over all dictionary entries to validate their content and adjust any convenience notations: - # STEP 1B: Check that all of the INPUT nodes are represented - if not, use default_external_input_values - for node in input_nodes: - if node not in inputs: - inputs[node] = node.default_external_input_values - return inputs + # (1) Replace any user provided convenience notations with values that match the following specs: + # a - all dictionary values are lists containing an input value for each trial (even if only one trial) + # b - each input value is a 2d array that matches variable + # example: { Mech1: [Fully_specified_input_for_mech1_on_trial_1, Fully_specified_input_for_mech1_on_trial_2 … ], + # Mech2: [Fully_specified_input_for_mech2_on_trial_1, Fully_specified_input_for_mech2_on_trial_2 … ]} + # (2) Verify that all nodes provide the same number of inputs (check length of each dictionary value) + _inputs = {} + input_lengths = set() + inputs_to_duplicate = [] + # loop through input dict + for receiver, stimulus in inputs.items(): + # see if the entire stimulus set provided is a valid input for the receiver (i.e. in the case of a call with a + # single trial of provided input) + _input = self._validate_single_input(receiver, stimulus) + if _input is not None: + _input = [_input] + else: + # if _input is None, it may mean there are multiple trials of input in the stimulus set, + # so in list comprehension below loop through and validate each individual input; + _input = [self._validate_single_input(receiver, single_trial_input) for single_trial_input in stimulus] + # Look for any bad ones (for which _validate_single_input() returned None) and report if found + if any(i is None for i in _input): + if isinstance(receiver, InputPort): + receiver_shape = receiver.default_input_shape + receiver_name = receiver.full_name + elif isinstance(receiver, Mechanism): + receiver_shape = receiver.external_input_shape + receiver_name = receiver.name + elif isinstance(receiver, Composition): + receiver_shape = receiver.input_CIM.external_input_shape + receiver_name = receiver.name + # # MODIFIED 3/12/22 OLD: + # bad_stimulus = np.atleast_1d(np.squeeze(np.array(stimulus[_input.index(None)], dtype=object))) + # correct_stimulus = np.atleast_1d(np.array(receiver_shape[_input.index(None)], dtype=object)) + # err_msg = f"Input stimulus ({bad_stimulus}) for {receiver_name} is incompatible with " \ + # f"the shape of its external input ({correct_stimulus})." + # MODIFIED 3/12/22 NEW: + # FIX: MIS-REPORTS INCOMPATIBLITY AS BEING FOR SHAPE IF NUM TRIALS IS DIFFERENT FOR DIFF PORTS + # SHOULD BE HANDLED SAME AS FOR DIFFERNCE ACROSS NODES (PER BELOW) + receiver_shape = np.atleast_1d(np.squeeze(np.array(receiver_shape, dtype=object))) + bad_stimulus = [stim for stim, _inp in zip(stimulus, _input) if _inp is None] + bad_stimulus = np.atleast_1d(np.squeeze(np.array(bad_stimulus, dtype=object))) + err_msg = f"Input stimulus ({bad_stimulus}) for {receiver_name} is incompatible with " \ + f"the shape of its external input ({receiver_shape})." + # MODIFIED 3/12/22 END + # 8/3/17 CW: I admit the error message implementation here is very hacky; + # but it's at least not a hack for "functionality" but rather a hack for user clarity + if "KWTA" in str(type(receiver)): + err_msg = err_msg + " For KWTA mechanisms, remember to append an array of zeros " \ + "(or other values) to represent the outside stimulus for " \ + "the inhibition InputPort, and for Compositions, put your inputs" + raise RunError(err_msg) + _inputs[receiver] = _input + input_length = len(_input) + if input_length == 1: + inputs_to_duplicate.append(receiver) + # track input lengths. stimulus sets of length 1 can be duplicated to match another stimulus set length. + # there can be at maximum 1 other stimulus set length besides 1. + input_lengths.add(input_length) + if 1 in input_lengths: + input_lengths.remove(1) + if len(input_lengths) > 1: + raise CompositionError(f"The input dictionary for {self.name} contains input specifications of different " + f"lengths ({input_lengths}). The same number of inputs must be provided for each " + f"receiver in a Composition.") + elif len(input_lengths) > 0: + num_trials = list(input_lengths)[0] + for mechanism in inputs_to_duplicate: + # hacky, but need to convert to list to use * syntax to duplicate element + if type(_inputs[mechanism]) == np.ndarray: + _inputs[mechanism] = _inputs[mechanism].tolist() + _inputs[mechanism] *= num_trials + return _inputs def _parse_run_inputs(self, inputs, context=None): """ @@ -8561,7 +9188,7 @@ def _parse_run_inputs(self, inputs, context=None): """ # handle user-provided input based on input type. return processd inputs and num_inputs_sets if not inputs: - _inputs, num_inputs_sets = self._parse_dict({}) + _inputs, num_inputs_sets = self._parse_input_dict({}) elif isgeneratorfunction(inputs): _inputs, num_inputs_sets = self._parse_generator_function(inputs) elif isgenerator(inputs): @@ -8571,7 +9198,7 @@ def _parse_run_inputs(self, inputs, context=None): elif type(inputs) == list: _inputs, num_inputs_sets = self._parse_list(inputs) elif type(inputs) == dict: - _inputs, num_inputs_sets = self._parse_dict(inputs) + _inputs, num_inputs_sets = self._parse_input_dict(inputs) elif type(inputs) == str: _inputs, num_inputs_sets = self._parse_string(inputs) else: @@ -8598,7 +9225,7 @@ def _parse_trial_inputs(self, inputs, trial_num): # this method is intended to run BEFORE a call to Composition.execute if callable(inputs): try: - inputs, _ = self._parse_dict(inputs(trial_num)) + inputs, _ = self._parse_input_dict(inputs(trial_num)) i = 0 except TypeError as e: error_text = e.args[0] @@ -8607,7 +9234,7 @@ def _parse_trial_inputs(self, inputs, trial_num): else: raise CompositionError(f"Problem with function provided to 'inputs' arg of {self.name}.run") elif isgenerator(inputs): - inputs, _ = self._parse_dict(inputs.__next__()) + inputs, _ = self._parse_input_dict(inputs.__next__()) i = 0 else: num_inputs_sets = len(next(iter(inputs.values()))) @@ -8631,11 +9258,14 @@ def _validate_execution_inputs(self, inputs): _inputs = {} for node, inp in inputs.items(): if isinstance(node, Composition) and type(inp) == dict: - inp = node._parse_dict(inp) + inp = node._parse_input_dict(inp) + if np.array(inp).ndim == 3: + # If inp formatted for trial series, get only one one trial's worth of inputs to test + inp = np.squeeze(inp, 0) inp = self._validate_single_input(node, inp) if inp is None: raise CompositionError(f"Input stimulus ({inp}) for {node.name} is incompatible " - f"with its variable ({node.default_external_input_values}).") + f"with its variable ({node.external_input_shape}).") _inputs[node] = inp return _inputs @@ -8643,7 +9273,11 @@ def _validate_execution_inputs(self, inputs): # EXECUTION # ****************************************************************************************************************** + # MODIFIED 3/28/22 OLD: @handle_external_context() + # # MODIFIED 3/28/22 NEW: + # @handle_external_context(source = ContextFlags.COMMAND_LINE) + # MODIFIED 3/28/22 END def run( self, inputs=None, @@ -8690,8 +9324,8 @@ def run( the inputs to each `INPUT` `Node ` of the Composition in each `TRIAL ` executed during the run (see `Composition_Execution_Inputs` for additional information about format, and `get_input_format ` method for generating an example of the input format for - the Composition). If **inputs** is not specified, the `default_variable ` for each - `INPUT` Node is used as its input on `TRIAL `. + the Composition). If **inputs** is not specified, the `default_variable ` for + each `INPUT` Node is used as its input on `TRIAL `. num_trials : int : default 1 typically, the composition will infer the number of trials from the length of its input specification. @@ -8791,17 +9425,17 @@ def run( details and `ReportDevices` for options. animate : dict or bool : default False - specifies use of the `show_graph`show_graph ` method - to generate a gif movie showing the sequence of Components executed in a run - (see `example `). A dict can be specified containing - options to pass to the `show_graph ` method; each key must be a legal - argument for the `show_graph ` method, and its value a - specification for that argument. The entries listed below can also be included in the dict to specify - parameters of the animation. If the **animate** argument is specified simply as `True`, defaults are - used for all arguments of `show_graph ` and the options below: + specifies use of the `show_graph`show_graph ` method to generate + a gif movie showing the sequence of Components executed in a run (see `example + `). A dict can be specified containing + options to pass to the `show_graph ` method; each key must be a legal + argument for the `show_graph ` method, and its value a specification for that + argument. The entries listed below can also be included in the dict to specify parameters of the + animation. If the **animate** argument is specified simply as `True`, defaults are used for all + arguments of `show_graph ` and the options below: * *UNIT*: *EXECUTION_SET* or *COMPONENT* (default=\\ *EXECUTION_SET*\\ ) -- specifies which Components - to treat as active in each call to `show_graph `. *COMPONENT* generates an + to treat as active in each call to `show_graph() `. *COMPONENT* generates an image for the execution of each Component. *EXECUTION_SET* generates an image for each `execution_set `, showing all of the Components in that set as active. @@ -8901,7 +9535,11 @@ def run( trials. """ + # MODIFIED 3/28/22 OLD: context.source = ContextFlags.COMPOSITION + # MODIFIED 3/28/22 END + execution_phase = context.execution_phase + context.execution_phase = ContextFlags.PREPARING for node in self.nodes: num_execs = node.parameters.num_executions._get(context) @@ -8919,7 +9557,7 @@ def run( # May be used by controller for specifying num_trials_per_simulation self.num_trials = num_trials - # DS 1/7/20: Check to see if any Components are still in deferred init. If so, attempt to initialize them. + # Check to see if any Components are still in deferred init. If so, attempt to initialize them. # If they can not be initialized, raise a warning. self._complete_init_of_partially_initialized_nodes(context=context) @@ -8930,6 +9568,9 @@ def run( if not skip_analyze_graph: self._analyze_graph(context=context) + if self._need_check_for_unused_projections: + self._check_for_unused_projections(context=context) + if scheduler is None: scheduler = self.scheduler @@ -9079,6 +9720,8 @@ def run( else: trial_output = None + context.execution_phase = execution_phase + # EXECUTE TRIALS ------------------------------------------------------------- with Report(self, @@ -9341,6 +9984,9 @@ def learn( runner = CompositionRunner(self) context.add_flag(ContextFlags.LEARNING_MODE) + # # MODIFIED 3/28/22 NEW: + # context.source = ContextFlags.COMPOSITION + # MODIFIED 3/28/22 END # # FIX 5/28/20 # context.add_flag(ContextFlags.PREPARING) # context.execution_phase=ContextFlags.PREPARING @@ -9475,8 +10121,8 @@ def execute( a dictionary containing a key-value pair for each `Node ` in the Composition that receives inputs from the user. For each pair, the key is the `Node ` (a `Mechanism ` or `Composition`) and the value is an input, the shape of which must match the Node's - default variable. If **inputs** is not specified, the `default_variable ` for - each `INPUT` Node is used as its input (see `Input Formats ` for + default variable. If **inputs** is not specified, the `default_variable ` + for each `INPUT` Node is used as its input (see `Input Formats ` for additional details). clamp_input : SOFT_CLAMP : default SOFT_CLAMP @@ -9587,11 +10233,15 @@ def execute( # These are meant to be assigned in run method; needed here for direct call to execute method self._animate = False - # KAM Note 4/29/19 + # IMPLEMENTATION NOTE: + # KAM 4/29/19 # The nested var is set to True if the Composition is nested in another Composition, otherwise False # Later on, this is used to determine: # (1) whether to initialize from context # (2) whether to assign values to CIM from input dict (if not nested) or simply execute CIM (if nested) + # JDC 3/28/22: + # This currently prevents a Composition that is nested within another to be tested on its own + # Would be good to figure out a way to accomodate that nested = False if len(self.input_CIM.path_afferents) > 0: nested = True @@ -9608,7 +10258,7 @@ def execute( # if execute was called from command line and no inputs were specified, # assign default inputs to highest level composition (i.e. not on any nested Compositions) if not inputs and not nested and ContextFlags.COMMAND_LINE in context.source: - inputs = self._validate_input_dict_node_roles({}) + inputs = self._instantiate_input_dict({}) # Skip initialization if possible (for efficiency): # - and(context has not changed # - structure of the graph has not changed @@ -9757,14 +10407,32 @@ def execute( # but node execution of nested compositions with # outside control is not supported yet. assert not nested or len(self.parameter_CIM.afferents) == 0 + elif nested: - # check that inputs are specified - autodiff does not in some cases - if ContextFlags.SIMULATION_MODE in context.runmode and inputs is not None: - self.input_CIM.execute(build_CIM_input, context=context) + + # MODIFIED 3/28/22 CURRENT: + # IMPLEMENTATION NOTE: context.string set in Mechanism.execute + direct_call = (f"{context.source.name} EXECUTING" not in context.string) + # MODIFIED 3/28/22 NEW: + # direct_call = (context.source == ContextFlags.COMMAND_LINE) + # MODIFIED 3/28/22 END + simulation = ContextFlags.SIMULATION_MODE in context.runmode + if simulation or direct_call: + # For simulations, or direct call to nested Composition (e.g., from COMMAND_LINE to test it) + # assign inputs if they not provided (e.g., # autodiff) + if inputs is not None: + self.input_CIM.execute(build_CIM_input, context=context) + else: + self.input_CIM.execute(context=context) else: - assert inputs is None, "Ignoring composition input!" + # regular run (DEFAULT_MODE) of nested Composition called from enclosing Composition, + # so inputs should be None, and be assigned from nested Composition's input_CIM + assert inputs is None,\ + f"Input provided to a nested Composition {self.name} in call from outer composition." self.input_CIM.execute(context=context) + self.parameter_CIM.execute(context=context) + else: self.input_CIM.execute(build_CIM_input, context=context) @@ -10259,101 +10927,180 @@ def __call__(self, *args, **kwargs): bad_args_str = ", ".join([str(arg) for arg in args] + list(kwargs.keys())) raise CompositionError(f"Composition ({self.name}) called with illegal argument(s): {bad_args_str}") - def get_inputs_format(self, **kwargs): + """Alias of get_input_format (easy mistake to make)""" return self.get_input_format(**kwargs, alias="get_inputs_format") - def get_input_format(self, num_trials:int=1, + def get_input_format(self, + form:Union[DICT,TEXT]=DICT, + num_trials:Union[int, FULL]=1, use_labels:bool=False, + use_names:bool=False, show_nested_input_nodes:bool=False, alias:str=None): - """Return str with format of dict used by **inputs** argument of `run ` method. + """Return dict or string with format of dict used by **inputs** argument of `run ` method. Arguments --------- - num_trials : int : default 1 - specifies number of trials' worth of inputs to included in format. + form : DICT or TEXT : default DICT + specifies the form in which the exampple is returned; DICT (the default) returns a dict (with + **num_trials** worth of default values for each `INPUT ` `Node `) + formatted for use as the **inputs** arg of the Compositon's `run ` method; + TEXT returns a user-readable text description of the format (optionally with inputs required for + `INPUT ` `Nodes ` of any `nested Compositions ` + (see **show_nested_input_nodes** below). + + num_trials : int or FULL : default 1 + specifies number of trials' worth of inputs to include in returned item. If *FULL* is specified, + **use_labels** is automatically set to True, and **num_trials** is set to number of labels in the + `input_label_dict ` with the largest number of labels specified; if + none of the `INPUT ` Mechanisms in the Composition (including any nested ones) have an + `input_label_dict ` specified, **num_trials** is set to the default (1). use_labels : bool : default False if True, shows labels instead of values for Mechanisms that have an `input_label_dict `. For **num_trials** = 1, a representative label is shown; for **num_trials** > 1, a different label is used for each trial shown, cycling - through the set if **num_trials** is greater than the number of labels. + through the set if **num_trials** is greater than the number of labels. If **num_trials = *FULL*, + trials will be included. + + it is set to the number of labels in the largest list specified in any `input_label_dict + ` specified for an `INPUT ` Mechanism; + + use_names : bool : default False + use `Node ` name as key for Node if **form** = DICT. show_nested_input_nodes : bool : default False - shows hierarchical display of `Nodes ` in `nested Compositions ` + show hierarchical display of `Nodes ` in `nested Compositions ` with names of destination `INPUT ` `Nodes ` and representative inputs, followed by the actual format used for the `run ` method. + + Returns + ------- + + Either a dict formatted appropriately for assignment as the **inputs** argument of the Composition's `run() + method (form = *DICT*, the default), or string showing the format required by the **inputs** argument + ` (form = *TEXT*). + """ if alias: warnings.warn(f"{alias} is aliased to get_input_format(); please use that in the future.") - def _get_inputs(comp, nesting_level=1, use_labels=False): + def _get_labels(labels_dict, index, input_port): + """Need index for InputPort, since owner Mechanism is not passed in.""" - input_format = '' + try: + return list(labels_dict[input_port.name].keys()) + except KeyError: + try: + return list(labels_dict[index].keys()) + except KeyError: + # Dict with no InputPort-specific subdicts, used to specify labels for all InputPorts of Mechanism + return list(labels_dict.keys()) + except: + assert False, f"PROGRAM ERROR: Unable to find labels for " \ + f"'{input_port.full_name}' of '{input_port.owner.name}'." + + def _get_inputs(comp, nesting_level=1, use_labels=False, template_dict=str): + + format_description_string = '' indent = '\t' * nesting_level + template_input_dict = {} + for node in comp.get_nodes_by_role(NodeRole.INPUT): - input_format += '\n' + indent + node.name + ': ' + node_inputs_for_format_string = [] + format_description_string += '\n' + indent + node.name + ': ' + node_inputs_for_template_dict = [] + node_key = node.name if use_names else node # Nested Compositions if show_nested_input_nodes and isinstance(node, Composition): - trials = _get_inputs(node, nesting_level=nesting_level + 1, use_labels=use_labels) + # No need for node_inputs_for_template_dict here as template_dict never contains nested_input_nodes + node_inputs_for_format_string = _get_inputs(node, + nesting_level=nesting_level + 1, + use_labels=use_labels) - # Nested Composition else: - trials = [] for t in range(num_trials): + inputs_for_format = [] + inputs_for_template_dict = [] # Mechanism with labels if use_labels and isinstance(node, Mechanism) and node.input_labels_dict: - input_values = [] - for i in range(len(node.input_values)): - label_dict = node.input_labels_dict[i] - labels = list(label_dict.keys()) - input_values.append(repr(labels[t % len(labels)])) - trial = f"[{','.join(input_values)}]" + labels_dict = node.input_labels_dict + + for i in range(len(node.external_input_shape)): + labels = _get_labels(labels_dict, i, node.input_ports[i]) + inputs_for_format.append(repr(labels[t % len(labels)])) + inputs_for_template_dict.append(labels[t % len(labels)]) + trial = f"[{','.join(inputs_for_format)}]" # Mechanism(s) with labels in nested Compositions elif (use_labels and isinstance(node, Composition) and any(n.input_labels_dict for n in node._get_nested_nodes_with_same_roles_at_all_levels(node, NodeRole.INPUT))): - input_values = [] - for i, port in enumerate(node.input_CIM.input_ports): - _, mech, __ = node.input_CIM._get_destination_node_for_input_port(port) + + for port in node.input_CIM.input_ports: + input_port, mech, __ = node.input_CIM._get_destination_info_from_input_CIM(port) labels_dict = mech.input_labels_dict if labels_dict: - labels = list(labels_dict[0].keys()) - input_values.append(repr([labels[t % len(labels)]])) + labels = _get_labels(labels_dict, mech.input_ports.index(input_port), input_port) + inputs_for_format.append(repr([labels[t % len(labels)]])) + inputs_for_template_dict.append([labels[t % len(labels)]]) else: - input_values.append(repr(np.array(mech.input_values).tolist())) - trial = f"[{','.join(input_values)}]" + inputs_for_template_dict.append(port.default_input_shape) + inputs_for_format.append(repr(np.array(port.default_input_shape).tolist())) + trial = f"[{','.join(inputs_for_format)}]" # No Mechanism(s) with labels or use_labels == False else: - trial = f"[{','.join([repr(i.tolist()) for i in node.input_values])}]" + inputs_for_template_dict = [port.default_input_shape for port in node.external_input_ports] + trial = f"[{','.join([repr(i.tolist()) for i in inputs_for_template_dict])}]" - trials.append(trial) + node_inputs_for_format_string.append(trial) + node_inputs_for_template_dict.append(inputs_for_template_dict) - trials = ', '.join(trials) + node_inputs_for_format_string = ', '.join(node_inputs_for_format_string) if num_trials > 1: - trials = f"[ {trials} ]" + node_inputs_for_format_string = f"[ {node_inputs_for_format_string} ]" - input_format += trials + format_description_string += node_inputs_for_format_string if not show_nested_input_nodes: - input_format += ',' - nesting_level -= 1 - return input_format - - formatted_input = _get_inputs(self, 1, use_labels) - if show_nested_input_nodes: - preface = f"\nInputs to (nested) INPUT Nodes of {self.name} for {num_trials} trials:" - epilog = f"\n\nFormat as follows for inputs to run():\n" \ - f"{self.get_input_format(num_trials=num_trials)}" - return preface + formatted_input[:-1] + epilog - return '{' + formatted_input[:-1] + '\n}' + format_description_string += ',' + template_input_dict[node_key]=node_inputs_for_template_dict + nesting_level -= 1 + if form == DICT: + return template_input_dict + else: + return format_description_string + + if num_trials == FULL: + num_trials = 1 + # Get number of labels in largest list of any input_labels_dict in an INPUT Mechanism + for node in self._get_nested_nodes_with_same_roles_at_all_levels(self, NodeRole.INPUT): + if node.input_labels_dict: + labels_dict = node.input_labels_dict + num_trials = max(num_trials, max([len(labels) for labels in labels_dict.values()])) + + # Return dict usable for run() + if form == DICT: + show_nested_input_nodes = False + return _get_inputs(self, 1, use_labels, form) + # Return text format + else: + formatted_input = _get_inputs(self, 1, use_labels) + if show_nested_input_nodes: + plural = 's' if num_trials > 1 else '' + preface = f"\nInputs to (nested) INPUT Nodes of {self.name} for {num_trials} trial{plural}:" + epilog = f"\n\nFormat as follows for inputs to run():\n" \ + f"{self.get_input_format(form=form, num_trials=num_trials)}" + return preface + formatted_input[:-1] + epilog + return '{' + formatted_input[:-1] + '\n}' + + # Aliases for get_results_by_node: def get_output_format(self, **kwargs): return self.get_results_by_nodes(**kwargs, alias="get_output_format") @@ -10410,13 +11157,13 @@ def get_results_by_nodes(self, warnings.warn(f"{alias} is aliased to get_results_by_nodes(); please use that in the future.") # Get all OUTPUT Nodes in (nested) Composition(s) - output_nodes = [self.output_CIM._get_source_node_for_output_port(port)[1] + output_nodes = [self.output_CIM._get_source_info_from_output_CIM(port)[1] for port in self.output_CIM.output_ports] # Get all values for all OUTPUT Nodes if use_labels: # Get labels for corresponding values - values = [node.output_labels for node in output_nodes] + values = [node.labeled_output_values for node in output_nodes] else: values = self.results[-1] or self.output_values @@ -10579,15 +11326,7 @@ def _build_variable_for_input_CIM(self, inputs): origin_node = origin_node.composition if origin_node in inputs: - # MODIFIED 12/19/21 OLD: value = inputs[origin_node][index] - # # MODIFIED 12/19/21 NEW: - # # MODIFIED 12/19/21 END - # if origin_node.input_labels_dict: - # labels = origin_node.input_labels_dict - # else: - # value = inputs[origin_node][index] - else: value = origin_node.defaults.variable[index] @@ -10716,6 +11455,27 @@ def _delete_contexts(self, *contexts, check_simulation_storage=False, visited=No except AttributeError: self.scheduler._delete_counts(c) + def _initialize_as_agent_rep(self, context, base_context, alt_controller=None): + assert self.controller is None or alt_controller is None + + _initialized = set() # avoid reinitializing shared dependencies below + self._initialize_from_context( + context, base_context=base_context, override=True, visited=_initialized + ) + if alt_controller is not None: + # evaluation will be done with a controller from another composition + alt_controller._initialize_from_context( + context, base_context=base_context, override=True, visited=_initialized + ) + + def _clean_up_as_agent_rep(self, context, alt_controller=None): + _deleted = set() # avoid traversing shared dependencies below + self._delete_contexts(context, visited=_deleted, check_simulation_storage=True) + if alt_controller is not None: + alt_controller._delete_contexts( + context, visited=_deleted, check_simulation_storage=True + ) + # endregion EXECUTION # ****************************************************************************************************************** @@ -10812,12 +11572,35 @@ def enable_logging(self): if param.loggable and param.log_condition is LogCondition.OFF: param.log_condition = LogCondition.EXECUTION - @property - def _dict_summary(self): - super_summary = super()._dict_summary + # endregion LLVM + + def as_mdf_model(self, simple_edge_format=True): + """Creates a ModECI MDF Model representing this Composition - nodes_dict = {MODEL_SPEC_ID_PSYNEULINK: {}} - projections_dict = {MODEL_SPEC_ID_PSYNEULINK: {}} + Args: + simple_edge_format (bool, optional): If True, Projections + with non-identity matrices are constructed as . Defaults to True. + + Returns: + modeci_mdf.Model: a ModECI Model representing this Composition + """ + import modeci_mdf.mdf as mdf + + def is_included_projection(proj): + included_types = ( + CompositionInterfaceMechanism, + LearningMechanism, + OptimizationControlMechanism, + ) + return ( + not isinstance(proj.sender.owner, included_types) + and not isinstance(proj.receiver.owner, included_types) + and not isinstance(proj, (AutoAssociativeProjection, ControlProjection)) + ) + nodes_dict = {} + projections_dict = {} + self_identifier = parse_valid_identifier(self.name) + metadata = self._mdf_metadata additional_projections = [] additional_nodes = ( @@ -10828,7 +11611,7 @@ def _dict_summary(self): for n in list(self.nodes) + additional_nodes: if not isinstance(n, CompositionInterfaceMechanism): - nodes_dict[n.name] = n._dict_summary + nodes_dict[parse_valid_identifier(n.name)] = n.as_mdf_model() # consider making this more general in the future try: @@ -10837,53 +11620,40 @@ def _dict_summary(self): pass for p in list(self.projections) + additional_projections: - has_cim_sender = isinstance( - p.sender.owner, - CompositionInterfaceMechanism - ) - has_cim_receiver = isinstance( - p.receiver.owner, - CompositionInterfaceMechanism - ) - - # filter projections to/from CIMs, unless they are to embedded - # compositions (any others should be automatically generated) - if ( - (not has_cim_sender or p.sender.owner.composition in self.nodes) - and ( - not has_cim_receiver - or p.receiver.owner.composition in self.nodes - ) - ): - p_summary = p._dict_summary + # filter projections to/from CIMs of this composition + # and projections to things outside this composition + if is_included_projection(p): + try: + pre_edge, edge_node, post_edge = p.as_mdf_model(simple_edge_format) + except TypeError: + edges = [p.as_mdf_model(simple_edge_format)] + else: + nodes_dict[edge_node.id] = edge_node + edges = [pre_edge, post_edge] + if 'excluded_node_roles' not in metadata[MODEL_SPEC_ID_METADATA]: + metadata[MODEL_SPEC_ID_METADATA]['excluded_node_roles'] = [] - if has_cim_sender: - p_summary[MODEL_SPEC_ID_SENDER_MECH] = p.sender.owner.composition.name + metadata[MODEL_SPEC_ID_METADATA]['excluded_node_roles'].append([edge_node.id, str(NodeRole.OUTPUT)]) - if has_cim_receiver: - p_summary[MODEL_SPEC_ID_RECEIVER_MECH] = p.receiver.owner.composition.name + for e in edges: + projections_dict[e.id] = e - projections_dict[p.name] = p_summary + metadata[MODEL_SPEC_ID_METADATA]['controller'] = self.controller.as_mdf_model() if self.controller is not None else None - if len(nodes_dict[MODEL_SPEC_ID_PSYNEULINK]) == 0: - del nodes_dict[MODEL_SPEC_ID_PSYNEULINK] + graph = mdf.Graph( + id=self_identifier, + conditions=self.scheduler.as_mdf_model(), + **self._mdf_model_parameters[self._model_spec_id_parameters], + **metadata + ) - if len(projections_dict[MODEL_SPEC_ID_PSYNEULINK]) == 0: - del projections_dict[MODEL_SPEC_ID_PSYNEULINK] + for _, node in nodes_dict.items(): + graph.nodes.append(node) - return { - MODEL_SPEC_ID_COMPOSITION: [{ - **super_summary, - **self.scheduler._dict_summary, - **{ - MODEL_SPEC_ID_NODES: nodes_dict, - MODEL_SPEC_ID_PROJECTIONS: projections_dict, - 'controller': self.controller, - } - }] - } + for _, proj in projections_dict.items(): + graph.edges.append(proj) - # endregion LLVM + return graph # ****************************************************************************************************************** # region ----------------------------------- PROPERTIES ------------------------------------------------------------ @@ -10945,29 +11715,75 @@ def runs_simulations(self): def simulation_results(self): return self.parameters.simulation_results.get(self.default_execution_id) - # For now, external_input_ports == input_ports and external_input_values == input_values - # They could be different in the future depending on new state_features (ex. if we introduce recurrent compositions) - # Useful to have this property for treating Compositions the same as Mechanisms in run & execute @property def external_input_ports(self): - """Returns all external InputPorts that belong to the Input CompositionInterfaceMechanism""" + """Return all external InputPorts that belong to the Input CompositionInterfaceMechanism""" try: return [input_port for input_port in self.input_CIM.input_ports if not input_port.internal_only] except (TypeError, AttributeError): return None + @property + def external_input_ports_of_all_input_nodes(self): + """Return all external InputPorts of all INPUT Nodes (including nested ones) of Composition. + Note: the InputPorts returned are those of the actual Mechanisms + to which the ones returned by external_input_ports ultimately project. + """ + try: + # return [self._get_destination(output_port.efferents[0])[0] + # for _,output_port in self.input_CIM.port_map.values()] + return self._get_input_receivers(comp=self, type=PORT, comp_as_node=False) + except (TypeError, AttributeError): + return None + + @property + def external_input_shape(self): + """Alias for _default_external_input_shape""" + return self._default_external_input_shape + + @property + def _default_external_input_shape(self): + """Return default_input_shape of all external InputPorts that belong to Input CompositionInterfaceMechanism""" + try: + return [input_port.default_input_shape for input_port in self.input_CIM.input_ports + # FIX: 2/4/22 - IS THIS NEEDED (HERE OR BELOW -- DO input_CIM.input_ports EVER GET ASSIGNED THIS? + if not input_port.internal_only] + except (TypeError, AttributeError): + return None + + @property + def external_input_variables(self): + """Return variables of all external InputPorts that belong to the Input CompositionInterfaceMechanism""" + try: + return [input_port.parameters.variable.get() + for input_port in self.input_CIM.input_ports if not input_port.internal_only] + except (TypeError, AttributeError): + return None + + @property + def default_external_input_variables(self): + """Return default variables of all external InputPorts that belong to the Input CompositionInterfaceMechanism + """ + + try: + return [input_port.defaults.variable for input_port in self.input_CIM.input_ports if + not input_port.internal_only] + except (TypeError, AttributeError): + return None + @property def external_input_values(self): - """Returns values of all external InputPorts that belong to the Input CompositionInterfaceMechanism""" + """Return values of all external InputPorts that belong to the Input CompositionInterfaceMechanism""" try: - return [input_port.value for input_port in self.input_CIM.input_ports if not input_port.internal_only] + # FIX: 2/4/22 SHOULD input_port.variable REPLACE input_port.value HERE? + return [input_port.parameters.value.get() + for input_port in self.input_CIM.input_ports if not input_port.internal_only] except (TypeError, AttributeError): return None @property def default_external_input_values(self): - """Return the default values of all external InputPorts that belong to the - Input CompositionInterfaceMechanism + """Return the default values of all external InputPorts that belong to the Input CompositionInterfaceMechanism """ try: @@ -11081,6 +11897,7 @@ def _all_nodes(self): # ****************************************************************************************************************** def show_graph(self, + show_all=False, show_node_structure=False, show_nested=NESTED, show_nested_args=ALL, @@ -11095,7 +11912,9 @@ def show_graph(self, active_items=None, output_fmt='pdf', context=None): - return self._show_graph(show_node_structure=show_node_structure, + + return self._show_graph(show_all=show_all, + show_node_structure=show_node_structure, show_nested=show_nested, show_nested_args=show_nested_args, show_cim=show_cim, @@ -11118,6 +11937,13 @@ def _animate_execution(self, active_items, context): # endregion SHOW_GRAPH + def make_likelihood_function(self, *args, **kwargs): + """ + This method invokes :func:`~psyneulink.core.components.functions.fitfunctions.make_likelihood_function` + on the composition. + """ + return make_likelihood_function(composition=self, *args, **kwargs) + def get_compositions(): """Return list of Compositions in caller's namespace.""" diff --git a/psyneulink/core/compositions/compositionfunctionapproximator.py b/psyneulink/core/compositions/compositionfunctionapproximator.py index 208dcbf4ac1..0623bb72ddb 100644 --- a/psyneulink/core/compositions/compositionfunctionapproximator.py +++ b/psyneulink/core/compositions/compositionfunctionapproximator.py @@ -27,10 +27,10 @@ A `CompositionFunctionApproximator` is an abstract subclass of `Composition` that, over calls to its `adapt ` method, parameterizes its `function ` to predict the `net_outcome ` of the Composition (or part of one) controlled by an -`OptimizationControlMechanism`, for a given set of `state_feature_values ` -and a `control_allocation ` provided by the OptimizationControlMechanism. -Its `evaluate ` method calls its `function -` to generate and return the predicted `net_outcome +`OptimizationControlMechanism`, for a given set of `state_feature_values +` and a `control_allocation ` +provided by the OptimizationControlMechanism. Its `evaluate ` method calls +its `function ` to generate and return the predicted `net_outcome ` for a given set of `state_feature_values `, `control_allocation `, `num_estimates `, and `num_trials_per_estimate @@ -54,8 +54,8 @@ """ from psyneulink.core.compositions.composition import Composition -from psyneulink.core.globals.keywords import COMPOSITION_FUNCTION_APPROXIMATOR from psyneulink.core.globals.context import Context +from psyneulink.core.globals.keywords import COMPOSITION_FUNCTION_APPROXIMATOR __all__ = ['CompositionFunctionApproximator'] diff --git a/psyneulink/core/compositions/parameterestimationcomposition.py b/psyneulink/core/compositions/parameterestimationcomposition.py index 339fc99cb67..0ab934d0fc2 100644 --- a/psyneulink/core/compositions/parameterestimationcomposition.py +++ b/psyneulink/core/compositions/parameterestimationcomposition.py @@ -52,7 +52,7 @@ attribute that it estimates best satisfy either of those conditions, and the results of running the `model ` with those parameters in its `results ` attribute. The arguments below are the primary ones used to configure a ParameterEstimationComposition for either -`ParameterEstimationComposition_Data_Fitting` or `ParameterEstimationComposition_Optimization`), followed by +`ParameterEstimationComposition_Data_Fitting` or `ParameterEstimationComposition_Optimization`, followed by sections that describe arguments specific to each. .. _ParameterEstimationComposition_Model: @@ -73,7 +73,7 @@ * **outcome_variables** - specifies the `OUTPUT` `Nodes ` of the `model `, the `values ` of which are used - to evaluate the fit of the different combination of parameter values sampled. + to evaluate the fit of the different combinations of parameter values sampled. * **num_estimates** - specifies the number of independent samples that are estimated for a given combination of parameter values. @@ -91,15 +91,15 @@ .. _ParameterEstimationComposition_Data: * **data** - specifies the data to which the `outcome_variables ` - are fit in the estimation process. They must be in a format that aligns the specification of - `outcome_variables `. + are fit in the estimation process. They must be in a format that aligns with the specification of + the `outcome_variables `. COMMENT: FIX: GET MORE FROM DAVE HERE COMMENT * **optimization_function** - specifies the function used to compare the `values ` of the `outcome_variables ` with the **data**, and search over values - of the `parameters ` that maximize the fit. This must be either + of the `parameters ` that maximize the fit. This must be either a `ParameterEstimationFunction` or a subclass of that. By default, ParameterEstimationFunction uses maximum likelihood estimation (MLE) to compare the `outcome_variables ` and the data, and @@ -118,8 +118,8 @@ * **objective_function** - specifies a function used to evaluate the `values ` of the `outcome_variables `, according to which combinations of `parameters ` are assessed. The shape of the `variable - ` of the `objective_function (i.e., its first positional argument) must be the same as an - array containing the `value ` of the OutputPort corresponding to each item specified in + ` of the **objective_function** (i.e., its first positional argument) must be the same as + an array containing the `value ` of the OutputPort corresponding to each item specified in `outcome_variables `. * **optimization_function** - specifies the function used to search over values of the `parameters @@ -259,7 +259,7 @@ class ParameterEstimationComposition(Composition): specifies the number of estimates made for a each combination of `parameter ` values (see `num_estimates ` for additional information); it is passed to the ParameterEstimationComposition's `controller ` to set its - `num_estimates ` Parameter. + `num_estimates ` Parameter. num_trials_per_estimate : int : default None specifies an exact number of trials to execute for each run of the `model diff --git a/psyneulink/core/compositions/showgraph.py b/psyneulink/core/compositions/showgraph.py index 7d3d1b208df..a4fbe76eb7c 100644 --- a/psyneulink/core/compositions/showgraph.py +++ b/psyneulink/core/compositions/showgraph.py @@ -42,16 +42,26 @@ `learning compnents `. These are listed as the arguments for the show_graph ` method below. -*Display attributes* -- state_features (such as the colors and shapes) in which different types of nodes are displayed -can be modified by assigning a dictionary of attribute:values pairs to the **show_graph_configuration** argument of the -Composition's constructor. These are listed as the arguments for the ShowGraph object (used to display the graph) -in the `class reference ` below. +*Display attributes* -- the colors, shapes and arrow styles used in the display can be modified using the +**show_graph_attributes** argument of a Composition's constructor, as described below. -COMMENT: +.. _ShowGraph_Attributes: + +*Display Attributes* +-------------------- + +The default attributes used to display different types of `Components ` and their `roles ` +within a Composition are listed below. These can be customized using the **show_graph_attributes** argument of a +Composition's constructor, in a dict with keys that are any of the parameters listed in `ShowGraph`, and values +that are any supported by `GraphViz `_ for +`shapes `_, +`arrow styles `_ +`colors `_. -The following are the default attribute used to display different types of `Components ` and their `roles -` within a Composition: +Shapes +~~~~~~ +COMMENT: FIX: MAKE FIGURE THAT HAS ALL THE VARIOUS TYPES USING CORRESPONDING NAMES Input Node Singleton Node @@ -60,12 +70,9 @@ ControlMechanism Controller Nested Composition +COMMENT - -Shapes -~~~~~~ - -`Nested Compositions `: square +`Nested Composition `: square `Mechanism`: - default: oval @@ -73,37 +80,38 @@ - `FEEDBACK_SENDER`: octagon - `CONTROLLER`: doubleoctagon -Projection: +`Projection`: - default: arrow - `ControlProjection`: box + - 'RANDOMIZATION_CONTROL_SIGNAL` : dashed line - `MappingProjection` that receives a `LearningProjection` when **show_learning** is True: diamond Colors ~~~~~~ +Component-types +^^^^^^^^^^^^^^^ + +- Control-related components: blue +- Controller-related: purple +- Learning-related components: orange +- Inactive Projection: red +- Active items (when **animate** = True in `run `): **BOLD** + Nodes ^^^^^ - `INPUT`: green - `OUTPUT`: red - `SINGLETON`: brown - -Component-types -^^^^^^^^^^^^^^^ - -Control-related compoments: blue -Controller-related: purple -Learning-related components: orange - -Active items (when **animate**=True in `run `): **BOLD** - -COMMENT + - `CONTROL`: blue + - `CONTROLLER` : purple + - `LEARNING` : orange .. _ShowGraph_Examples_Visualization: *Examples* ---------- - .. _Composition_show_graph_basic_figure: +-----------------------------------------------------------+----------------------------------------------------------+ @@ -201,7 +209,8 @@ from psyneulink.core.components.component import Component from psyneulink.core.components.mechanisms.modulatory.control.controlmechanism import ControlMechanism -from psyneulink.core.components.mechanisms.modulatory.control.optimizationcontrolmechanism import AGENT_REP +from psyneulink.core.components.mechanisms.modulatory.control.optimizationcontrolmechanism import \ + AGENT_REP, RANDOMIZATION_CONTROL_SIGNAL from psyneulink.core.components.mechanisms.processing.compositioninterfacemechanism import CompositionInterfaceMechanism from psyneulink.core.components.mechanisms.processing.objectivemechanism import ObjectiveMechanism from psyneulink.core.components.ports.outputport import OutputPort @@ -266,8 +275,10 @@ def __init__(self, error_value): class ShowGraph(): - """ - ShowGraph object with `show_graph ` method for displaying `Composition`. + """ShowGraph object with `show_graph ` method for displaying `Composition`. + + Every Composition is assigned a ShowGraph object, with its `show_graph ` method + assigned to, and callable as Composition.show_graph(). Arguments --------- @@ -303,7 +314,7 @@ class ShowGraph(): composition_shape : default 'rectangle' specifies the shape in which nodes that represent `nested Compositions ` are displayed when **show_nested** is specified as False or a `Composition is nested ` below the - level specified in a call to `show_graph `. + level specified in a call to `show_graph() `. agent_rep_shape : default 'egg' specifies the shape in which the `agent_rep` of an `OptimizationControlMechanism` is displayed. @@ -327,6 +338,9 @@ class ShowGraph(): input_color : keyword : default 'green', specifies the color in which `INPUT ` Nodes of the Composition are displayed. + probe_color : keyword : default 'pink', + specifies the color in which `PROBE ` Nodes of the Composition are displayed. + output_color : keyword : default 'red', specifies the color in which `OUTPUT ` Nodes of the Composition are displayed. @@ -352,7 +366,7 @@ class ShowGraph(): composition_color : keyword : default 'pink' specifies the color in which nodes that represent `nested Compositions are displayed when **show_nested** is specified as False or a `Composition is nested ` below the - level specified in a call to `show_graph `. + level specified in a call to `show_graph() `. inactive_projection_color : keyword : default 'red' specifies the color in which `Projections ` not active within the `Composition` are displayed, @@ -363,7 +377,7 @@ class ShowGraph(): active_thicker_by : int : default 2 specifies the amount by which to increase the width of the outline of Components specified in the - **active_items** argument of a call to `show_graph `. + **active_items** argument of a call to `show_graph() `. bold_width : int : default 3, specifies the width of the outline for `INPUT` and `OUTPUT` Nodes of the Composition. @@ -399,6 +413,7 @@ def __init__(self, default_node_color = 'black', active_color=BOLD, input_color='green', + probe_color='pink', output_color='red', input_and_output_color='brown', # feedback_color='yellow', @@ -437,6 +452,7 @@ def __init__(self, self.default_node_color = default_node_color self.active_color = active_color self.input_color = input_color + self.probe_color=probe_color self.output_color = output_color self.input_and_output_color = input_and_output_color # self.feedback_color = self.feedback_color @@ -459,6 +475,7 @@ def __init__(self, @tc.typecheck @handle_external_context(source=ContextFlags.COMPOSITION) def show_graph(self, + show_all:bool=False, show_node_structure:tc.any(bool, tc.enum(VALUES, LABELS, FUNCTIONS, MECH_FUNCTION_PARAMS, PORT_FUNCTION_PARAMS, ROLES, ALL))=False, show_nested:tc.optional(tc.any(bool,int,dict,tc.enum(NESTED, INSET)))=NESTED, @@ -474,9 +491,11 @@ def show_graph(self, active_items=None, output_fmt:tc.optional(tc.enum('pdf','gv','jupyter','gif'))='pdf', context=None, + *args, **kwargs): """ show_graph( \ + show_all=False, \ show_node_structure=False, \ show_nested=NESTED, \ show_nested_args=ALL, \ @@ -492,7 +511,8 @@ def show_graph(self, output_fmt='pdf', \ context=None) - Show graphical display of Components in a Composition's graph. + Show graphical display of Components in a Composition's graph. See `show_graph ` + for additional details. .. note:: This method relies on `graphviz `_, which must be installed and imported @@ -501,6 +521,10 @@ def show_graph(self, Arguments --------- + show_all : bool : default False + if False, defer to specification of all other arguments; if True, override all show_XXX arguments, + automatically specifying them with their most informative settings. + show_node_structure : bool, VALUES, LABELS, FUNCTIONS, MECH_FUNCTION_PARAMS, PORT_FUNCTION_PARAMS, ROLES, \ or ALL : default False show a detailed representation of each `Mechanism ` in the graph, including its `Ports `; @@ -574,7 +598,8 @@ def show_graph(self, show_projections_not_in_composition : bool : default False specifies whether or not to show `Projections ` that are not active in the current - `Composition`; these will display in red. This option is for use in debugging. + `Composition` (and, accordingly, are *not* listed in its `projections ` + attribute); these are shown in red. show_headers : bool : default True specifies whether or not to show headers in the subfields of a Mechanism's node; only takes effect if @@ -622,9 +647,7 @@ def show_graph(self, - ``source`` -- str with content of G.body """ - # MODIFIED 6/13/20 NEW: from psyneulink.core.compositions.composition import Composition - # MODIFIED 6/13/20 END composition = self.composition @@ -656,6 +679,16 @@ def show_graph(self, # ASSIGN ATTRIBUTES PASSED TO NESTED COMPOSITIONS ----------------------------------------------- + if show_all: + show_node_structure=ALL + show_nested=NESTED + show_nested_args=ALL + show_cim=True + show_controller=True + show_learning=ALL + show_headers=True + show_projections_not_in_composition=True + # Assign node_struct_arg based on show_node_structure ~~~~~~~~~~~~~~~~~~~~~~~~~ # Argument values used to call Mechanism._show_structure() if isinstance(show_node_structure, (list, tuple, set)): @@ -733,6 +766,7 @@ def show_graph(self, # BUILD GRAPH ------------------------------------------------------------------------ import graphviz as gv + self.style = 'solid' G = gv.Digraph( name=composition.name, @@ -760,6 +794,8 @@ def show_graph(self, # get all Nodes if output_fmt != 'gv': composition._analyze_graph(context=context) + if composition._need_check_for_unused_projections: + composition._check_for_unused_projections(context) rcvrs = list(processing_graph.keys()) for rcvr in rcvrs: @@ -899,6 +935,8 @@ def _assign_processing_components(self, nested_comp_graph.attr(color=self.input_and_output_color) elif rcvr in composition.get_nodes_by_role(NodeRole.INPUT): nested_comp_graph.attr(color=self.input_color) + elif rcvr in composition.get_nodes_by_role(NodeRole.PROBE): + nested_comp_graph.attr(color=self.probe_color) elif rcvr in composition.get_nodes_by_role(NodeRole.OUTPUT): nested_comp_graph.attr(color=self.output_color) nested_comp_graph.attr(label=rcvr_label) @@ -978,6 +1016,20 @@ def _assign_processing_components(self, rcvr_penwidth = str(self.bold_width) rcvr_rank = self.input_rank + # PROBE Node + elif rcvr in composition.get_nodes_by_role(NodeRole.PROBE): + if rcvr in active_items: + if self.active_color == BOLD: + rcvr_color = self.probe_color + else: + rcvr_color = self.active_color + rcvr_penwidth = str(self.bold_width + self.active_thicker_by) + composition.active_item_rendered = True + else: + rcvr_color = self.probe_color + rcvr_penwidth = str(self.bold_width) + rcvr_rank = self.output_rank + # OUTPUT Node elif rcvr in composition.get_nodes_by_role(NodeRole.OUTPUT): if rcvr in active_items: @@ -1096,7 +1148,8 @@ def _assign_cim_components(self, def _render_projection(_g, proj, sndr_label, rcvr_label, proj_color=self.default_node_color, - arrowhead=self.default_projection_arrow): + arrowhead=self.default_projection_arrow, + style=self.style): if any(item in active_items for item in {proj, proj.sender.owner}): if self.active_color == BOLD: color = proj_color @@ -1113,7 +1166,11 @@ def _render_projection(_g, proj, sndr_label, rcvr_label, else: label = '' - _g.edge(sndr_label, rcvr_label, label=label, color=color, penwidth=proj_width, arrowhead=arrowhead) + _g.edge(sndr_label, rcvr_label, + label=label, color=color, + penwidth=proj_width, + arrowhead=arrowhead, + style=style) for cim in composition.cims: @@ -1231,7 +1288,10 @@ def _render_projection(_g, proj, sndr_label, rcvr_label, sndr_output_node_proj_label = sndr_label # Render Projection - _render_projection(enclosing_g, proj, sndr_output_node_proj_label, rcvr_cim_proj_label, + _render_projection(enclosing_g, + proj, + sndr_output_node_proj_label, + rcvr_cim_proj_label, proj_color) # Projections from input_CIM to INPUT nodes @@ -1403,10 +1463,18 @@ def _render_projection(_g, proj, sndr_label, rcvr_label, else: ctl_proj_color = proj_color or self.control_color - arrowhead = self.default_projection_arrow if isinstance(proj, MappingProjection) else self.control_projection_arrow + if isinstance(proj, MappingProjection): + arrowhead = self.default_projection_arrow + else: + arrowhead = self.control_projection_arrow + + if RANDOMIZATION_CONTROL_SIGNAL in proj.sender.name: + style = 'dashed' + else: + style = self.style _render_projection(g, proj, sndr_param_cim_proj_label, rcvr_modulated_mec_proj_label, - proj_color=ctl_proj_color, arrowhead=arrowhead) + proj_color=ctl_proj_color, arrowhead=arrowhead, style=style) # OUTPUT_CIM ---------------------------------------------------------------------------- @@ -1424,6 +1492,11 @@ def _render_projection(_g, proj, sndr_label, rcvr_label, continue else: proj_color=self.inactive_projection_color + else: + port, node, comp = cim._get_source_info_from_output_CIM(proj.receiver) + if (node in comp.get_nodes_by_role(NodeRole.PROBE) + and not composition.include_probes_in_output): + proj_color=self.probe_color sndr_output_node_proj = proj.sender if (isinstance(sndr_output_node_proj.owner, CompositionInterfaceMechanism) @@ -1431,8 +1504,7 @@ def _render_projection(_g, proj, sndr_label, rcvr_label, sndr_output_node_proj_owner = sndr_output_node_proj.owner.composition else: sndr_output_node_proj_owner = sndr_output_node_proj.owner - # Validate the Projection is from an OUTPUT node - # or a PROBE node if allow_probes is set for a controller or its objective_mechanism + # Validate the Projection is from an OUTPUT or PROBE node if ((sndr_output_node_proj_owner in composition.nodes_to_roles and not any(role for role in {NodeRole.OUTPUT, NodeRole.PROBE} if role in composition.nodes_to_roles[sndr_output_node_proj_owner]))): @@ -1464,7 +1536,7 @@ def _render_projection(_g, proj, sndr_label, rcvr_label, sndr_output_node_proj_label = sndr_label rcvr_output_cim_proj_label = cim_label - # FIX 6/23/20 PROBLEM POINT: + # FIX 6/23/20 PROBLEM POINT: (SEE MESSAGE FOR COMMIT eb61303808ad2a5ba46fdd18d0e583283397915c) # Render Projection _render_projection(g, proj, @@ -1483,7 +1555,6 @@ def _render_projection(_g, proj, sndr_label, rcvr_label, continue else: proj_color=self.inactive_projection_color - rcvr_node_input_port = proj.receiver # Skip if receiver is controller of enclosing_comp (handled by _assign_controller_components) @@ -1568,10 +1639,10 @@ def _assign_controller_components(self, f"so \'show_controller\' option in call to its show_graph() method will be ignored.") return + # Assign colors, penwidth and label displayed for controller and ControlProjections --------------------- + ctlr_color = self.controller_color if controller in active_items: - if self.active_color == BOLD: - ctlr_color = self.controller_color - else: + if self.active_color != BOLD: ctlr_color = self.active_color ctlr_width = str(self.default_width + self.active_thicker_by) composition.active_item_rendered = True @@ -1579,6 +1650,15 @@ def _assign_controller_components(self, ctlr_color = self.controller_color ctlr_width = str(self.default_width) + ctl_proj_color = self.controller_color + if controller in active_items: + if self.active_color != BOLD: + ctl_proj_color = self.active_color + ctl_proj_width = str(self.default_width + self.active_thicker_by) + composition.active_item_rendered = True + else: + ctl_proj_width = str(self.default_width) + # Assign controller node node_shape = self.mechanism_shape ctlr_label = self._get_graph_node_label(composition, controller, show_types, show_dimensions) @@ -1613,10 +1693,10 @@ def _assign_controller_components(self, ctl_proj_rcvr = ctl_proj.receiver # If receiver is a parameter_CIM if isinstance(ctl_proj_rcvr.owner, CompositionInterfaceMechanism): - # PATCH 6/7/20 to deal with ControlProjections across more than one level of nesting: + # Deal with ControlProjections across more than one level of nesting: rcvr_comp = ctl_proj_rcvr.owner.composition def find_rcvr_comp(r, c, l): - """Find deepest enclosing composition within range of num_nesting_levels""" + """Find deepest Composition within c that encloses r within range of num_nesting_levels of c""" if (self.num_nesting_levels is not None and l > self.num_nesting_levels): return c, l elif r in c.nodes: @@ -1644,26 +1724,17 @@ def find_rcvr_comp(r, c, l): rcvr_comp = enclosing_comp else: rcvr_comp = enclosing_comp - # PATCH 6/6/20 END - # PATCH 6/6/20: # if show_cim and show_nested is NESTED: if show_cim and project_to_node: - # PATCH 6/6/20 END # Use Composition's parameter_CIM port ctl_proj_rcvr_owner = ctl_proj_rcvr.owner - # PATCH 6/6/20: - # elif show_nested is NESTED: elif project_to_node: - # PATCH 6/6/20 END ctl_proj_rcvr = self._trace_receivers_for_terminal_receiver(ctl_proj_rcvr) ctl_proj_rcvr_owner = ctl_proj_rcvr.owner else: # Use Composition if show_cim is False - # PATCH 6/6/20: - # ctl_proj_rcvr_owner = ctl_proj_rcvr.owner.composition ctl_proj_rcvr_owner = rcvr_comp - # PATCH 6/6/20 END # In all other cases, use Port (either ParameterPort of a Mech, or parameter_CIM for nested comp) else: ctl_proj_rcvr_owner = ctl_proj_rcvr.owner @@ -1687,29 +1758,24 @@ def find_rcvr_comp(r, c, l): ctl_proj_sndr_label = ctlr_label ctl_proj_rcvr_label = rcvr_label - # Assign colors, penwidth and label displayed for ControlProjection --------------------- - if controller in active_items: - if self.active_color == BOLD: - ctl_proj_color = self.controller_color - else: - ctl_proj_color = self.active_color - ctl_proj_width = str(self.default_width + self.active_thicker_by) - composition.active_item_rendered = True - else: - ctl_proj_color = self.controller_color - ctl_proj_width = str(self.default_width) if show_projection_labels: edge_label = ctl_proj.name else: edge_label = '' + if RANDOMIZATION_CONTROL_SIGNAL in ctl_proj.sender.name: + style = 'dashed' + else: + style = self.style + # Construct edge ----------------------------------------------------------------------- g.edge(ctl_proj_sndr_label, ctl_proj_rcvr_label, label=edge_label, color=ctl_proj_color, penwidth=ctl_proj_width, - arrowhead=ctl_proj_arrowhead + arrowhead=ctl_proj_arrowhead, + style = style ) # If controller has objective_mechanism, assign its node and Projections, @@ -1776,6 +1842,14 @@ def find_rcvr_comp(r, c, l): # incoming edges (from monitored mechs to objective mechanism) for input_port in objmech.input_ports: for projection in input_port.path_afferents: + # MODIFIED 1/6/22 NEW: + # Get nested source node for direct projection to objective mechanism + if isinstance(projection.sender.owner, CompositionInterfaceMechanism) and not show_cim: + cim_output_port = projection.sender + proj_sndr, node, comp = cim_output_port.owner._get_source_info_from_output_CIM(cim_output_port) + else: + proj_sndr = projection.sender + # MODIFIED 1/6/22 END if objmech in active_items: if self.active_color == BOLD: proj_color = self.controller_color @@ -1788,12 +1862,15 @@ def find_rcvr_comp(r, c, l): proj_width = str(self.default_width) if show_node_structure: sndr_proj_label = self._get_graph_node_label(composition, - projection.sender.owner, + proj_sndr.owner, show_types, show_dimensions) - if projection.sender.owner not in composition.nodes: + if (proj_sndr.owner not in composition.nodes + # MODIFIED 1/6/22 NEW: + and isinstance(proj_sndr.owner, CompositionInterfaceMechanism)): + # MODIFIED 1/6/22 END num_nesting_levels = self.num_nesting_levels or 0 - nested_comp = projection.sender.owner.composition + nested_comp = proj_sndr.owner.composition try: nesting_depth = next((k for k, v in comp_hierarchy.items() if v == nested_comp)) sender_visible = nesting_depth <= num_nesting_levels @@ -1802,11 +1879,11 @@ def find_rcvr_comp(r, c, l): else: sender_visible = True if sender_visible: - sndr_proj_label += ':' + objmech._get_port_name(projection.sender) + sndr_proj_label += ':' + objmech._get_port_name(proj_sndr) objmech_proj_label = objmech_label + ':' + objmech._get_port_name(input_port) else: sndr_proj_label = self._get_graph_node_label(composition, - projection.sender.owner, + proj_sndr.owner, show_types, show_dimensions) objmech_proj_label = self._get_graph_node_label(composition, @@ -1825,17 +1902,12 @@ def find_rcvr_comp(r, c, l): # incoming edges (from monitored mechs directly to controller) for outcome_input_port in controller.outcome_input_ports: for projection in outcome_input_port.path_afferents: - if controller in active_items: - if self.active_color == BOLD: - proj_color = self.controller_color - else: - proj_color = self.active_color - proj_width = str(self.default_width + self.active_thicker_by) - composition.active_item_rendered = True - else: - proj_color = self.controller_color - proj_width = str(self.default_width) - if show_node_structure: + # MODIFIED 1/6/22 NEW: + # Handled by _assign_cim_components() + if isinstance(projection.sender.owner, CompositionInterfaceMechanism) and not show_cim: + continue + # MODIFIED 1/6/22 END + if show_node_structure and show_cim: sndr_proj_label = self._get_graph_node_label(composition, projection.sender.owner, show_types, @@ -1868,7 +1940,8 @@ def find_rcvr_comp(r, c, l): else: edge_label = '' g.edge(sndr_proj_label, ctlr_input_proj_label, label=edge_label, - color=proj_color, penwidth=proj_width) + # color=proj_color, penwidth=proj_width) + color=ctl_proj_color, penwidth=ctl_proj_width) # If controller has an agent_rep, assign its node and edges (not Projections per se) if hasattr(controller, 'agent_rep') and controller.agent_rep and show_controller==AGENT_REP : @@ -1896,12 +1969,18 @@ def find_rcvr_comp(r, c, l): g.edge(agent_rep_label, ctlr_label, color=agent_rep_color, penwidth=agent_rep_width) g.edge(ctlr_label, agent_rep_label, color=agent_rep_color, penwidth=agent_rep_width) - # get any other incoming edges to controller (i.e., other than from ObjectiveMechanism) + # get any state_feature projections and any other incoming edges to controller senders = set() # FIX: 11/3/21 - NEED TO MODIFY ONCE OUTCOME InputPorts ARE MOVED for i in controller.input_ports[controller.num_outcome_input_ports:]: for p in i.path_afferents: - senders.add(p.sender.owner) + # MODIFIED 1/6/22 NEW: + sender = p.sender.owner + if isinstance(sender, CompositionInterfaceMechanism) and not show_cim: + pass # FIX: 1/6/22 - PLACEMARKER FOR RELABELING INPUT_CIM AS SHADOWING INPUT OF SHADOWED NODE + assert True + # MODIFIED 1/6/22 END + senders.add(sender) self._assign_incoming_edges(g, controller, ctlr_label, @@ -2132,7 +2211,7 @@ def _assign_incoming_edges(self, and isinstance(proj.sender.owner, CompositionInterfaceMechanism) and proj.sender.owner in {composition.input_CIM, composition.parameter_CIM})]) senders.update(cims) - # HACK: FIX 6/13/20 - ADD USER-SPECIFIED TARGET NODE FOR INNER COMOSITION (NOT IN processing_graph) + # HACK: FIX 6/13/20 - ADD USER-SPECIFIED TARGET NODE FOR INNER COMPOSITION (NOT IN processing_graph) def assign_sender_edge(sndr:Union[Mechanism, Composition], proj_color:str, proj_arrowhead:str @@ -2303,7 +2382,7 @@ def assign_sender_edge(sndr:Union[Mechanism, Composition], if not sender.afferents and rcvr is not composition.controller: continue # FIX: LOOP HERE OVER sndr_spec IF THERE ARE SEVERAL - # Get node(s) from enclosing Comopsition that is/are source(s) of sender(s) + # Get node(s) from enclosing Composition that is/are source(s) of sender(s) sndrs_specs = self._trace_senders_for_original_sender_mechanism(proj, nesting_level) if not sndrs_specs: continue @@ -2314,11 +2393,15 @@ def assign_sender_edge(sndr:Union[Mechanism, Composition], enclosing_comp = comp_hierarchy[sndr_nesting_level] enclosing_g = enclosing_comp._show_graph.G # Skip: - # - cims as sources (handled in _assign_cim_componoents) + # - cims as sources (handled in _assign_cim_components) + # unless it is the input_CIM for the outermost Composition and show_cim is not true # - controller (handled in _assign_controller_components) if (isinstance(sndr, CompositionInterfaceMechanism) and rcvr is not enclosing_comp.controller and rcvr is not composition.controller + # MODIFIED 1/6/22 NEW: + and not sndr.afferents and show_cim + # MODIFIED 1/6/22 END or self._is_composition_controller(sndr, enclosing_comp)): continue if sender is composition.parameter_CIM: @@ -2506,7 +2589,12 @@ def _trace_senders_for_original_sender_mechanism(self, nesting_level -= 1 num_afferents = len(owner.port_map[proj.receiver][0].path_afferents) if num_afferents == 0: + # MODIFIED 1/6/22 OLD: return None + # # MODIFIED 1/6/22 NEW: + # # Presumably outermost Composition, so return CIM itself + # return [(owner, sender, nesting_level)] + # MODIFIED 1/6/22 END # # FIX: ITERATE OVER ALL AFFERENTS TO relevant InputPort of cim: # # MODIFIED 4/5/21 OLD: # outer_proj = owner.port_map[proj.receiver][0].path_afferents[0] @@ -2519,6 +2607,10 @@ def _trace_senders_for_original_sender_mechanism(self, sndrs = enclosing_showgraph._trace_senders_for_original_sender_mechanism(outer_proj, nesting_level) if sndrs is not None: senders.extend(sndrs) + # MODIFIED 1/6/22 NEW: + else: + senders.append((outer_proj.sender.owner, sender, nesting_level)) + # MODIFIED 1/6/22 END return senders # MODIFIED 4/5/21 END # FIX: RECEIVERS OF THIS RETURN NEED TO HANDLE LIST diff --git a/psyneulink/core/globals/context.py b/psyneulink/core/globals/context.py index a9a52284d63..250ff7bf63b 100644 --- a/psyneulink/core/globals/context.py +++ b/psyneulink/core/globals/context.py @@ -498,7 +498,7 @@ def add_to_string(self, string): if self.string is None: self.string = string else: - self.string = '{0} {1} {2}'.format(self.string, SEPARATOR_BAR, string) + self.string = f'{self.string} {SEPARATOR_BAR} {string}' def _change_flags(self, *flags, operation=lambda attr, blank_flag, *flags: NotImplemented): # split by flag type to avoid extra costly binary operations on enum flags diff --git a/psyneulink/core/globals/json.py b/psyneulink/core/globals/json.py index 9f7dcc39571..4c598cc8c4d 100644 --- a/psyneulink/core/globals/json.py +++ b/psyneulink/core/globals/json.py @@ -16,26 +16,29 @@ The developers of PsyNeuLink are collaborating with the scientific community, as part of the `OpenNeuro effort `_, to create a standard, JSON-based format for the description and exchange of computational models of brain and psychological function across different simulation environments. As part of this effort, -PsyNeuLink includes the ability to export models into, and import valid Python scripts that express a PsyNeuLink -model from this JSON format. +PsyNeuLink supports the `ModECI Model Description Format `_ (MDF) by +including the ability to produce an MDF-compatible model from a PsyNeuLink model and to construct valid Python +scripts that express a PsyNeuLink model from an MDF model. -Any PsyNeuLink `Composition` or `Component` can be exported to the JSON format using its `json_summary` method, that -uses its `_dict_summary `. This generates a string that, passed into the +Any PsyNeuLink `Composition` or `Component` can be exported to MDF format using its `as_mdf_model` method or +to JSON format using its `json_summary` method. `json_summary` generates a string that, passed into the `generate_script_from_json` function, produces a valid Python script replicating the original PsyNeuLink model. `write_json_file` can be used to write the json_summary for one or more Compositions into a specified file (though see `note `). `generate_script_from_json` can accept either the string returned by `generate_script_from_json` or the name of a file containing one. Calling ``exec(generate_script_from_json())`` will load into the current namespace all of the PsyNeuLink objects specified in the ``input``; and `get_compositions` can be used to retrieve a list of all of the Compositions -in that namespace, including any generated by execution of `generate_script_from_json`. +in that namespace, including any generated by execution of `generate_script_from_json`. `generate_script_from_mdf` +may similarly be used to create a PsyNeuLink Python script from a ModECI MDF Model object, such as that created +by `as_mdf_model `. .. _JSON_Security_Warning: .. warning:: - Use of `generate_script_from_json` to generate a Python script from a file without taking proper precautions can + Use of `generate_script_from_json` or `generate_script_from_mdf` to generate a Python script from a file without taking proper precautions can introduce a security risk to the system on which the Python interpreter is running. This is because it calls exec, which has the potential to execute non-PsyNeuLink-related code embedded in the file. Therefore, - `generate_script_from_json` should be used to read only files of known and secure origin. + `generate_script_from_json` or `generate_script_from_mdf` should be used to read only files of known and secure origin. .. _JSON_Examples: @@ -54,156 +57,48 @@ .. _JSON_Model_Specification: -JSON Model Specification +JSON/MDF Model Specification ------------------------ .. note:: - The JSON format is in early development, and is subject to change. + The format is in development, and is subject to change. - -The outermost level of a JSON model is a dictionary with entry ``graphs``, a list of Composition objects. - -Each Component's JSON object contains multiple entries. Those that are common to all are: - -* ``name`` : a label for the Component - -* ``parameters`` (non-`Function`\\ s) / ``args`` (`Function`\\ s) : a dictionary where each entry is either a - `Parameter` name and value, or a subdictionary of modeling-environment specific parameters. For PsyNeuLink, - this is indicated by `PNL`: - - -.. code-block:: javascript - - "args": { - "PNL": { - "execution_count": 0, - "has_initializers": false, - "variable": [ - 0.01 - ] - }, - "bounds": null, - "intercept": 0.0, - "slope": 1.0 - } - -Note that the value of a parameter may be a long-form dictionary when it corresponds to a `ParameterPort`. -In this case, it will indicate the ParameterPort in a `source<>` field: - -.. code-block:: javascript - - "intercept": { - "source": "A.input_ports.intercept", - "type": "float", - "value": 2.0 - } - -* ``type`` : a dictionary with entries based on modeling environment to describe the type of the object. - The `generic` entry is populated if the object has a universal name (such as a linear function). - Modeling-environment-specific entries are populated when relevant. - -.. code-block:: javascript - - "type": { - "PNL": "Composition", - "generic": "graph" - } - - -**Mechanisms**, **Projections**, and **Ports** each have: - -* ``functions`` : a list of primary `Function` JSON objects. In \ -PsyNeuLink, only one primary function is allowed. - -.. code-block:: javascript - - "functions": [ - { - "args": { - "intercept": { - "source": "A.input_ports.intercept", - "type": "float", - "value": 2.0 - }, - "slope": { - "source": "A.input_ports.slope", - "type": "float", - "value": 5.0 - } - }, - "name": "Linear Function-1", - "type": { - "generic": "Linear" - } - } - ] - -**Mechanisms** have: - -* ``input_ports`` : a list of InputPort and ParameterPort JSON objects - -* ``output_ports`` : a list of OutputPort JSON objects - -**Projections** have: - -* ``sender`` : the name of the Component it projects from - -* ``sender_port`` : the name of the port on the ``sender`` to which it \ -connects - -* ``receiver`` : the name of the Component it projects to - -* ``receiver_port`` : the name of the port on the ``receiver`` to \ -which it connects - -**Ports** have: - -* ``dtype`` : the type of accepted input/output for the Port. This \ -corresponds to `numpy.dtype `_ - -* ``shape`` : the shape of the accepted input/output. This corresponds \ -to numpy ndarray shapes. (`numpy.zeros()` would produce an \ -array with the correct shape) - -**Compositions** have: - -* ``nodes`` : a dictionary of Mechanisms or Compositions keyed on \ -their names that are part of the Composition - -* ``edges`` : a dictionary of Projections keyed on their names that \ -connect nodes of the Composition - -* ``controller`` : the name of the Mechanism in the Composition's \ -nodes that serves as the Composition's \ -`controller `, if it exists +See https://github.com/ModECI/MDF/blob/main/docs/README.md#model """ -import abc +import ast import base64 import binascii +import copy import dill import enum +import graph_scheduler +import inspect import json +import math +import numbers import numpy import pickle +import pint import psyneulink import re import types +import warnings from psyneulink.core.globals.keywords import \ MODEL_SPEC_ID_COMPOSITION, MODEL_SPEC_ID_GENERIC, MODEL_SPEC_ID_NODES, MODEL_SPEC_ID_PARAMETER_SOURCE, \ - MODEL_SPEC_ID_PARAMETER_VALUE, MODEL_SPEC_ID_PROJECTIONS, MODEL_SPEC_ID_PSYNEULINK, MODEL_SPEC_ID_RECEIVER_MECH, \ - MODEL_SPEC_ID_SENDER_MECH, MODEL_SPEC_ID_TYPE + MODEL_SPEC_ID_PARAMETER_INITIAL_VALUE, MODEL_SPEC_ID_PARAMETER_VALUE, MODEL_SPEC_ID_PROJECTIONS, MODEL_SPEC_ID_PSYNEULINK, MODEL_SPEC_ID_RECEIVER_MECH, MODEL_SPEC_ID_RECEIVER_PORT, \ + MODEL_SPEC_ID_SENDER_MECH, MODEL_SPEC_ID_SENDER_PORT, MODEL_SPEC_ID_TYPE, MODEL_SPEC_ID_OUTPUT_PORTS, MODEL_SPEC_ID_MDF_VARIABLE, MODEL_SPEC_ID_INPUT_PORTS, MODEL_SPEC_ID_SHAPE, MODEL_SPEC_ID_METADATA, MODEL_SPEC_ID_INPUT_PORT_COMBINATION_FUNCTION +from psyneulink.core.globals.parameters import ParameterAlias from psyneulink.core.globals.sampleiterator import SampleIterator -from psyneulink.core.globals.utilities import convert_to_list, get_all_explicit_arguments, \ - parse_string_to_psyneulink_object_string, parse_valid_identifier, safe_equals +from psyneulink.core.globals.utilities import convert_to_list, gen_friendly_comma_str, get_all_explicit_arguments, \ + parse_string_to_psyneulink_object_string, parse_valid_identifier, safe_equals, convert_to_np_array __all__ = [ 'PNLJSONError', 'JSONDumpable', 'PNLJSONEncoder', - 'generate_script_from_json', + 'generate_json', 'generate_script_from_json', 'generate_script_from_mdf', 'write_json_file' ] @@ -213,16 +108,13 @@ class PNLJSONError(Exception): class JSONDumpable: - @property - @abc.abstractmethod - def _dict_summary(self): - pass - @property def json_summary(self): - return _dump_pnl_json_from_dict(self._dict_summary) + return self.as_mdf_model().to_json() +# leaving this due to instructions in test_documentation_models +# (useful for exporting Composition results to JSON) class PNLJSONEncoder(json.JSONEncoder): """ A `JSONEncoder @@ -231,6 +123,7 @@ class PNLJSONEncoder(json.JSONEncoder): into a more JSON-friendly format. """ def default(self, o): + import modeci_mdf.mdf as mdf from psyneulink.core.components.component import Component, ComponentsMeta if isinstance(o, ComponentsMeta): @@ -259,55 +152,141 @@ def default(self, o): return list(o) elif isinstance(o, numpy.random.RandomState): return f'numpy.random.RandomState({o.seed})' - else: - try: - # convert numpy number type to python type - return o.item() - except AttributeError: - pass + elif isinstance(o, numpy.number): + return o.item() + elif isinstance(o, mdf.BaseWithId): + return json.loads(o.to_json()) - return super().default(o) + try: + return super().default(o) + except TypeError: + return str(o) -def _dump_pnl_json_from_dict(dict_summary): - return json.dumps( - dict_summary, - sort_keys=True, - indent=4, - separators=(',', ': '), - cls=PNLJSONEncoder - ) +def _get_variable_parameter_name(obj): + try: + if obj.parameters.variable.mdf_name is not None: + return obj.parameters.variable.mdf_name + except AttributeError: + pass + + return MODEL_SPEC_ID_MDF_VARIABLE + + +def _substitute_expression_args(model): + # currently cannot use args with value expressions + if model.value is not None: + for arg, val in model.args.items(): + model.value = model.value.replace(arg, str(val)) def _parse_component_type(component_dict): - type_dict = component_dict[MODEL_SPEC_ID_TYPE] + def get_pnl_component_type(s): + from psyneulink.core.components.component import ComponentsMeta - try: - type_str = type_dict[MODEL_SPEC_ID_PSYNEULINK] - except KeyError: - # catch error outside of this function if necessary - type_str = type_dict[MODEL_SPEC_ID_GENERIC] + try: + return getattr(psyneulink, s) + except AttributeError: + for o in dir(psyneulink): + if s.lower() == o.lower(): + o = getattr(psyneulink, o) + if isinstance(o, ComponentsMeta): + return o + # if matching component not found, raise original exception + raise + + type_str = None + if MODEL_SPEC_ID_TYPE in component_dict: + type_dict = component_dict[MODEL_SPEC_ID_TYPE] + else: + try: + type_dict = component_dict[MODEL_SPEC_ID_METADATA][MODEL_SPEC_ID_TYPE] + except KeyError: + # specifically for functions the keyword is not 'type' + type_str = component_dict['function'] + + if type_str is None: + try: + type_str = type_dict[MODEL_SPEC_ID_PSYNEULINK] + except KeyError: + # catch error outside of this function if necessary + type_str = type_dict[MODEL_SPEC_ID_GENERIC] + except TypeError: + # actually a str + type_str = type_dict + elif isinstance(type_str, dict): + if len(type_str) != 1: + raise PNLJSONError + else: + elem = list(type_str.keys())[0] + # not a function_type: args dict + if MODEL_SPEC_ID_METADATA in type_str[elem]: + raise PNLJSONError + else: + type_str = elem try: # gets the actual psyneulink type (Component, etc..) from the module - return getattr(psyneulink, type_str) - except AttributeError as e: - raise PNLJSONError( - 'Invalid PsyNeuLink type specified for JSON object: {0}'.format( - component_dict - ) - ) from e + return get_pnl_component_type(type_str) + except (AttributeError, TypeError): + pass + + try: + from modeci_mdf.functions.standard import mdf_functions + mdf_functions[type_str]['function'] + # remove import/module errors when modeci_mdf is a package + except (ImportError, KeyError, ModuleNotFoundError): + pass + else: + return f"modeci_mdf.functions.standard.mdf_functions['{type_str}']['function']" + + try: + getattr(math, type_str) + except (AttributeError, TypeError): + pass + else: + return f'math.{type_str}' + + try: + eval(type_str) + except (TypeError, SyntaxError): + pass + except NameError: + return type_str + else: + return type_str + raise PNLJSONError( + 'Invalid type specified for JSON object: {0}'.format( + component_dict + ) + ) -def _parse_parameter_value(value, component_identifiers=None): + +def _parse_parameter_value(value, component_identifiers=None, name=None, parent_parameters=None): if component_identifiers is None: component_identifiers = {} exec('import numpy') + try: + pnl_type = _parse_component_type(value) + except (KeyError, TypeError, PNLJSONError): + # ignore parameters that aren't components + pnl_type = None if isinstance(value, list): - value = [_parse_parameter_value(x, component_identifiers) for x in value] - value = f"[{', '.join([str(x) for x in value])}]" + new_val = [_parse_parameter_value(x, component_identifiers, name, parent_parameters) for x in value] + + # check for ParameterPort spec + if ( + len(value) == 2 + and isinstance(value[0], (numbers.Number, numpy.ndarray)) + and isinstance(value[1], dict) + ): + # make tuple instead of list + value = f"({', '.join([str(x) for x in new_val])})" + else: + value = f"[{', '.join([str(x) for x in new_val])}]" elif isinstance(value, dict): if ( MODEL_SPEC_ID_PARAMETER_SOURCE in value @@ -325,7 +304,9 @@ def _parse_parameter_value(value, component_identifiers=None): value = _parse_parameter_value( value[MODEL_SPEC_ID_PARAMETER_VALUE], - component_identifiers + component_identifiers, + name, + parent_parameters, ) # handle tuples and numpy arrays, which both are dumped @@ -336,12 +317,49 @@ def _parse_parameter_value(value, component_identifiers=None): value = f'({value[1:-1]})' elif value_type is numpy.ndarray: value = f'{value[MODEL_SPEC_ID_TYPE]}({value})' - + elif MODEL_SPEC_ID_PARAMETER_INITIAL_VALUE in value: + # is a stateful parameter with initial value + value = _parse_parameter_value( + value[MODEL_SPEC_ID_PARAMETER_INITIAL_VALUE], + component_identifiers, + name, + parent_parameters + ) + elif MODEL_SPEC_ID_PARAMETER_VALUE in value and pnl_type is None: + # is a standard mdf Parameter class with value + value = _parse_parameter_value( + value[MODEL_SPEC_ID_PARAMETER_VALUE], + component_identifiers, + name, + parent_parameters + ) else: # it is either a Component spec or just a plain dict try: # try handling as a Component spec - identifier = parse_valid_identifier(value['name']) + try: + comp_name = value['name'] + except KeyError: + comp_name = name + + if comp_name is not None: + identifier = parse_valid_identifier(comp_name) + if len(value) == 1: + try: + value = value[comp_name] + except KeyError: + pass + else: + if len(value) == 1: + comp_name = list(value.keys())[0] + identifier = parse_valid_identifier(comp_name) + if isinstance(value[comp_name], dict): + value = value[comp_name] + else: + raise PNLJSONError( + f'Component without name could reference multiple objects: {value}', + ) + if ( identifier in component_identifiers and component_identifiers[identifier] @@ -352,21 +370,30 @@ def _parse_parameter_value(value, component_identifiers=None): else: value = _generate_component_string( value, - component_identifiers + component_identifiers, + component_name=comp_name, + parent_parameters=parent_parameters ) - except (PNLJSONError, KeyError): + except (PNLJSONError, KeyError, TypeError): # standard dict handling value = '{{{0}}}'.format( ', '.join([ '{0}: {1}'.format( - str(_parse_parameter_value(k, component_identifiers)), - str(_parse_parameter_value(v, component_identifiers)) + str(_parse_parameter_value(k, component_identifiers, name)), + str(_parse_parameter_value(v, component_identifiers, name)) ) for k, v in value.items() ]) ) elif isinstance(value, str): + # handle pointer to parent's parameter value + try: + return _parse_parameter_value(parent_parameters[value]) + except (KeyError, TypeError): + pass + + # handle reference to psyneulink object obj_string = parse_string_to_psyneulink_object_string(value) if obj_string is not None: return f'psyneulink.{obj_string}' @@ -399,6 +426,20 @@ def _parse_parameter_value(value, component_identifiers=None): if identifier in component_identifiers: value = identifier + try: + psyneulink._unit_registry.Unit(value) + except (AttributeError, TypeError, ValueError, pint.errors.DefinitionSyntaxError): + pass + else: + value = f"'{value}'" + + try: + psyneulink._unit_registry.Quantity(value) + except (AttributeError, TypeError, ValueError, pint.errors.DefinitionSyntaxError): + pass + else: + value = f"'{value}'" + evaluates = False try: eval(value) @@ -423,9 +464,15 @@ def _parse_parameter_value(value, component_identifiers=None): def _generate_component_string( component_dict, component_identifiers, + component_name=None, + parent_parameters=None, assignment=False, default_type=None # used if no PNL or generic types are specified ): + from psyneulink.core.components.functions.function import Function_Base + from psyneulink.core.components.functions.userdefinedfunction import UserDefinedFunction + from psyneulink.core.components.projections.projection import Projection_Base + try: component_type = _parse_component_type(component_dict) except KeyError as e: @@ -438,8 +485,48 @@ def _generate_component_string( 'default_type is specified' ) from e - name = component_dict['name'] - parameters = dict(component_dict[component_type._model_spec_id_parameters]) + if component_name is None: + name = component_dict['name'] + else: + name = component_name + try: + assert component_name == component_dict['name'] + except KeyError: + pass + + is_user_defined_function = False + try: + parameters = dict(component_dict[component_type._model_spec_id_parameters]) + except AttributeError: + is_user_defined_function = True + except KeyError: + parameters = {} + + if is_user_defined_function or component_type is UserDefinedFunction: + custom_func = component_type + component_type = UserDefinedFunction + try: + parameters = dict(component_dict[component_type._model_spec_id_parameters]) + except KeyError: + parameters = {} + parameters['custom_function'] = f'{custom_func}' + try: + del component_dict[MODEL_SPEC_ID_METADATA]['custom_function'] + except KeyError: + pass + + try: + parameters.update(component_dict[component_type._model_spec_id_stateful_parameters]) + except KeyError: + pass + + try: + # args in function dict + parameters.update(component_dict['function'][list(component_dict['function'].keys())[0]]) + except (AttributeError, KeyError): + pass + + parameter_names = {} # If there is a parameter that is the psyneulink identifier string # (as of this comment, 'pnl'), then expand these parameters as @@ -452,12 +539,63 @@ def _generate_component_string( except KeyError: pass - # pnl objects only have one function unless specified in another way - # than just "function" try: - parameters['function'] = component_dict['functions'][0] + metadata = component_dict[MODEL_SPEC_ID_METADATA] except KeyError: - pass + metadata = {} + + if issubclass(component_type, Projection_Base): + try: + component_dict['functions'] = metadata['functions'] + except KeyError: + pass + + # pnl objects only have one function unless specified in another way + # than just "function" + if 'functions' in component_dict: + dup_function_names = set([name for name in component_dict['functions'] if name in component_identifiers]) + if len(dup_function_names) > 0: + warnings.warn( + f'Functions ({gen_friendly_comma_str(dup_function_names)}) of' + f' {name} share names of mechanisms or compositions in this' + ' model. This is likely to cause incorrect script reproduction.' + ) + + function_determined_by_output_port = False + + try: + output_ports = component_dict[MODEL_SPEC_ID_OUTPUT_PORTS] + except KeyError: + pass + else: + if len(output_ports) == 1 or isinstance(output_ports, list): + try: + primary_output_port = output_ports[0] + except KeyError: + primary_output_port = output_ports[list(output_ports)[0]] + function_determined_by_output_port = True + else: + try: + # 'out_port' appears to be the general primary output_port term + # should ideally have a marker in json to define it as primary + primary_output_port = output_ports['out_port'] + except KeyError: + pass + else: + function_determined_by_output_port = True + + # neuroml-style mdf has MODEL_SPEC_ID_PARAMETER_VALUE in output port definitions + if function_determined_by_output_port and MODEL_SPEC_ID_PARAMETER_VALUE in primary_output_port: + parameter_names['function'] = re.sub(r'(.*)\[\d+\]', '\\1', primary_output_port[MODEL_SPEC_ID_PARAMETER_VALUE]) + else: + parameter_names['function'] = [ + f for f in component_dict['functions'] + if not f.endswith(MODEL_SPEC_ID_INPUT_PORT_COMBINATION_FUNCTION) + ][0] + + parameters['function'] = { + parameter_names['function']: component_dict['functions'][parameter_names['function']] + } assignment_str = f'{parse_valid_identifier(name)} = ' if assignment else '' @@ -473,8 +611,95 @@ def _generate_component_string( if 'name' in constructor_arguments: additional_arguments.append(f"name='{name}'") + if parent_parameters is None: + parent_parameters = parameters + + parameters = { + **{k: v for k, v in parent_parameters.items() if isinstance(v, dict) and MODEL_SPEC_ID_PARAMETER_INITIAL_VALUE in v}, + **parameters, + **metadata + } + + # MDF input ports do not have functions, so their shape is + # equivalent to ours after the InputPort function is run (this + # function may change the shape of the default variable), so ignore + # the input port shape if input_ports parameter is specified + if 'variable' not in parameters and 'input_ports' not in parameters: + try: + ip = parameters['function'][Function_Base._model_spec_id_parameters][MODEL_SPEC_ID_MDF_VARIABLE] + var = convert_to_np_array( + numpy.zeros( + ast.literal_eval( + component_dict[MODEL_SPEC_ID_INPUT_PORTS][ip][MODEL_SPEC_ID_SHAPE] + ) + ), + dimension=2 + ).tolist() + parameters['variable'] = var + except KeyError: + pass + + def parameter_value_matches_default(component_type, param, value): + default_val = getattr(component_type.defaults, param) + evaled_val = NotImplemented + + # see if val is a psyneulink class instantiation + # if so, do not instantiate it (avoid offsetting rng for + # testing - see if you can bypass another way?) + try: + eval(re.match(r'(psyneulink\.\w+)\(', value).group(1)) + is_pnl_instance = True + except (AttributeError, TypeError, NameError, ValueError): + is_pnl_instance = False + + if not is_pnl_instance: + # val may be a string that evaluates to the default value + # also skip listing in constructor in this case + try: + evaled_val = eval(value) + except (TypeError, NameError, ValueError): + pass + except Exception: + # Assume this occurred in creation of a Component + # that probably needs some hidden/automatic modification. + # Special handling here? + # still relevant after testing for instance above? + pass + + # skip specifying parameters that match the class defaults + if ( + not safe_equals(value, default_val) + and ( + evaled_val is NotImplemented + or not safe_equals(evaled_val, default_val) + ) + ): + # test for dill use/equivalence + try: + is_dill_str = value[:5] == 'dill.' + except TypeError: + is_dill_str = False + + if ( + not is_dill_str + or dill.dumps(eval(value)) != dill.dumps(default_val) + ): + return False + + return True + + mdf_names_to_pnl = { + p.mdf_name: p.name for p in component_type.parameters + if p.mdf_name is not None and not isinstance(p, ParameterAlias) + } + # sort on arg name for arg, val in sorted(parameters.items(), key=lambda p: p[0]): + try: + arg = mdf_names_to_pnl[arg] + except KeyError: + pass + try: constructor_parameter_name = getattr(component_type.parameters, arg).constructor_argument # Some Parameters may be stored just to be replicated here, and @@ -491,52 +716,41 @@ def _generate_component_string( constructor_arg = arg if constructor_arg in constructor_arguments: - val = _parse_parameter_value(val, component_identifiers) - default_val = getattr(component_type.defaults, arg) - - evaled_val = NotImplemented - - # see if val is a psyneulink class instantiation - # if so, do not instantiate it (avoid offsetting rng for - # testing - see if you can bypass another way?) try: - eval(re.match(r'(psyneulink\.\w+)\(', val).group(1)) - is_pnl_instance = True - except (AttributeError, TypeError, NameError, ValueError): - is_pnl_instance = False - - if not is_pnl_instance: - # val may be a string that evaluates to the default value - # also skip listing in constructor in this case - try: - evaled_val = eval(val) - except (TypeError, NameError, ValueError): - pass - except Exception: - # Assume this occurred in creation of a Component - # that probably needs some hidden/automatic modification. - # Special handling here? - # still relevant after testing for instance above? - pass + val = _parse_parameter_value( + val, component_identifiers, + name=parameter_names[arg], + parent_parameters=parent_parameters, + ) + except KeyError: + val = _parse_parameter_value(val, component_identifiers, parent_parameters=parent_parameters) - # skip specifying parameters that match the class defaults if ( - not safe_equals(val, default_val) - and ( - evaled_val is NotImplemented - or not safe_equals(evaled_val, default_val) - ) + (arg in component_type.parameters or constructor_arg in component_type.parameters) + and not parameter_value_matches_default(component_type, arg, val) ): - # test for dill use/equivalence + additional_arguments.append(f'{constructor_arg}={val}') + elif component_type is UserDefinedFunction: + try: + val[MODEL_SPEC_ID_PARAMETER_INITIAL_VALUE] + except (KeyError, TypeError): + pass + else: + # is a stateful parameter corresponding to this function + if val[MODEL_SPEC_ID_PARAMETER_VALUE] == name: + additional_arguments.append(f"stateful_parameter='{arg}'") + + if arg != MODEL_SPEC_ID_MDF_VARIABLE: + val = _parse_parameter_value( + val, component_identifiers, parent_parameters=parent_parameters + ) + try: - is_dill_str = val[:5] == 'dill.' - except TypeError: - is_dill_str = False + matches = parameter_value_matches_default(component_type, arg, val) + except AttributeError: + matches = False - if ( - not is_dill_str - or dill.dumps(eval(val)) != dill.dumps(default_val) - ): + if not matches: additional_arguments.append(f'{constructor_arg}={val}') output = '{0}psyneulink.{1}{2}{3}{4}'.format( @@ -557,89 +771,166 @@ def _generate_scheduler_string( blacklist=[] ): output = [] - for node, condition in scheduler_dict['node_specific'].items(): - if node not in blacklist: - output.append( - '{0}.add_condition({1}, {2})'.format( - scheduler_id, - parse_valid_identifier(node), - _generate_condition_string( - condition, - component_identifiers + try: + node_specific_conds = scheduler_dict['node_specific'] + except KeyError: + pass + else: + for node, condition in node_specific_conds.items(): + if node not in blacklist: + output.append( + '{0}.add_condition({1}, {2})'.format( + scheduler_id, + parse_valid_identifier(node), + _generate_condition_string( + condition, + component_identifiers + ) ) ) - ) - output.append('') + output.append('') termination_str = [] - for scale, cond in scheduler_dict['termination'].items(): - termination_str.insert( - 1, - 'psyneulink.{0}: {1}'.format( - f'TimeScale.{str.upper(scale)}', - _generate_condition_string(cond, component_identifiers) + try: + termination_conds = scheduler_dict['termination'] + except KeyError: + pass + else: + for scale, cond in termination_conds.items(): + termination_str.insert( + 1, + 'psyneulink.{0}: {1}'.format( + f'TimeScale.{str.upper(scale)}', + _generate_condition_string(cond, component_identifiers) + ) ) - ) - output.append( - '{0}.termination_conds = {{{1}}}'.format( - scheduler_id, - ', '.join(termination_str) + output.append( + '{0}.termination_conds = {{{1}}}'.format( + scheduler_id, + ', '.join(termination_str) + ) ) - ) return '\n'.join(output) def _generate_condition_string(condition_dict, component_identifiers): def _parse_condition_arg_value(value): - pnl_str = parse_string_to_psyneulink_object_string(value) try: identifier = parse_valid_identifier(value) except TypeError: - identifier = None + pass + else: + if identifier in component_identifiers: + return str(identifier) - if identifier in component_identifiers: - return identifier - elif pnl_str is not None: - return f'psyneulink.{pnl_str}' + try: + getattr(psyneulink.core.scheduling.condition, value['type']) + except (AttributeError, KeyError, TypeError): + pass else: - return str(value) + return _generate_condition_string(value, component_identifiers) + + # handle value/outputport fix for threshold + try: + if re.match(r'\w+_OutputPort_0', value): + return '"value"' + except TypeError: + pass + + return str(_parse_parameter_value(value, component_identifiers)) + + def _parse_graph_scheduler_type(typ): + for ts, pnl_ts in graph_scheduler.time._time_scale_aliases.items(): + ts_class_name = graph_scheduler.time._time_scale_to_class_str(ts) + pnl_ts_class_name = graph_scheduler.time._time_scale_to_class_str(pnl_ts) + + if ts_class_name in typ: + return typ.replace(ts_class_name, pnl_ts_class_name) + + return typ args_str = '' + cond_type = _parse_graph_scheduler_type(condition_dict[MODEL_SPEC_ID_TYPE]) + sig = inspect.signature(getattr(psyneulink, cond_type).__init__) - if len(condition_dict['args']) > 0: - arg_str_list = [] - for arg in condition_dict['args']: - # handle nested Conditions - try: - arg = _generate_condition_string(arg, component_identifiers) - except TypeError: - pass + var_positional_arg_name = None + + for name, param in sig.parameters.items(): + if param.kind is inspect.Parameter.VAR_POSITIONAL: + var_positional_arg_name = name + break - arg_str_list.append(_parse_condition_arg_value(arg)) - args_str = f", {', '.join(arg_str_list)}" + args_dict = condition_dict['args'] + + try: + pos_args = args_dict[var_positional_arg_name] + except KeyError: + pass + else: + if len(pos_args) > 0: + arg_str_list = [] + for arg in pos_args: + # handle nested Conditions + try: + arg = _generate_condition_string(arg, component_identifiers) + except TypeError: + pass + + arg_str_list.append(_parse_condition_arg_value(arg)) + args_str = f", {', '.join(arg_str_list)}" kwargs_str = '' - if len(condition_dict['kwargs']) > 0: + kwargs = {k: v for k, v in args_dict.items() if k not in {'function', var_positional_arg_name}} + if len(kwargs) > 0: kwarg_str_list = [] - for key, val in condition_dict['kwargs'].items(): + for key, val in kwargs.items(): kwarg_str_list.append(f'{key}={_parse_condition_arg_value(val)}') kwargs_str = f", {', '.join(kwarg_str_list)}" + if 'function' in args_dict and args_dict['function'] is not None: + func_str = args_dict['function'] + else: + func_str = '' + arguments_str = '{0}{1}{2}'.format( - condition_dict['function'] if condition_dict['function'] is not None else '', + func_str, args_str, kwargs_str ) if len(arguments_str) > 0 and arguments_str[0] == ',': arguments_str = arguments_str[2:] - return f'psyneulink.{condition_dict[MODEL_SPEC_ID_TYPE]}({arguments_str})' + return f'psyneulink.{cond_type}({arguments_str})' + + +def _generate_composition_string(graphs_dict, component_identifiers): + def _replace_function_node_with_mech_node(function_dict, name, typ=None): + if typ is None: + typ = _parse_component_type(function_dict) + else: + typ = typ.__name__ + mech_func_dict = { + 'functions': { + name: { + MODEL_SPEC_ID_TYPE: {MODEL_SPEC_ID_PSYNEULINK: typ}, + psyneulink.Function_Base._model_spec_id_parameters: function_dict[psyneulink.Component._model_spec_id_parameters] + }, + } + } + + try: + del function_dict[MODEL_SPEC_ID_TYPE] + except KeyError: + pass + + function_dict['name'] = f"{name}_wrapped_mech" + + return {**function_dict, **mech_func_dict} -def _generate_composition_string(composition_list, component_identifiers): # used if no generic types are specified default_composition_type = psyneulink.Composition default_node_type = psyneulink.ProcessingMechanism @@ -657,24 +948,42 @@ def _generate_composition_string(composition_list, component_identifiers): output = [] # may be given multiple compositions - for composition_dict in composition_list: + for comp_name, composition_dict in graphs_dict.items(): try: - comp_type = _parse_component_type(composition_dict) + assert comp_name == composition_dict['name'] except KeyError: - comp_type = default_composition_type + pass - comp_name = composition_dict['name'] comp_identifer = parse_valid_identifier(comp_name) + def alphabetical_order(items): + alphabetical = enumerate( + sorted(items) + ) + return { + parse_valid_identifier(item[1]): item[0] + for item in alphabetical + } + # get order in which nodes were added # may be node names or dictionaries try: - node_order = composition_dict[comp_type._model_spec_id_parameters][MODEL_SPEC_ID_PSYNEULINK]['node_ordering'] + node_order = composition_dict[MODEL_SPEC_ID_METADATA]['node_ordering'] node_order = { - parse_valid_identifier(node['name']) if isinstance(node, dict) + parse_valid_identifier(list(node.keys())[0]) if isinstance(node, dict) else parse_valid_identifier(node): node_order.index(node) for node in node_order } + + unspecified_node_order = { + node: position + len(node_order) + for node, position in alphabetical_order([ + n for n in composition_dict[MODEL_SPEC_ID_NODES] if n not in node_order + ]).items() + } + + node_order.update(unspecified_node_order) + assert all([ (parse_valid_identifier(node) in node_order) for node in composition_dict[MODEL_SPEC_ID_NODES] @@ -682,13 +991,7 @@ def _generate_composition_string(composition_list, component_identifiers): except (KeyError, TypeError, AssertionError): # if no node_ordering attribute exists, fall back to # alphabetical order - alphabetical = enumerate( - sorted(composition_dict[MODEL_SPEC_ID_NODES]) - ) - node_order = { - parse_valid_identifier(item[1]): item[0] - for item in alphabetical - } + node_order = alphabetical_order(composition_dict[MODEL_SPEC_ID_NODES]) # clean up pnl-specific and other software-specific items pnl_specific_items = {} @@ -696,7 +999,7 @@ def _generate_composition_string(composition_list, component_identifiers): for name, node in composition_dict[MODEL_SPEC_ID_NODES].items(): try: - _parse_component_type(node) + component_type = _parse_component_type(node) except KeyError: # will use a default type pass @@ -709,6 +1012,77 @@ def _generate_composition_string(composition_list, component_identifiers): if MODEL_SPEC_ID_COMPOSITION not in node: keys_to_delete.append(name) + else: + # projection was written out as a node for simple_edge_format + if issubclass(component_type, psyneulink.Projection_Base): + assert len(node[MODEL_SPEC_ID_INPUT_PORTS]) == 1 + assert len(node[MODEL_SPEC_ID_OUTPUT_PORTS]) == 1 + + extra_projs_to_delete = set() + + sender = None + sender_port = None + receiver = None + receiver_port = None + + for proj_name, proj in composition_dict[MODEL_SPEC_ID_PROJECTIONS].items(): + if proj[MODEL_SPEC_ID_RECEIVER_MECH] == name: + assert 'dummy' in proj_name + sender = proj[MODEL_SPEC_ID_SENDER_MECH] + sender_port = proj[MODEL_SPEC_ID_SENDER_PORT] + extra_projs_to_delete.add(proj_name) + + if proj[MODEL_SPEC_ID_SENDER_MECH] == name: + assert 'dummy' in proj_name + receiver = proj[MODEL_SPEC_ID_RECEIVER_MECH] + receiver_port = proj[MODEL_SPEC_ID_RECEIVER_PORT] + # if for some reason the projection has node as both sender and receiver + # this is a bug, let the deletion fail + extra_projs_to_delete.add(proj_name) + + if sender is None: + raise PNLJSONError(f'Dummy node {name} for projection has no sender in projections list') + + if receiver is None: + raise PNLJSONError(f'Dummy node {name} for projection has no receiver in projections list') + + proj_dict = { + **{ + MODEL_SPEC_ID_SENDER_PORT: sender_port, + MODEL_SPEC_ID_RECEIVER_PORT: receiver_port, + MODEL_SPEC_ID_SENDER_MECH: sender, + MODEL_SPEC_ID_RECEIVER_MECH: receiver + }, + **{ + MODEL_SPEC_ID_METADATA: { + # variable isn't specified for projections + **{k: v for k, v in node[MODEL_SPEC_ID_METADATA].items() if k != 'variable'}, + 'functions': node['functions'] + } + }, + } + try: + proj_dict[component_type._model_spec_id_parameters] = node[psyneulink.Component._model_spec_id_parameters] + except KeyError: + pass + + composition_dict[MODEL_SPEC_ID_PROJECTIONS][name.rstrip('_dummy_node')] = proj_dict + + keys_to_delete.append(name) + for p in extra_projs_to_delete: + del composition_dict[MODEL_SPEC_ID_PROJECTIONS][p] + + for nr_item in ['required_node_roles', 'excluded_node_roles']: + nr_removal_indices = [] + + for i, (nr_name, nr_role) in enumerate( + composition_dict[MODEL_SPEC_ID_METADATA][nr_item] + ): + if nr_name == name: + nr_removal_indices.append(i) + + for i in nr_removal_indices: + del composition_dict[MODEL_SPEC_ID_METADATA][nr_item][i] for nodes_dict in pnl_specific_items: for name, node in nodes_dict.items(): @@ -717,31 +1091,36 @@ def _generate_composition_string(composition_list, component_identifiers): for name_to_delete in keys_to_delete: del composition_dict[MODEL_SPEC_ID_NODES][name_to_delete] - pnl_specific_items = {} - keys_to_delete = [] - for name, edge in composition_dict[MODEL_SPEC_ID_PROJECTIONS].items(): - try: - _parse_component_type(edge) - except KeyError: - # will use a default type - pass - except PNLJSONError: - if name == MODEL_SPEC_ID_PSYNEULINK: - pnl_specific_items = edge + try: + edges_dict = composition_dict[MODEL_SPEC_ID_PROJECTIONS] + pnl_specific_items = {} + keys_to_delete = [] + except KeyError: + pass + else: + for name, edge in edges_dict.items(): + try: + _parse_component_type(edge) + except KeyError: + # will use a default type + pass + except PNLJSONError: + if name == MODEL_SPEC_ID_PSYNEULINK: + pnl_specific_items = edge - keys_to_delete.append(name) + keys_to_delete.append(name) - for name, edge in pnl_specific_items.items(): - # exclude CIM projections because they are automatically - # generated - if ( - edge[MODEL_SPEC_ID_SENDER_MECH] != comp_name - and edge[MODEL_SPEC_ID_RECEIVER_MECH] != comp_name - ): - composition_dict[MODEL_SPEC_ID_PROJECTIONS][name] = edge + for name, edge in pnl_specific_items.items(): + # exclude CIM projections because they are automatically + # generated + if ( + edge[MODEL_SPEC_ID_SENDER_MECH] != comp_name + and edge[MODEL_SPEC_ID_RECEIVER_MECH] != comp_name + ): + composition_dict[MODEL_SPEC_ID_PROJECTIONS][name] = edge - for name_to_delete in keys_to_delete: - del composition_dict[MODEL_SPEC_ID_PROJECTIONS][name_to_delete] + for name_to_delete in keys_to_delete: + del composition_dict[MODEL_SPEC_ID_PROJECTIONS][name_to_delete] # generate string for Composition itself output.append( @@ -750,16 +1129,17 @@ def _generate_composition_string(composition_list, component_identifiers): _generate_component_string( composition_dict, component_identifiers, + component_name=comp_name, default_type=default_composition_type ) ) ) component_identifiers[comp_identifer] = True - mechanisms = [] - compositions = [] - control_mechanisms = [] - implicit_mechanisms = [] + mechanisms = {} + compositions = {} + control_mechanisms = {} + implicit_mechanisms = {} # add nested compositions and mechanisms in order they were added # to this composition @@ -768,7 +1148,7 @@ def _generate_composition_string(composition_list, component_identifiers): key=lambda item: node_order[parse_valid_identifier(item[0])] ): if MODEL_SPEC_ID_COMPOSITION in node: - compositions.append(node[MODEL_SPEC_ID_COMPOSITION]) + compositions[name] = node[MODEL_SPEC_ID_COMPOSITION] else: try: component_type = _parse_component_type(node) @@ -776,24 +1156,50 @@ def _generate_composition_string(composition_list, component_identifiers): component_type = default_node_type identifier = parse_valid_identifier(name) if issubclass(component_type, control_mechanism_types): - control_mechanisms.append(node) + control_mechanisms[name] = node component_identifiers[identifier] = True elif issubclass(component_type, implicit_types): - implicit_mechanisms.append(node) + implicit_mechanisms[name] = node else: - mechanisms.append(node) + mechanisms[name] = node component_identifiers[identifier] = True implicit_names = [ - x['name'] - for x in implicit_mechanisms + control_mechanisms + x + for x in [*implicit_mechanisms.keys(), *control_mechanisms.keys()] ] - for mech in mechanisms: + for name, mech in copy.copy(mechanisms).items(): + try: + mech_type = _parse_component_type(mech) + except KeyError: + mech_type = None + + if ( + isinstance(mech_type, type) + and issubclass(mech_type, psyneulink.Function) + ): + mech = _replace_function_node_with_mech_node(mech, name, mech_type) + + component_identifiers[mech['name']] = component_identifiers[name] + del component_identifiers[name] + + node_order[mech['name']] = node_order[name] + del node_order[name] + + mechanisms[mech['name']] = mechanisms[name] + del mechanisms[name] + + composition_dict['nodes'][mech['name']] = composition_dict['nodes'][name] + del composition_dict['nodes'][name] + + name = mech['name'] + output.append( _generate_component_string( mech, component_identifiers, + component_name=name, assignment=True, default_type=default_node_type ) @@ -801,11 +1207,12 @@ def _generate_composition_string(composition_list, component_identifiers): if len(mechanisms) > 0: output.append('') - for mech in control_mechanisms: + for name, mech in control_mechanisms.items(): output.append( _generate_component_string( mech, component_identifiers, + component_name=name, assignment=True, default_type=default_node_type ) @@ -815,7 +1222,7 @@ def _generate_composition_string(composition_list, component_identifiers): output.append('') # recursively generate string for inner Compositions - for comp in compositions: + for name, comp in compositions.items(): output.append( _generate_composition_string( comp, @@ -829,17 +1236,23 @@ def _generate_composition_string(composition_list, component_identifiers): try: node_roles = { parse_valid_identifier(node): role for (node, role) in - composition_dict[comp_type._model_spec_id_parameters][MODEL_SPEC_ID_PSYNEULINK]['required_node_roles'] + composition_dict[MODEL_SPEC_ID_METADATA]['required_node_roles'] } except KeyError: node_roles = [] - # do not add the controller as a normal node try: - controller_name = composition_dict['controller']['name'] - except TypeError: - controller_name = composition_dict['controller'] + excluded_node_roles = { + parse_valid_identifier(node): role for (node, role) in + composition_dict[MODEL_SPEC_ID_METADATA]['excluded_node_roles'] + } except KeyError: + excluded_node_roles = [] + + # do not add the controller as a normal node + try: + controller_name = list(composition_dict[MODEL_SPEC_ID_METADATA]['controller'].keys())[0] + except (AttributeError, KeyError, TypeError): controller_name = None for name in sorted( @@ -867,34 +1280,48 @@ def _generate_composition_string(composition_list, component_identifiers): if len(composition_dict[MODEL_SPEC_ID_NODES]) > 0: output.append('') - # generate string to add the projections - for name, projection_dict in composition_dict[MODEL_SPEC_ID_PROJECTIONS].items(): - try: - projection_type = _parse_component_type(projection_dict) - except KeyError: - projection_type = default_edge_type + if len(excluded_node_roles) > 0: + for node, roles in excluded_node_roles.items(): + if name not in implicit_names and name != controller_name: + output.append( + f'{comp_identifer}.exclude_node_roles({node}, {_parse_parameter_value(roles, component_identifiers)})' + ) + output.append('') - if ( - not issubclass(projection_type, implicit_types) - and projection_dict[MODEL_SPEC_ID_SENDER_MECH] not in implicit_names - and projection_dict[MODEL_SPEC_ID_RECEIVER_MECH] not in implicit_names - ): - output.append( - '{0}.add_projection(projection={1}, sender={2}, receiver={3})'.format( - comp_identifer, - _generate_component_string( - projection_dict, - component_identifiers, - default_type=default_edge_type - ), - parse_valid_identifier( - projection_dict[MODEL_SPEC_ID_SENDER_MECH] - ), - parse_valid_identifier( - projection_dict[MODEL_SPEC_ID_RECEIVER_MECH] - ), + try: + edges_dict = composition_dict[MODEL_SPEC_ID_PROJECTIONS] + except KeyError: + pass + else: + # generate string to add the projections + for name, projection_dict in edges_dict.items(): + try: + projection_type = _parse_component_type(projection_dict) + except KeyError: + projection_type = default_edge_type + + if ( + not issubclass(projection_type, implicit_types) + and projection_dict[MODEL_SPEC_ID_SENDER_MECH] not in implicit_names + and projection_dict[MODEL_SPEC_ID_RECEIVER_MECH] not in implicit_names + ): + output.append( + '{0}.add_projection(projection={1}, sender={2}, receiver={3})'.format( + comp_identifer, + _generate_component_string( + projection_dict, + component_identifiers, + component_name=name, + default_type=default_edge_type + ), + parse_valid_identifier( + projection_dict[MODEL_SPEC_ID_SENDER_MECH] + ), + parse_valid_identifier( + projection_dict[MODEL_SPEC_ID_RECEIVER_MECH] + ), + ) ) - ) # add controller if it exists (must happen after projections) if controller_name is not None: @@ -908,11 +1335,16 @@ def _generate_composition_string(composition_list, component_identifiers): # add schedulers # blacklist automatically generated nodes because they will # not exist in the script namespace + try: + conditions = composition_dict['conditions'] + except KeyError: + conditions = {} + output.append('') output.append( _generate_scheduler_string( f'{comp_identifer}.scheduler', - composition_dict['conditions'], + conditions, component_identifiers, blacklist=implicit_names ) @@ -921,7 +1353,7 @@ def _generate_composition_string(composition_list, component_identifiers): return '\n'.join(output) -def generate_script_from_json(model_input): +def generate_script_from_json(model_input, outfile=None): """ Generate a Python script from JSON **model_input** in the `general JSON format ` @@ -948,11 +1380,16 @@ def generate_script_from_json(model_input): """ - def get_declared_identifiers(composition_list): + def get_declared_identifiers(graphs_dict): names = set() - for composition_dict in composition_list: - names.add(parse_valid_identifier(composition_dict['name'])) + for comp_name, composition_dict in graphs_dict.items(): + try: + assert comp_name == composition_dict['name'] + except KeyError: + pass + + names.add(parse_valid_identifier(comp_name)) for name, node in composition_dict[MODEL_SPEC_ID_NODES].items(): if MODEL_SPEC_ID_COMPOSITION in node: names.update( @@ -970,7 +1407,16 @@ def get_declared_identifiers(composition_list): model_input = open(model_input, 'r').read() except (FileNotFoundError, OSError): pass - model_input = json.loads(model_input) + + try: + model_input = json.loads(model_input) + except json.decoder.JSONDecodeError: + raise ValueError( + f'{model_input} is neither valid JSON nor a file containing JSON' + ) + + assert len(model_input.keys()) == 1 + model_input = model_input[list(model_input.keys())[0]] imports_str = '' if MODEL_SPEC_ID_COMPOSITION in model_input: @@ -1002,26 +1448,46 @@ def get_declared_identifiers(composition_list): } module_names = set() - potential_module_names = set(re.findall(r'([A-Za-z]+?)\.', comp_str)) + + # greedy and non-greedy + potential_module_names = set([ + *re.findall(r'([A-Za-z_\.]+)\.', comp_str), + *re.findall(r'([A-Za-z_\.]+?)\.', comp_str) + ]) for module in potential_module_names: - try: - exec(f'import {module}') - module_names.add(module) - except (ImportError, ModuleNotFoundError, SyntaxError): - pass + if module not in component_identifiers: + try: + exec(f'import {module}') + module_names.add(module) + except (ImportError, ModuleNotFoundError, SyntaxError): + pass - for module in module_names: + for module in module_names.copy(): try: friendly_name = module_friendly_name_mapping[module] comp_str = re.sub(f'{module}\\.', f'{friendly_name}.', comp_str) except KeyError: friendly_name = module - if f'{friendly_name}.' in comp_str: - imports_str += 'import {0}{1}\n'.format( - module, - f' as {friendly_name}' if friendly_name != module else '' - ) + if not re.findall(rf'[^\.]{friendly_name}\.', comp_str): + module_names.remove(module) + + for m in module_names.copy(): + for n in module_names.copy(): + # remove potential modules that are substrings of another + if m is not n and m in n: + module_names.remove(m) + + for module in sorted(module_names): + try: + friendly_name = module_friendly_name_mapping[module] + except KeyError: + friendly_name = module + + imports_str += 'import {0}{1}\n'.format( + module, + f' as {friendly_name}' if friendly_name != module else '' + ) model_output = '{0}{1}{2}'.format( imports_str, @@ -1029,10 +1495,79 @@ def get_declared_identifiers(composition_list): comp_str ) - return model_output + if outfile is not None: + # pass through any file exceptions + with open(outfile, 'w') as outfile: + outfile.write(model_output) + print(f'Wrote JSON to {outfile.name}') + else: + return model_output + + +def generate_script_from_mdf(model_input, outfile=None): + """ + Generate a Python script from MDF model **model_input** + + .. warning:: + Use of `generate_script_from_mdf` to generate a Python script from a model without taking proper precautions + can introduce a security risk to the system on which the Python interpreter is running. This is because it + calls exec, which has the potential to execute non-PsyNeuLink-related code embedded in the file. Therefore, + `generate_script_from_mdf` should be used to read only model of known and secure origin. + + Arguments + --------- + + model_input : modeci_mdf.Model + + Returns + ------- + + Text of Python script : str + """ + return generate_script_from_json(model_input.to_json(), outfile) + + +def generate_json(*compositions, simple_edge_format=True): + """ + Generate the `general JSON format ` + for one or more `Compositions ` and associated + objects. + .. _JSON_Write_Multiple_Compositions_Note: + + .. note:: + At present, if more than one Composition is specified, all + must be fully disjoint; that is, they must not share any + `Components ` (e.g., `Mechanism`, `Projections` + etc.). This limitation will be addressed in a future update. + + Arguments: + *compositions : Composition + specifies `Composition` or iterable of ones to be output + in JSON + """ + import modeci_mdf + import modeci_mdf.mdf as mdf + from psyneulink.core.compositions.composition import Composition + + model_name = "_".join([c.name for c in compositions]) + + model = mdf.Model( + id=model_name, + format=f'ModECI MDF v{modeci_mdf.__version__}', + generating_application=f'PsyNeuLink v{psyneulink.__version__}', + ) + + for c in compositions: + if not isinstance(c, Composition): + raise PNLJSONError( + f'Item in compositions arg of {__name__}() is not a Composition: {c}.' + ) + model.graphs.append(c.as_mdf_model(simple_edge_format=simple_edge_format)) + + return model.to_json() -def write_json_file(compositions, filename:str, path:str=None): +def write_json_file(compositions, filename:str, path:str=None, simple_edge_format=True): """ Write one or more `Compositions ` and associated objects to file in the `general JSON format ` @@ -1059,23 +1594,6 @@ def write_json_file(compositions, filename:str, path:str=None): """ compositions = convert_to_list(compositions) - for c in compositions: - from psyneulink.core.compositions.composition import Composition - if not isinstance(c, Composition): - raise PNLJSONError(f'Item in compositions arg of write_to_json_file() is not a Composition: {c}.') - if path: - if path[-1] != '/': - path += '/' - filename = path + filename - - merged_dict_summary = {} - for c in compositions: - try: - merged_dict_summary[MODEL_SPEC_ID_COMPOSITION].extend( - c._dict_summary[MODEL_SPEC_ID_COMPOSITION] - ) - except KeyError: - merged_dict_summary.update(c._dict_summary) with open(filename, 'w') as json_file: - json_file.write(_dump_pnl_json_from_dict(merged_dict_summary)) + json_file.write(generate_json(*compositions, simple_edge_format=simple_edge_format)) diff --git a/psyneulink/core/globals/keywords.py b/psyneulink/core/globals/keywords.py index d27a777ebc0..c65e6a5c965 100644 --- a/psyneulink/core/globals/keywords.py +++ b/psyneulink/core/globals/keywords.py @@ -39,20 +39,20 @@ 'CONTROL_PROJECTIONS', 'CONTROL_SIGNAL', 'CONTROL_SIGNAL_SPECS', 'CONTROL_SIGNALS', 'CONTROLLED_PARAMS', 'CONTROLLER', 'CONTROLLER_OBJECTIVE', 'CORRELATION', 'COSINE', 'COST_FUNCTION', 'COUNT', 'CROSS_ENTROPY', 'CURRENT_EXECUTION_TIME', 'CUSTOM_FUNCTION', 'CYCLE', - 'DDM_MECHANISM', 'DECAY', 'DEFAULT', 'DEFAULT_CONTROL_MECHANISM', 'DEFAULT_MATRIX', + 'DDM_MECHANISM', 'DECAY', 'DEFAULT', 'DEFAULT_CONTROL_MECHANISM', 'DEFAULT_INPUT', 'DEFAULT_MATRIX', 'DEFAULT_PREFERENCE_SET_OWNER', 'DEFAULT_PROCESSING_MECHANISM', 'DEFAULT_VARIABLE', - 'DEFERRED_ASSIGNMENT', 'DEFERRED_DEFAULT_NAME', 'DEFERRED_INITIALIZATION', 'DictionaryMemory_FUNCTION', + 'DEFERRED_ASSIGNMENT', 'DEFERRED_DEFAULT_NAME', 'DEFERRED_INITIALIZATION', 'DICT', 'DictionaryMemory_FUNCTION', 'DIFFERENCE', 'DIFFERENCE', 'DIFFUSION', 'DIRECT', 'DISABLE', 'DISABLE_PARAM', 'DIST_FUNCTION_TYPE', 'DIST_MEAN', 'DIST_SHAPE', 'DISTANCE_FUNCTION', 'DISTANCE_METRICS', 'DISTRIBUTION_FUNCTION_TYPE', 'DIVISION', 'DRIFT_DIFFUSION_INTEGRATOR_FUNCTION', 'DRIFT_ON_A_SPHERE_INTEGRATOR_FUNCTION', 'DUAL_ADAPTIVE_INTEGRATOR_FUNCTION', - 'EID_SIMULATION', 'EID_FROZEN', 'EITHER', 'ENABLE_CONTROLLER', 'ENABLED', 'ENERGY', 'ENTROPY', + 'EFFERENTS', 'EID_SIMULATION', 'EID_FROZEN', 'EITHER', 'ENABLE_CONTROLLER', 'ENABLED', 'ENERGY', 'ENTROPY', 'EPISODIC_MEMORY_MECHANISM', 'EQUAL', 'ERROR_DERIVATIVE_FUNCTION', 'EUCLIDEAN', 'EVC_MECHANISM', 'EVC_SIMULATION', 'EXAMPLE_FUNCTION_TYPE', 'EXECUTE_UNTIL_FINISHED', 'EXECUTING', 'EXECUTION', 'EXECUTION_COUNT', 'EXECUTION_ID', 'EXECUTION_PHASE', 'EXPONENTIAL', 'EXPONENT', 'EXPONENTIAL_DIST_FUNCTION', 'EXPONENTIAL_FUNCTION', 'EXPONENTS', 'FEEDBACK', 'FITZHUGHNAGUMO_INTEGRATOR_FUNCTION', 'FINAL', 'FLAGS', 'FULL', 'FULL_CONNECTIVITY_MATRIX', 'FUNCTION', 'FUNCTIONS', 'FUNCTION_COMPONENT_CATEGORY','FUNCTION_CHECK_ARGS', 'FUNCTION_OUTPUT_TYPE', 'FUNCTION_OUTPUT_TYPE_CONVERSION', 'FUNCTION_PARAMS', - 'GAIN', 'GAMMA_DIST_FUNCTION', 'GATE', 'GATING', 'GATING_MECHANISM', 'GATING_ALLOCATION', 'GATING_PROJECTION', + 'GAIN', 'GAMMA_DIST_FUNCTION', 'GATE', 'GATING_MECHANISM', 'GATING_ALLOCATION', 'GATING_PROJECTION', 'GATING_PROJECTION_PARAMS', 'GATING_PROJECTIONS', 'GATING_SIGNAL', 'GATING_SIGNAL_SPECS', 'GATING_SIGNALS', 'GAUSSIAN', 'GAUSSIAN_FUNCTION', 'GILZENRAT_INTEGRATOR_FUNCTION', 'GREATER_THAN', 'GREATER_THAN_OR_EQUAL', 'GRADIENT_OPTIMIZATION_FUNCTION', 'GRID_SEARCH_FUNCTION', @@ -74,14 +74,15 @@ 'MATRIX', 'MATRIX_KEYWORD_NAMES', 'MATRIX_KEYWORD_SET', 'MATRIX_KEYWORD_VALUES', 'MATRIX_KEYWORDS','MatrixKeywords', 'MAX_ABS_DIFF', 'MAX_ABS_INDICATOR', 'MAX_ONE_HOT', 'MAX_ABS_ONE_HOT', 'MAX_ABS_VAL', 'MAX_EXECUTIONS_BEFORE_FINISHED', 'MAX_INDICATOR', 'MAX_VAL', 'MAYBE', 'MEAN', - 'MECHANISM', 'MECHANISM_COMPONENT_CATEGORY', 'MECHANISM_DEFAULT', 'MECHANISM_DEFAULTInputValue', + 'MECHANISM', 'MECHANISM_COMPONENT_CATEGORY', 'MECHANISM_DEFAULT', 'MECHANISM_DEFAULT_INPUT_VALUE', 'MECHANISM_DEFAULTParams', 'MECHANISM_EXECUTED_LOG_ENTRY', 'MECHANISM_NAME', 'MECHANISM_PARAM_VALUE', 'MECHANISM_TYPE', 'MECHANISM_VALUE', 'MEDIAN', 'METRIC', 'MIN_VAL', 'MIN_ABS_VAL', 'MIN_ABS_INDICATOR', - 'MODE', 'MODULATES','MODULATION', 'MODULATORY_PROJECTION', 'MODULATORY_SIGNAL', 'MODULATORY_SIGNALS', - 'MONITOR', 'MONITOR_FOR_CONTROL', 'MONITOR_FOR_LEARNING', 'MONITOR_FOR_MODULATION', + 'MOD_AFFERENTS', 'MODE', 'MODULATES','MODULATION', 'MODULATORY_PROJECTION', 'MODULATORY_SIGNAL', + 'MODULATORY_SIGNALS', 'MONITOR', 'MONITOR_FOR_CONTROL', 'MONITOR_FOR_LEARNING', 'MONITOR_FOR_MODULATION', 'MODEL_SPEC_ID_GENERIC', 'MODEL_SPEC_ID_INPUT_PORTS', 'MODEL_SPEC_ID_OUTPUT_PORTS', 'MODEL_SPEC_ID_PSYNEULINK', 'MODEL_SPEC_ID_SENDER_MECH', 'MODEL_SPEC_ID_SENDER_PORT', - 'MODEL_SPEC_ID_RECEIVER_MECH', 'MODEL_SPEC_ID_RECEIVER_PORT','MODEL_SPEC_ID_PARAMETER_SOURCE', + 'MODEL_SPEC_ID_RECEIVER_MECH', 'MODEL_SPEC_ID_RECEIVER_PORT', + 'MODEL_SPEC_ID_PARAMETER_INITIAL_VALUE', 'MODEL_SPEC_ID_PARAMETER_SOURCE', 'MODEL_SPEC_ID_PARAMETER_VALUE', 'MODEL_SPEC_ID_TYPE', 'MSE', 'MULTIPLICATIVE', 'MULTIPLICATIVE_PARAM', 'MUTUAL_ENTROPY', 'NAME', 'NESTED', 'NEWEST', 'NODE', 'NOISE', 'NORMAL_DIST_FUNCTION', 'NORMED_L0_SIMILARITY', 'NOT_EQUAL', @@ -93,7 +94,7 @@ 'OVERRIDE', 'OVERRIDE_PARAM', 'OVERWRITE', 'OWNER', 'OWNER_EXECUTION_COUNT', 'OWNER_EXECUTION_TIME', 'OWNER_VALUE', 'OWNER_VARIABLE', 'PARAMETER', 'PARAMETER_CIM_NAME', 'PARAMETER_PORT', 'PARAMETER_PORT_PARAMS', 'PARAMETER_PORTS', - 'PARAMETERS', 'PARAMS', 'PARAMS_DICT', 'PATHWAY', 'PATHWAY_PROJECTION', 'PEARSON', + 'PARAMETERS', 'PARAMS', 'PARAMS_DICT', 'PATH_AFFERENTS', 'PATHWAY', 'PATHWAY_PROJECTION', 'PEARSON', 'PORT', 'PORT_COMPONENT_CATEGORY', 'PORT_CONTEXT', 'Port_Name', 'port_params', 'PORT_PREFS', 'PORT_TYPE', 'port_value', 'PORTS', 'PREDICTION_MECHANISM', 'PREDICTION_MECHANISMS', 'PREDICTION_MECHANISM_OUTPUT', 'PREDICTION_MECHANISM_PARAMS', @@ -111,8 +112,10 @@ 'SINGLETON', 'SIZE', 'SLOPE', 'SOFT_CLAMP', 'SOFTMAX_FUNCTION', 'SOURCE', 'SSE', 'STABILITY_FUNCTION', 'STANDARD_ARGS', 'STANDARD_DEVIATION', 'STANDARD_OUTPUT_PORTS', 'SUBTRACTION', 'SUM', 'TARGET', 'TARGET_MECHANISM', 'TARGET_LABELS_DICT', 'TERMINAL', 'TERMINATION_MEASURE', 'TERMINATION_THRESHOLD', - 'TERMINATION_COMPARISION_OP', 'TERSE', 'THRESHOLD', 'TIME', 'TIME_STEP_SIZE', 'TIME_STEPS_DIM', 'TRAINING_SET', - 'TRANSFER_FUNCTION_TYPE', 'TRANSFER_MECHANISM', 'TRANSFER_WITH_COSTS_FUNCTION', 'TRIAL', 'TRIALS_DIM', + 'TERMINATION_COMPARISION_OP', 'TERSE', 'TEXT', 'THRESHOLD', 'TIME', 'TIME_STEP_SIZE', 'TIME_STEPS_DIM', + 'TRAINING_SET', + 'TRANSFER_FUNCTION_TYPE', 'TRANSFER_MECHANISM', 'TRANSFER_WITH_COSTS_FUNCTION', + 'TRIAL', 'TRIALS_DIM', 'UNCHANGED', 'UNIFORM_DIST_FUNCTION', 'USER_DEFINED_FUNCTION', 'USER_DEFINED_FUNCTION_TYPE', 'VALUES', 'VALIDATE', 'VALIDATION', 'VALUE', 'VALUE_ASSIGNMENT', 'VALUE_FUNCTION', 'VARIABLE', 'VARIANCE', 'VECTOR', 'WALD_DIST_FUNCTION', 'WEIGHT', 'WEIGHTS', 'X_0', @@ -339,6 +342,8 @@ def _is_metric(metric): FULL = 'full' TERSE = 'terse' DIRECT = 'direct' +DICT = 'dict' +TEXT = 'text' LESS_THAN = '<' LESS_THAN_OR_EQUAL = '<=' @@ -385,14 +390,13 @@ def _is_metric(metric): VALUE_ASSIGNMENT = 'VALUE_ASSIGNMENT' FINAL = 'FINAL' - #endregion #region ---------------------------------------------- COMPOSITION ------------------------------------------------- # 11/15/21: FIX - CHANGE TO LOWER CASE FOR USE WITH componentCategory (OR CHANGE THAT?); MAY NEED TO CHANGE TESTS # Composition Categories -COMPOSITION = 'COMPOSITION' +COMPOSITION = 'Composition' AUTODIFF_COMPOSITION = 'AutodiffComposition' COMPOSITION_FUNCTION_APPROXIMATOR = 'CompositionFunctionApproximator' @@ -487,6 +491,10 @@ def _is_metric(metric): CONTROL_SIGNAL = 'ControlSignal' GATING_SIGNAL = 'GatingSignal' +PATH_AFFERENTS = 'path_afferents' +MOD_AFFERENTS = 'mod_afferents' +EFFERENTS = 'efferents' + # Projections: MAPPING_PROJECTION = "MappingProjection" AUTO_ASSOCIATIVE_PROJECTION = "AutoAssociativeProjection" @@ -661,8 +669,7 @@ def _is_metric(metric): PULSE_CLAMP = "pulse_clamp" NO_CLAMP = "no_clamp" LEARNING_RATE = "learning_rate" -CONTROL = 'CONTROL' -GATING = 'gating' +# CONTROL = 'CONTROL' PROCESS_DEFAULT_PROJECTION_FUNCTION = "Default Projection Function" PROCESS_EXECUTE = "ProcessExecute" MECHANISM_EXECUTED_LOG_ENTRY = "Mechanism Executed" @@ -677,7 +684,7 @@ def _is_metric(metric): DEFAULT_PROCESSING_MECHANISM = "DefaultProcessingMechanism" PROCESS_DEFAULT_MECHANISM = "ProcessDefaultMechanism" MECHANISM_TYPE = "Mechanism Type" # Used in mechanism dict specification (e.g., in process.pathway[]) -MECHANISM_DEFAULTInputValue = "Mechanism Default Input Value " # Used in mechanism specification dict +MECHANISM_DEFAULT_INPUT_VALUE = "Mechanism Default Input Value " # Used in mechanism specification dict MECHANISM_PARAM_VALUE = "Mechanism Parameter Value" # Used to specify mechanism param value MECHANISM_DEFAULTParams = "Mechanism Default Parameters" # Used in mechanism specification dict CONDITION = 'condition' @@ -765,6 +772,7 @@ def _is_metric(metric): PREDICTION_MECHANISM_OUTPUT = "PredictionMechanismOutput" MODULATORY_SIGNALS = 'modulatory_signals' +CONTROL = 'control' CONTROL_SIGNALS = 'control_signals' CONTROL_SIGNAL_SPECS = 'CONTROL_SIGNAL_SPECS' CONTROLLED_PARAMS = 'CONTROLLED_PARAMS' @@ -779,16 +787,16 @@ def _is_metric(metric): ALLOCATION_SAMPLES = "allocation_samples" # GatingMechanism +GATE = 'gate' GATING_SIGNALS = 'gating_signals' GATING_SIGNAL_SPECS = 'GATING_SIGNAL_SPECS' -GATE = 'GATE' GATED_PORTS = 'GATED_PORTS' GATING_PROJECTIONS = 'GatingProjections' GATING_ALLOCATION = 'gating_allocation' MODULATORY_SPEC_KEYWORDS = {LEARNING, LEARNING_SIGNAL, LEARNING_PROJECTION, LEARNING_MECHANISM, CONTROL, CONTROL_SIGNAL, CONTROL_PROJECTION, CONTROL_MECHANISM, - GATING, GATING_SIGNAL, GATING_PROJECTION, GATING_MECHANISM} + GATE, GATING_SIGNAL, GATING_PROJECTION, GATING_MECHANISM} MODULATED_PARAMETER_PREFIX = 'mod_' @@ -819,6 +827,7 @@ def _is_metric(metric): WEIGHT = 'weight' EXPONENT = 'exponent' INTERNAL_ONLY = 'internal_only' +DEFAULT_INPUT = 'default_input' # ParameterPorts: PARAMETER_PORTS = 'parameter_ports' @@ -974,6 +983,7 @@ def _is_metric(metric): MODEL_SPEC_ID_TYPE = 'type' MODEL_SPEC_ID_PSYNEULINK = 'PNL' MODEL_SPEC_ID_GENERIC = 'generic' +MODEL_SPEC_ID_METADATA = 'metadata' MODEL_SPEC_ID_INPUT_PORTS = 'input_ports' MODEL_SPEC_ID_OUTPUT_PORTS = 'output_ports' @@ -985,7 +995,14 @@ def _is_metric(metric): MODEL_SPEC_ID_PARAMETER_SOURCE = 'source' MODEL_SPEC_ID_PARAMETER_VALUE = 'value' +MODEL_SPEC_ID_PARAMETER_INITIAL_VALUE = 'default_initial_value' MODEL_SPEC_ID_NODES = 'nodes' MODEL_SPEC_ID_PROJECTIONS = 'edges' MODEL_SPEC_ID_COMPOSITION = 'graphs' + +MODEL_SPEC_ID_MDF_VARIABLE = 'variable0' + +MODEL_SPEC_ID_SHAPE = 'shape' + +MODEL_SPEC_ID_INPUT_PORT_COMBINATION_FUNCTION = 'input_combination_function' diff --git a/psyneulink/core/globals/parameters.py b/psyneulink/core/globals/parameters.py index feabfa83a85..d7cc7233a38 100644 --- a/psyneulink/core/globals/parameters.py +++ b/psyneulink/core/globals/parameters.py @@ -30,6 +30,10 @@ ``t.defaults.noise`` is shorthand for ``t.parameters.noise.default_value``, and they both refer to the default ``noise`` value for *t* +Default values are sometimes also used when the parameters value has not been specified; for example, a Component's +``defaults.variable`` is used as the input to a `Mechanism` if its `execute ` method is called +without any input specified, and similarly it is used for the `INPUT ` `Nodes ` of +a `Composition` which are not specified in the **inputs** argument of its `run ` method. .. _Parameter_Statefulness: @@ -102,8 +106,10 @@ class Parameters(A.Parameters): - an instance of *B*.Parameters will be assigned to the parameters attribute of the class *B* and all instances of *B* - each attribute on *B*.Parameters becomes a parameter (instance of the Parameter class) - as with *p*, specifying only a value uses default values for the attributes of the Parameter - - as with *q*, specifying an explicit instance of the Parameter class allows you to modify the `Parameter attributes ` -- if you want assignments to parameter *p* to be validated, add a method _validate_p(value), that returns None if value is a valid assignment, or an error string if value is not a valid assignment + - as with *q*, specifying an explicit instance of the Parameter class allows you to modify the + `Parameter attributes ` +- if you want assignments to parameter *p* to be validated, add a method _validate_p(value), + that returns None if value is a valid assignment, or an error string if value is not a valid assignment - if you want all values set to *p* to be parsed beforehand, add a method _parse_p(value) that returns the parsed value - for example, convert to a numpy array or float @@ -291,17 +297,18 @@ def _recurrent_transfer_mechanism_matrix_setter(value, owning_component=None, co import copy import itertools import logging -import toposort import types import typing import weakref +import toposort -from psyneulink.core.rpc.graph_pb2 import Entry, ndArray from psyneulink.core.globals.context import Context, ContextError, ContextFlags, _get_time, handle_external_context from psyneulink.core.globals.context import time as time_object from psyneulink.core.globals.log import LogCondition, LogEntry, LogError -from psyneulink.core.globals.utilities import call_with_pruned_args, copy_iterable_with_shared, get_alias_property_getter, get_alias_property_setter, get_deepcopy_with_shared, unproxy_weakproxy, create_union_set +from psyneulink.core.globals.utilities import call_with_pruned_args, copy_iterable_with_shared, \ + get_alias_property_getter, get_alias_property_setter, get_deepcopy_with_shared, unproxy_weakproxy, create_union_set +from psyneulink.core.rpc.graph_pb2 import Entry, ndArray __all__ = [ 'Defaults', 'get_validator_by_function', 'Parameter', 'ParameterAlias', 'ParameterError', @@ -853,6 +860,7 @@ def __init__( dependencies=None, initializer=None, port=None, + mdf_name=None, _owner=None, _inherited=False, # this stores a reference to the Parameter object that is the @@ -916,6 +924,7 @@ def __init__( dependencies=dependencies, initializer=initializer, port=port, + mdf_name=mdf_name, _inherited=_inherited, _inherited_source=_inherited_source, _user_specified=_user_specified, diff --git a/psyneulink/core/globals/registry.py b/psyneulink/core/globals/registry.py index 2586761aba4..15c585d1c7f 100644 --- a/psyneulink/core/globals/registry.py +++ b/psyneulink/core/globals/registry.py @@ -274,12 +274,12 @@ def register_instance(entry, name, base_class, registry, sub_dict): else: renamed_instance_counts[match.groups()[0]] += 1 -def rename_instance_in_registry(registry, category, name=None, component=None): +def rename_instance_in_registry(registry, category, new_name, old_name=None, component=None): """Rename instance in category registry Instance to be renamed can be specified by a reference to the component or its name. COMMENT: - DEPRECACTED (SEE IMPLEMENTATION NOTE BELOW) + DEPRECATED (SEE IMPLEMENTATION NOTE BELOW) If the name of the instance was a default name, and it was the last in the sequence, decrement renamed_instance_counts and if it was the only one, remove that name from the renamed_instance list COMMENT @@ -287,24 +287,27 @@ def rename_instance_in_registry(registry, category, name=None, component=None): registry_entry = registry[category] - if not (name or component): + if not (old_name or component): raise RegistryError("Must specify a name or component to remove an entry of {}". format(registry.__class__.__name__)) - if (name and component) and name != component.name: + if (old_name and component) and old_name != component.old_name: raise RegistryError("Conflicting name ({}) and component ({}) specified for entry to remove from {}". - format(name, component.name, registry.__class__.__name__)) - if component and not name: + format(old_name, component.old_name, registry.__class__.__name__)) + if component and not old_name: for n, c in registry_entry.instanceDict.items(): if component == c: - name = n + old_name = n try: - clear_registry(registry_entry.instanceDict[name]._portRegistry) + clear_registry(registry_entry.instanceDict[old_name]._portRegistry) except (AttributeError): pass - # Delete instance - del registry_entry.instanceDict[name] + entry = registry_entry.instanceDict[old_name] + # Delete entry for instance + del registry_entry.instanceDict[old_name] + # Add entry for instance under new name + registry_entry.instanceDict[new_name] = entry # Decrement count for instances in entry instance_count = registry_entry.instanceCount - 1 @@ -327,6 +330,7 @@ def rename_instance_in_registry(registry, category, name=None, component=None): instance_count, registry_entry.renamed_instance_counts, registry_entry.default) + return new_name def remove_instance_from_registry(registry, category, name=None, component=None): """Remove instance from registry category entry diff --git a/psyneulink/core/globals/socket.py b/psyneulink/core/globals/socket.py index e995466f98c..54e93c44a8d 100644 --- a/psyneulink/core/globals/socket.py +++ b/psyneulink/core/globals/socket.py @@ -34,6 +34,15 @@ def add_composition(self, composition): else: self.compositions.add(composition) + def remove_composition(self, composition): + if composition is self.ALL: + self.compositions = set() + else: + try: + self.compositions.remove(composition) + except (AttributeError, KeyError): + logger.info('Attempted to remove composition from {} but was not active'.format(self)) + def is_active_in_composition(self, composition): if self.compositions is None: return False diff --git a/psyneulink/core/globals/utilities.py b/psyneulink/core/globals/utilities.py index 351775aed03..a77f319061c 100644 --- a/psyneulink/core/globals/utilities.py +++ b/psyneulink/core/globals/utilities.py @@ -67,6 +67,14 @@ * powerset * tensor_power +*LIST MANAGEMENT* +~~~~~~~~~~~~~~~~~ + +* `insert_list` +* `convert_to_list` +* `flatten_list` +* `nesting_depth` + *OTHER* ~~~~~~~ @@ -85,9 +93,6 @@ * `ContentAddressableList` * `make_readonly_property` * `get_class_attributes` -* `insert_list` -* `flatten_list` -* `convert_to_list` * `get_global_seed` * `set_global_seed` @@ -126,6 +131,7 @@ 'is_modulation_operation', 'is_numeric', 'is_numeric_or_none', 'is_number', 'is_same_function_spec', 'is_unit_interval', 'is_value_spec', 'kwCompatibilityLength', 'kwCompatibilityNumeric', 'kwCompatibilityType', + 'nesting_depth', 'make_readonly_property', 'Modulation', 'MODULATION_ADD', 'MODULATION_MULTIPLY','MODULATION_OVERRIDE', 'multi_getattr', 'np_array_less_than_2d', 'object_has_single_value', 'optional_parameter_spec', 'normpdf', @@ -665,6 +671,32 @@ def tensor_power(items, levels:tc.optional(range)=None, flat=False): return pp +# LIST MANAGEMENT ****************************************************************************************************** + +def insert_list(list1, position, list2): + """Insert list2 into list1 at position""" + return list1[:position] + list2 + list1[position:] + +def convert_to_list(l): + if l is None: + return None + elif isinstance(l, list): + return l + elif isinstance(l, ContentAddressableList): + return list(l) + elif isinstance(l, set): + return list(l) + else: + return [l] + +def flatten_list(l): + return [item for sublist in l for item in sublist] + +def nesting_depth(l): + if isinstance(l, np.ndarray): + l = l.tolist() + return isinstance(l, list) and max(map(nesting_depth, l)) + 1 + # OTHER **************************************************************************************************************** @@ -769,7 +801,7 @@ def copy_iterable_with_shared(obj, shared_types=None, memo=None): dict_types = (dict, collections.UserDict) list_types = (list, collections.UserList, collections.deque) - tuple_types = (tuple, ) + tuple_types = (tuple, set) all_types_using_recursion = dict_types + list_types + tuple_types if isinstance(obj, dict_types): @@ -1379,9 +1411,15 @@ def get_values_as_lists(self, context=None): def is_value_spec(spec): + from psyneulink.core.components.component import Component + if isinstance(spec, (numbers.Number, np.ndarray)): return True - elif isinstance(spec, list) and is_numeric(spec): + elif ( + isinstance(spec, list) + and is_numeric(spec) + and not contains_type(spec, (Component, types.FunctionType)) + ): return True else: return False @@ -1518,28 +1556,6 @@ def convert_all_elements_to_np_array(arr, cast_from=None, cast_to=None): return elementwise_subarr - -def insert_list(list1, position, list2): - """Insert list2 into list1 at position""" - return list1[:position] + list2 + list1[position:] - - -def convert_to_list(l): - if l is None: - return None - elif isinstance(l, list): - return l - elif isinstance(l, ContentAddressableList): - return list(l) - elif isinstance(l, set): - return list(l) - else: - return [l] - -def flatten_list(l): - return [item for sublist in l for item in sublist] - - # Seeds and randomness class SeededRandomState(np.random.RandomState): @@ -1913,3 +1929,17 @@ def contains_type( pass return False + + +def _is_module_class(class_: type, module: types.ModuleType) -> bool: + """ + Returns: + bool: True if **class_** is a member of **module**, False otherwise + """ + if module.__name__ == class_.__module__: + try: + return class_ is getattr(module, class_.__name__) + except AttributeError: + pass + + return False diff --git a/psyneulink/core/llvm/__init__.py b/psyneulink/core/llvm/__init__.py index e971df3d616..f59a46e4dde 100644 --- a/psyneulink/core/llvm/__init__.py +++ b/psyneulink/core/llvm/__init__.py @@ -13,6 +13,7 @@ import functools import numpy as np import time +from math import ceil, log2 from typing import Set from llvmlite import ir @@ -129,12 +130,38 @@ def _cuda_kernel(self): self.__cuda_kernel = _ptx_engine.get_kernel(self.name) return self.__cuda_kernel - def cuda_call(self, *args, threads=1, block_size=128): + def cuda_max_block_size(self, override): + if override is not None: + return override + + kernel = self._cuda_kernel + device = jit_engine.pycuda.autoinit.device + + if kernel.shared_size_bytes > 0: + # we use shared memory, prefer big blocks. + # Limited by reg usage + rounded_regs = 2 ** ceil(log2(kernel.num_regs)) + block_size = device.get_attribute(jit_engine.pycuda.driver.device_attribute.MAX_REGISTERS_PER_BLOCK) // rounded_regs + else: + # Use smallest possible blocks + block_size = device.get_attribute(jit_engine.pycuda.driver.device_attribute.WARP_SIZE) + + block_size = min(device.get_attribute(jit_engine.pycuda.driver.device_attribute.MAX_THREADS_PER_BLOCK), block_size) + if "stat" in debug_env: + print("kernel '", self.name, "' registers:", kernel.num_regs) + print("kernel '", self.name, "' local memory size:", kernel.local_size_bytes) + print("kernel '", self.name, "' shared memory size:", kernel.shared_size_bytes) + print("kernel '", self.name, "' selected block size:", block_size) + + return block_size + + def cuda_call(self, *args, threads=1, block_size=None): + block_size = self.cuda_max_block_size(block_size) grid = ((threads + block_size - 1) // block_size, 1) self._cuda_kernel(*args, np.int32(threads), block=(block_size, 1, 1), grid=grid) - def cuda_wrap_call(self, *args, threads=1, block_size=128): + def cuda_wrap_call(self, *args, threads=1, block_size=None): wrap_args = (jit_engine.pycuda.driver.InOut(a) if isinstance(a, np.ndarray) else a for a in args) self.cuda_call(*wrap_args, threads=threads, block_size=block_size) diff --git a/psyneulink/core/llvm/builder_context.py b/psyneulink/core/llvm/builder_context.py index 42a95aa9fc1..6fa5af54287 100644 --- a/psyneulink/core/llvm/builder_context.py +++ b/psyneulink/core/llvm/builder_context.py @@ -179,15 +179,20 @@ def init_builtins(self): def get_uniform_dist_function_by_state(self, state): if len(state.type.pointee) == 5: return self.import_llvm_function("__pnl_builtin_mt_rand_double") - if len(state.type.pointee) == 7: + elif len(state.type.pointee) == 7: + # we have different versions based on selected FP precision return self.import_llvm_function("__pnl_builtin_philox_rand_{}".format(str(self.float_ty))) + else: + assert False, "Unknown PRNG type!" def get_normal_dist_function_by_state(self, state): if len(state.type.pointee) == 5: return self.import_llvm_function("__pnl_builtin_mt_rand_normal") - if len(state.type.pointee) == 7: + elif len(state.type.pointee) == 7: # Normal exists only for self.float_ty return self.import_llvm_function("__pnl_builtin_philox_rand_normal") + else: + assert False, "Unknown PRNG type!" def get_builtin(self, name: str, args=[], function_type=None): if name in _builtin_intrinsics: @@ -272,6 +277,8 @@ def get_random_state_ptr(self, builder, component, state, params): reseed_f = self.get_builtin("mt_rand_init") elif seed_idx == 6: reseed_f = self.get_builtin("philox_rand_init") + else: + assert False, "Unknown PRNG type!" builder.call(reseed_f, [random_state_ptr, new_seed]) @@ -340,6 +347,7 @@ def get_output_struct_type(self, component): @_comp_cached def get_param_struct_type(self, component): + from psyneulink.core.components.mechanisms.modulatory.control.optimizationcontrolmechanism import NUM_ESTIMATES self._stats["param_structs_generated"] += 1 if hasattr(component, '_get_param_struct_type'): return component._get_param_struct_type(self) @@ -353,8 +361,6 @@ def _param_struct(p): return ir.LiteralStructType(self.get_param_struct_type(x) for x in val) elif p.name == 'matrix': # Flatten matrix val = np.asfarray(val).flatten() - elif p.name == 'num_estimates': # Should always be int - val = np.int32(0) if val is None else np.int32(val) elif p.name == 'num_trials_per_estimate': # Should always be int val = np.int32(0) if val is None else np.int32(val) elif np.ndim(val) == 0 and component._is_param_modulated(p): @@ -477,18 +483,76 @@ def _gen_cuda_kernel_wrapper_module(function): tid_x_f = ir.Function(module, intrin_ty, "llvm.nvvm.read.ptx.sreg.tid.x") ntid_x_f = ir.Function(module, intrin_ty, "llvm.nvvm.read.ptx.sreg.ntid.x") ctaid_x_f = ir.Function(module, intrin_ty, "llvm.nvvm.read.ptx.sreg.ctaid.x") - global_id = builder.mul(builder.call(ctaid_x_f, []), builder.call(ntid_x_f, [])) - global_id = builder.add(global_id, builder.call(tid_x_f, [])) - # Check global id and exit if we're over - should_quit = builder.icmp_unsigned(">=", global_id, kernel_func.args[-1]) - with builder.if_then(should_quit): - builder.ret_void() + # Number of threads per block + ntid = builder.call(ntid_x_f, []) + # Thread ID in block + tid = builder.call(tid_x_f, []) + + global_id = builder.mul(builder.call(ctaid_x_f, []), ntid) + global_id = builder.add(global_id, tid) # Index all pointer arguments. Ignore the thread count argument args = list(kernel_func.args)[:-1] indexed_args = [] + # pointer args do not alias + for a in args: + if isinstance(a.type, ir.PointerType): + a.attributes.add('noalias') + + def _upload_to_shared(b, ptr, name): + shared = ir.GlobalVariable(module, ptr.type.pointee, + name=function.name + "_shared_" + name, + addrspace=3) + shared.alignment = 128 + shared.linkage = "internal" + shared_ptr = b.addrspacecast(shared, shared.type.pointee.as_pointer()) + + char_ptr_ty = ir.IntType(8).as_pointer() + bool_ty = ir.IntType(1) + + ptr_src = b.bitcast(ptr, char_ptr_ty) + ptr_dst = b.bitcast(shared_ptr, char_ptr_ty) + + obj_size_ty = ir.FunctionType(ir.IntType(32), [char_ptr_ty, bool_ty, bool_ty, bool_ty]) + obj_size_f = module.declare_intrinsic("llvm.objectsize.i32", [], obj_size_ty) + # the params are: obj pointer, 0 on unknown size, NULL is unknown, size at runtime + obj_size = b.call(obj_size_f, [ptr_dst, bool_ty(1), bool_ty(0), bool_ty(0)]) + + if "unaligned_copy" not in debug_env: + copy_ty = ir.IntType(32) + copy_ptr_ty = copy_ty.as_pointer() + copy_bytes = copy_ty.width // 8 + obj_size = builder.add(obj_size, obj_size.type(copy_bytes - 1)) + obj_size = builder.udiv(obj_size, obj_size.type(copy_bytes)) + ptr_src = builder.bitcast(ptr, copy_ptr_ty) + ptr_dst = builder.bitcast(shared_ptr, copy_ptr_ty) + + + # copy data using as many threads as available in thread group + with helpers.for_loop(b, tid, obj_size, ntid, id="copy_" + name) as (b1, i): + src = b1.gep(ptr_src, [i]) + dst = b1.gep(ptr_dst, [i]) + b1.store(b1.load(src), dst) + + sync_threads_ty = ir.FunctionType(ir.VoidType(), []) + sync_threads = module.declare_intrinsic("llvm.nvvm.barrier0", [], sync_threads_ty) + builder.call(sync_threads, []) + + return b, shared_ptr + + if is_grid_ranged and "cuda_no_shared" not in debug_env: + builder, args[0] = _upload_to_shared(builder, args[0], "params") + builder, args[1] = _upload_to_shared(builder, args[1], "state") + builder, args[3] = _upload_to_shared(builder, args[3], "inputs") + builder, args[4] = _upload_to_shared(builder, args[4], "data") + + # Check global id and exit if we're over + should_quit = builder.icmp_unsigned(">=", global_id, kernel_func.args[-1]) + with builder.if_then(should_quit): + builder.ret_void() + # If we're calling ranged search there are no offsets if is_grid_ranged: next_id = builder.add(global_id, global_id.type(1)) @@ -497,11 +561,6 @@ def _gen_cuda_kernel_wrapper_module(function): builder.ret_void() return module - - # There are 6 arguments to evaluate: - # comp_param, comp_state, allocations, output, input, comp_data - is_grid_evaluate = len(args) == 6 - # Runs need special handling. data_in and data_out are one dimensional, # but hold entries for all parallel invocations. # comp_state, comp_params, comp_data, comp_in, comp_out, #trials, #inputs @@ -522,14 +581,11 @@ def _gen_cuda_kernel_wrapper_module(function): offset = builder.mul(global_id, runs_count) elif i == 3: # data_in offset = builder.mul(global_id, input_count) - elif is_grid_evaluate: - # all but #2 and #3 are shared - if i != 2 and i != 3: - offset = ir.IntType(32)(0) arg = builder.gep(arg, [offset]) indexed_args.append(arg) + builder.call(decl_f, indexed_args) builder.ret_void() diff --git a/psyneulink/core/llvm/builtins.py b/psyneulink/core/llvm/builtins.py index 859a740af0c..a64be3d4c6a 100644 --- a/psyneulink/core/llvm/builtins.py +++ b/psyneulink/core/llvm/builtins.py @@ -543,13 +543,13 @@ def _setup_mt_rand_init(ctx, state_ty, init_scalar): builder.call(init_scalar, [state, default_seed]) # python considers everything to be an array - key_array = builder.alloca(ir.ArrayType(seed.type, 1)) + key_array = builder.alloca(ir.ArrayType(seed.type, 1), name="key_array") key_p = builder.gep(key_array, [ctx.int32_ty(0), ctx.int32_ty(0)]) builder.store(seed, key_p) - pi = builder.alloca(ctx.int32_ty) + pi = builder.alloca(ctx.int32_ty, name="pi_slot") builder.store(ctx.int32_ty(1), pi) - pj = builder.alloca(ctx.int32_ty) + pj = builder.alloca(ctx.int32_ty, name="pj_slot") builder.store(ctx.int32_ty(0), pj) array = builder.gep(state, [ctx.int32_ty(0), ctx.int32_ty(0)]) a_0 = builder.gep(array, [ctx.int32_ty(0), ctx.int32_ty(0)]) @@ -640,8 +640,8 @@ def _setup_mt_rand_integer(ctx, state_ty): cond = builder.icmp_signed(">=", idx, ctx.int32_ty(_MERSENNE_N)) with builder.if_then(cond, likely=False): mag01 = ir.ArrayType(array.type.pointee.element, 2)([0, 0x9908b0df]) - pmag01 = builder.alloca(mag01.type) - builder.store(mag01, pmag01) + mag0 = builder.extract_value(mag01, [0]) + mag1 = builder.extract_value(mag01, [1]) with helpers.for_loop_zero_inc(builder, ctx.int32_ty(_MERSENNE_N - _MERSENNE_M), @@ -653,9 +653,9 @@ def _setup_mt_rand_integer(ctx, state_ty): val_kk_1 = b.and_(b.load(pkk_1), pkk_1.type.pointee(0x7fffffff)) val = b.or_(val_kk, val_kk_1) - val_1 = b.and_(val, val.type(1)) - pval_mag = b.gep(pmag01, [ctx.int32_ty(0), val_1]) - val_mag = b.load(pval_mag) + val_i1 = b.and_(val, val.type(1)) + val_b = b.trunc(val_i1, ctx.bool_ty) + val_mag = b.select(val_b, mag1, mag0) val_shift = b.lshr(val, val.type(1)) @@ -681,9 +681,9 @@ def _setup_mt_rand_integer(ctx, state_ty): val_kk_1 = b.and_(b.load(pkk_1), pkk.type.pointee(0x7fffffff)) val = b.or_(val_kk, val_kk_1) - val_1 = b.and_(val, val.type(1)) - pval_mag = b.gep(pmag01, [ctx.int32_ty(0), val_1]) - val_mag = b.load(pval_mag) + val_i1 = b.and_(val, val.type(1)) + val_b = b.trunc(val_i1, ctx.bool_ty) + val_mag = b.select(val_b, mag1, mag0) val_shift = b.lshr(val, val.type(1)) @@ -741,10 +741,10 @@ def _setup_mt_rand_float(ctx, state_ty, gen_int): builder = _setup_builtin_func_builder(ctx, "mt_rand_double", (state_ty.as_pointer(), ctx.float_ty.as_pointer())) state, out = builder.function.args - al = builder.alloca(gen_int.args[1].type.pointee) + al = builder.alloca(gen_int.args[1].type.pointee, name="al_gen_int") builder.call(gen_int, [state, al]) - bl = builder.alloca(gen_int.args[1].type.pointee) + bl = builder.alloca(gen_int.args[1].type.pointee, name="bl_gen_int") builder.call(gen_int, [state, bl]) a = builder.load(al) @@ -802,7 +802,7 @@ def _setup_mt_rand_normal(ctx, state_ty, gen_float): builder.branch(loop_block) builder.position_at_end(loop_block) - tmp = builder.alloca(out.type.pointee) + tmp = builder.alloca(out.type.pointee, name="mt_rand_normal_tmp") # X1 is in (-1, 1) builder.call(gen_float, [state, tmp]) @@ -1085,7 +1085,7 @@ def _setup_philox_rand_int32(ctx, state_ty, gen_int64): builder.ret_void() - val_ptr = builder.alloca(gen_int64.args[1].type.pointee) + val_ptr = builder.alloca(gen_int64.args[1].type.pointee, name="rand_i64") builder.call(gen_int64, [state, val_ptr]) val = builder.load(val_ptr) @@ -1112,7 +1112,7 @@ def _setup_philox_rand_double(ctx, state_ty, gen_int64): rhs = double_ty(1.0 / 9007199254740992.0) # Generate random integer - lhs_ptr = builder.alloca(gen_int64.args[1].type.pointee) + lhs_ptr = builder.alloca(gen_int64.args[1].type.pointee, name="rand_int64") builder.call(gen_int64, [state, lhs_ptr]) # convert to float @@ -1138,7 +1138,7 @@ def _setup_philox_rand_float(ctx, state_ty, gen_int32): rhs = float_ty(1.0 / 8388608.0) # Generate random integer - lhs_ptr = builder.alloca(gen_int32.args[1].type.pointee) + lhs_ptr = builder.alloca(gen_int32.args[1].type.pointee, name="rand_int32") builder.call(gen_int32, [state, lhs_ptr]) # convert to float @@ -1880,8 +1880,8 @@ def _setup_philox_rand_normal(ctx, state_ty, gen_float, gen_int, wi_data, ki_dat # Allocate storage for calling int/float PRNG # outside of the loop - tmp_fptype = builder.alloca(fptype) - tmp_itype = builder.alloca(itype) + tmp_fptype = builder.alloca(fptype, name="tmp_fp") + tmp_itype = builder.alloca(itype, name="tmp_int") # Enter the main generation loop builder.branch(loop_block) diff --git a/psyneulink/core/llvm/codegen.py b/psyneulink/core/llvm/codegen.py index 1ad7df72155..7b8258e077b 100644 --- a/psyneulink/core/llvm/codegen.py +++ b/psyneulink/core/llvm/codegen.py @@ -22,10 +22,9 @@ from .debug import debug_env class UserDefinedFunctionVisitor(ast.NodeVisitor): - def __init__(self, ctx, var_builder, builder, func_globals, func_params, arg_in, arg_out): + def __init__(self, ctx, builder, func_globals, func_params, arg_in, arg_out): self.ctx = ctx self.builder = builder - self.var_builder = var_builder self.func_params = func_params self.arg_in = arg_in self.arg_out = arg_out @@ -100,6 +99,37 @@ def visit_arguments(self, node): else: self.register[param.arg] = self.func_params[param.arg] + def visit_FunctionDef(self, node): + # the current position will be used to create temp space + # for local variables. This block dominates all others + # generated by this visitor. + self.var_builder = self.builder + + # Create a new basic block to house the generated code + udf_block = self.builder.append_basic_block(name="udf_body") + self.builder = ir.IRBuilder(udf_block) + + super().generic_visit(node) + + if not self.builder.block.is_terminated: + # the function didn't use return as the last statement + # e.g. only includes 'return' statements in if blocks + self.builder.ret_void() + + # No more local variables at this point + self.var_builder.branch(udf_block) + return self.builder + + def visit_Lambda(self, node): + self.visit(node.args) + expr = self.visit(node.body) + + # store the lambda expression in the result and terminate + self.builder.store(expr, self.arg_out) + self.builder.ret_void() + + return self.builder + def visit_Add(self, node): def _add(builder, x, y): assert helpers.is_floating_point(x) @@ -133,13 +163,13 @@ def _div(builder, x, y): return _div def visit_Pow(self, node): - def _div(builder, x, y): + def _pow(builder, x, y): assert helpers.is_floating_point(x) assert helpers.is_floating_point(y) - pow_f = ctx.get_builtin("pow", [x.type, y.type]) + pow_f = self.ctx.get_builtin("pow", [x.type, y.type]) return builder.call(pow_f, [x, y]) - return _div + return _pow def visit_USub(self, node): def _usub(builder, x): @@ -208,7 +238,7 @@ def visit_Assign(self, node): for t in node.targets: target = self.visit(t) if target is None: # Allocate space for new variable - target = self.var_builder.alloca(value.type) + target = self.var_builder.alloca(value.type, name=str(t.id) + '_local_variable') self.register[t.id] = target assert self.is_lval(target) self.builder.store(value, target) @@ -543,13 +573,15 @@ def gen_node_wrapper(ctx, composition, node, *, tags:frozenset): # And we run no further projection incoming_projections = [] elif not is_mech: - node_in = builder.alloca(node_function.args[2].type.pointee) + node_in = builder.alloca(node_function.args[2].type.pointee, + name="composition_node_input") incoming_projections = node.input_CIM.afferents + node.parameter_CIM.afferents else: # this path also handles parameter_CIM with no afferent # projections. 'comp_in' does not include any extra values, # and the entire call should be optimized out. - node_in = builder.alloca(node_function.args[2].type.pointee) + node_in = builder.alloca(node_function.args[2].type.pointee, + name="mechanism_node_input") incoming_projections = node.afferents if "reset" in tags or "is_finished" in tags: @@ -584,9 +616,10 @@ def gen_node_wrapper(ctx, composition, node, *, tags:frozenset): ctx.int32_ty(parent_idx), ctx.int32_ty(output_port_idx)]) - # Get location of projection output (in mechanism's input structure + # Get location of projection output (in mechanism's input structure) rec_port = proj.receiver - assert rec_port.owner is node or rec_port.owner is node.input_CIM or rec_port.owner is node.parameter_CIM + assert not is_mech or rec_port.owner is node + assert is_mech or rec_port.owner is node.input_CIM or rec_port.owner is node.parameter_CIM indices = [0] if proj in rec_port.owner.path_afferents: rec_port_idx = rec_port.owner.input_ports.index(rec_port) @@ -623,7 +656,13 @@ def gen_node_wrapper(ctx, composition, node, *, tags:frozenset): if proj_out.type != proj_function.args[3].type: warnings.warn("Shape mismatch: Projection ({}) results does not match the receiver state({}) input: {} vs. {}".format(proj, proj.receiver, proj.defaults.value, proj.receiver.defaults.variable)) + # Check that this workaround applies only to projections to inner composition + # that are off by one dimension, but in the 'wrong' direction (we need to add one dim). + assert len(proj_function.args[3].type.pointee) == 1 + assert proj_function.args[3].type.pointee.element == proj_out.type.pointee + proj_out = builder.bitcast(proj_out, proj_function.args[3].type) + builder.call(proj_function, [proj_params, proj_state, proj_in, proj_out]) @@ -679,19 +718,12 @@ def _gen_composition_exec_context(ctx, composition, *, tags:frozenset, suffix="" for a in llvm_func.args: a.attributes.add('noalias') - state, params, comp_in, data_arg, cond, *_ = llvm_func.args + state, params, comp_in, data, cond, *_ = llvm_func.args if "const_params" in debug_env: const_params = params.type.pointee(composition._get_param_initializer(None)) params = builder.alloca(const_params.type, name="const_params_loc") builder.store(const_params, params) - if "alloca_data" in debug_env: - data = builder.alloca(data_arg.type.pointee) - data_vals = builder.load(data_arg) - builder.store(data_vals, data) - else: - data = data_arg - node_tags = tags.union({"node_wrapper"}) # Call input CIM input_cim_w = ctx.get_node_wrapper(composition, composition.input_CIM) @@ -705,10 +737,6 @@ def _gen_composition_exec_context(ctx, composition, *, tags:frozenset, suffix="" yield builder, data, params, cond_gen - if "alloca_data" in debug_env: - data_vals = builder.load(data) - builder.store(data_vals, data_arg) - # Bump run counter cond_gen.bump_ts(builder, cond, (1, 0, 0)) @@ -725,7 +753,7 @@ def gen_composition_exec(ctx, composition, *, tags:frozenset): nodes_states = helpers.get_state_ptr(builder, composition, state, "nodes") # Allocate temporary output storage - output_storage = builder.alloca(data.type.pointee, name="output_storage") + output_storage = builder.alloca(data.type.pointee, name="comp_output_frozen_temp") # Get locations of number of executions. num_exec_locs = {} @@ -745,6 +773,8 @@ def gen_composition_exec(ctx, composition, *, tags:frozenset): # Reset internal TRIAL/PASS/TIME_STEP clock for each node + # This also resets TIME_STEP counter for input_CIM and parameter_CIM + # executed above for time_loc in num_exec_locs.values(): for scale in (TimeScale.TRIAL, TimeScale.PASS, TimeScale.TIME_STEP): num_exec_time_ptr = builder.gep(time_loc, [ctx.int32_ty(0), @@ -761,7 +791,7 @@ def gen_composition_exec(ctx, composition, *, tags:frozenset): continue reinit_cond = cond_gen.generate_sched_condition( - builder, when, cond, node, is_finished_callbacks, num_exec_locs) + builder, when, cond, node, is_finished_callbacks, num_exec_locs, nodes_states) with builder.if_then(reinit_cond): node_w = ctx.get_node_wrapper(composition, node) node_reinit_f = ctx.import_llvm_function(node_w, tags=node_tags.union({"reset"})) @@ -795,7 +825,7 @@ def gen_composition_exec(ctx, composition, *, tags:frozenset): trial_term_cond = cond_gen.generate_sched_condition( builder, composition.termination_processing[TimeScale.TRIAL], - cond, None, is_finished_callbacks, num_exec_locs) + cond, None, is_finished_callbacks, num_exec_locs, nodes_states) trial_cond = builder.not_(trial_term_cond, name="not_trial_term_cond") loop_body = builder.append_basic_block(name="scheduling_loop_body") @@ -805,6 +835,8 @@ def gen_composition_exec(ctx, composition, *, tags:frozenset): # Generate loop body builder.position_at_end(loop_body) + previous_step = builder.load(run_set_ptr) + zero = ctx.int32_ty(0) any_cond = ctx.bool_ty(0) # Calculate execution set before running the mechanisms @@ -814,7 +846,7 @@ def gen_composition_exec(ctx, composition, *, tags:frozenset): name="run_cond_ptr_" + node.name) node_cond = cond_gen.generate_sched_condition( builder, composition._get_processing_condition_set(node), - cond, node, is_finished_callbacks, num_exec_locs) + cond, node, is_finished_callbacks, num_exec_locs, nodes_states) ran = cond_gen.generate_ran_this_pass(builder, cond, node) node_cond = builder.and_(node_cond, builder.not_(ran), name="run_cond_" + node.name) @@ -822,12 +854,15 @@ def gen_composition_exec(ctx, composition, *, tags:frozenset): builder.store(node_cond, run_set_node_ptr) # Reset internal TIME_STEP clock for each node - # NOTE: This is done _after_ condition evluation, otherwise + # NOTE: This is done _after_ condition evaluation, otherwise # TIME_STEP related conditions will only see 0 executions - for time_loc in num_exec_locs.values(): - num_exec_time_ptr = builder.gep(time_loc, [ctx.int32_ty(0), - ctx.int32_ty(TimeScale.TIME_STEP.value)]) - builder.store(num_exec_time_ptr.type.pointee(0), num_exec_time_ptr) + for idx, node in enumerate(composition.nodes): + ran_prev_step = builder.extract_value(previous_step, [idx]) + time_loc = num_exec_locs[node] + with builder.if_then(ran_prev_step): + num_exec_time_ptr = builder.gep(time_loc, [ctx.int32_ty(0), + ctx.int32_ty(TimeScale.TIME_STEP.value)]) + builder.store(num_exec_time_ptr.type.pointee(0), num_exec_time_ptr) for idx, node in enumerate(composition.nodes): @@ -926,6 +961,9 @@ def gen_composition_run(ctx, composition, *, tags:frozenset): a.attributes.add('noalias') state, params, data, data_in, data_out, trials_ptr, inputs_ptr = llvm_func.args + + nodes_states = helpers.get_state_ptr(builder, composition, state, "nodes") + # simulation does not care about the output # it extracts results of the controller objective mechanism if simulation: @@ -933,7 +971,7 @@ def gen_composition_run(ctx, composition, *, tags:frozenset): if not simulation and "const_data" in debug_env: const_data = data.type.pointee(composition._get_data_initializer(None)) - data = builder.alloca(data.type.pointee) + data = builder.alloca(data.type.pointee, name="const_data_loc") builder.store(const_data, data) # Hardcode stateful parameters if set in the environment @@ -953,15 +991,22 @@ def gen_composition_run(ctx, composition, *, tags:frozenset): builder.store(data_in.type.pointee(input_init), data_in) builder.store(inputs_ptr.type.pointee(1), inputs_ptr) + # Reset internal 'RUN' clocks of each node + for idx, node in enumerate(composition._all_nodes): + node_state = builder.gep(state, [ctx.int32_ty(0), ctx.int32_ty(0), ctx.int32_ty(idx)]) + num_executions_ptr = helpers.get_state_ptr(builder, node, node_state, "num_executions") + num_exec_time_ptr = builder.gep(num_executions_ptr, [ctx.int32_ty(0), ctx.int32_ty(TimeScale.RUN.value)]) + builder.store(num_exec_time_ptr.type.pointee(0), num_exec_time_ptr) + # Allocate and initialize condition structure cond_gen = helpers.ConditionGenerator(ctx, composition) cond_type = cond_gen.get_condition_struct_type() - cond = builder.alloca(cond_type) + cond = builder.alloca(cond_type, name="scheduler_metadata") cond_init = cond_type(cond_gen.get_condition_initializer()) builder.store(cond_init, cond) trials = builder.load(trials_ptr, "trials") - iters_ptr = builder.alloca(trials.type) + iters_ptr = builder.alloca(trials.type, name="iterations") builder.store(iters_ptr.type.pointee(0), iters_ptr) # Start the main loop structure @@ -973,7 +1018,7 @@ def gen_composition_run(ctx, composition, *, tags:frozenset): run_term_cond = cond_gen.generate_sched_condition( builder, composition.termination_processing[TimeScale.RUN], - cond, None, None, None) + cond, None, None, None, nodes_states) run_cond = builder.not_(run_term_cond, name="not_run_term_cond") # Iter cond @@ -997,13 +1042,6 @@ def gen_composition_run(ctx, composition, *, tags:frozenset): input_idx = builder.urem(iters, builder.load(inputs_ptr)) data_in_ptr = builder.gep(data_in, [input_idx]) - # Reset internal 'RUN' clocks of each node - for idx, node in enumerate(composition._all_nodes): - node_state = builder.gep(state, [ctx.int32_ty(0), ctx.int32_ty(0), ctx.int32_ty(idx)]) - num_executions_ptr = helpers.get_state_ptr(builder, node, node_state, "num_executions") - num_exec_time_ptr = builder.gep(num_executions_ptr, [ctx.int32_ty(0), ctx.int32_ty(TimeScale.RUN.value)]) - builder.store(num_exec_time_ptr.type.pointee(0), num_exec_time_ptr) - # Call execution exec_tags = tags.difference({"run"}) exec_f = ctx.import_llvm_function(composition, tags=exec_tags) diff --git a/psyneulink/core/llvm/debug.py b/psyneulink/core/llvm/debug.py index ec9ccaa50f6..0a6788f838d 100644 --- a/psyneulink/core/llvm/debug.py +++ b/psyneulink/core/llvm/debug.py @@ -19,12 +19,10 @@ * "compile" -- prints information messages when modules are compiled * "stat" -- prints code generation and compilation statistics * "time_stat" -- print compilation and code generation times - * "cuda_data" -- print data upload/download statistic (to GPU VRAM) * "comp_node_debug" -- print intermediate results after execution composition node wrapper. * "print_values" -- Enabled printfs in llvm code (from ctx printf helper) Compilation modifiers: - * "alloca_data" -- use alloca'd storage for composition data (exposes data flow) * "debug_info" -- emit line debugging information when generating LLVM IR * "const_data" -- hardcode initial output values into generated code, instead of loading them from the data argument @@ -34,13 +32,18 @@ * "const_state" -- hardcode base context values into generate code, instead of laoding them from the context argument * "opt" -- Set compiler optimization level (0,1,2,3) - * "cuda_max_regs" -- Set maximum allowed GPU arch registers + * "unaligned_copy" -- Do not assume structures are 4B aligned + +CUDA options: + * "cuda_max_regs" -- Set maximum allowed GPU arch registers. + Equivalent to the CUDA JIT compiler option of the same name. + * "cuda_no_shared" -- Do not use on-chip 'shared' memory in generated code. Compiled code dump: - * "llvm" -- dumps LLVM IR into a file (named after the dumped module). - Code is dumped both after module generation and linking into global module. - * "opt" -- dump LLVM IR after running through the optimization passes - * "isa" -- dump machine specific ISA + * "dump-llvm-gen" -- Dumps LLVM IR generated by us into a file (named after the dumped module). + IR is dumped both after module generation and linking into global module. + * "dump-llvm-opt" -- Dump LLVM IR after running through the optimization passes. + * "dump-asm" -- Dump machine specific asm, fed to the JIT engine (currently CPU ISA, or PTX). """ import os diff --git a/psyneulink/core/llvm/execution.py b/psyneulink/core/llvm/execution.py index ac722dd9d77..ff7a2defdd6 100644 --- a/psyneulink/core/llvm/execution.py +++ b/psyneulink/core/llvm/execution.py @@ -110,7 +110,7 @@ def __init__(self, buffers=['param_struct', 'state_struct', 'out']): self._downloaded_bytes = Counter() def __del__(self): - if "cuda_data" in self._debug_env: + if "stat" in self._debug_env: try: name = self._bin_func.name except AttributeError: @@ -132,7 +132,10 @@ def _bin_func_multirun(self): def upload_ctype(self, data, name='other'): self._uploaded_bytes[name] += ctypes.sizeof(data) - assert ctypes.sizeof(data) != 0 + if ctypes.sizeof(data) == 0: + # 0-sized structures fail to upload + # provide a small device buffer instead + return jit_engine.pycuda.driver.mem_alloc(4) return jit_engine.pycuda.driver.to_device(bytearray(data)) def download_ctype(self, source, ty, name='other'): diff --git a/psyneulink/core/llvm/helpers.py b/psyneulink/core/llvm/helpers.py index dce10f5ba15..6b54aaf4bde 100644 --- a/psyneulink/core/llvm/helpers.py +++ b/psyneulink/core/llvm/helpers.py @@ -10,12 +10,16 @@ from contextlib import contextmanager from ctypes import util +import warnings +import sys from llvmlite import ir +import llvmlite.binding as llvm + from .debug import debug_env from psyneulink.core.scheduling.condition import All, AllHaveRun, Always, Any, AtPass, AtTrial, BeforeNCalls, AtNCalls, AfterNCalls, \ - EveryNCalls, Never, Not, WhenFinished, WhenFinishedAny, WhenFinishedAll + EveryNCalls, Never, Not, WhenFinished, WhenFinishedAny, WhenFinishedAll, Threshold from psyneulink.core.scheduling.time import TimeScale @@ -62,6 +66,37 @@ def array_ptr_loop(builder, array, id): stop = ir.IntType(32)(array.type.pointee.count) return for_loop_zero_inc(builder, stop, id) +def memcpy(builder, dst, src): + + bool_ty = ir.IntType(1) + char_ptr_ty = ir.IntType(8).as_pointer() + ptr_src = builder.bitcast(src, char_ptr_ty) + ptr_dst = builder.bitcast(dst, char_ptr_ty) + + obj_size_ty = ir.FunctionType(ir.IntType(64), [char_ptr_ty, bool_ty, bool_ty, bool_ty]) + obj_size_f = builder.function.module.declare_intrinsic("llvm.objectsize.i64", [], obj_size_ty) + # the params are: obj pointer, 0 on unknown size, NULL is unknown, size at runtime + obj_size = builder.call(obj_size_f, [ptr_dst, bool_ty(1), bool_ty(0), bool_ty(0)]) + + if "unaligned_copy" in debug_env: + memcpy_ty = ir.FunctionType(ir.VoidType(), [char_ptr_ty, char_ptr_ty, obj_size.type, bool_ty]) + memcpy_f = builder.function.module.declare_intrinsic("llvm.memcpy", [], memcpy_ty) + builder.call(memcpy_f, [ptr_dst, ptr_src, obj_size, bool_ty(0)]) + else: + int_ty = ir.IntType(32) + int_ptr_ty = int_ty.as_pointer() + obj_size = builder.add(obj_size, obj_size.type((int_ty.width // 8) - 1)) + obj_size = builder.udiv(obj_size, obj_size.type(int_ty.width // 8)) + ptr_src = builder.bitcast(src, int_ptr_ty) + ptr_dst = builder.bitcast(dst, int_ptr_ty) + + with for_loop_zero_inc(builder, obj_size, id="memcopy_loop") as (b, idx): + src = b.gep(ptr_src, [idx]) + dst = b.gep(ptr_dst, [idx]) + b.store(b.load(src), dst) + + return builder + def fclamp(builder, val, min_val, max_val): min_val = min_val if isinstance(min_val, ir.Value) else val.type(min_val) @@ -192,11 +227,11 @@ def is_close(ctx, builder, val1, val2, rtol=1e-05, atol=1e-08): def all_close(ctx, builder, arr1, arr2, rtol=1e-05, atol=1e-08): assert arr1.type == arr2.type - all_ptr = builder.alloca(ir.IntType(1)) + all_ptr = builder.alloca(ir.IntType(1), name="all_close_slot") builder.store(all_ptr.type.pointee(1), all_ptr) with array_ptr_loop(builder, arr1, "all_close") as (b1, idx): val1_ptr = b1.gep(arr1, [idx.type(0), idx]) - val2_ptr = b1.gep(arr1, [idx.type(0), idx]) + val2_ptr = b1.gep(arr2, [idx.type(0), idx]) val1 = b1.load(val1_ptr) val2 = b1.load(val2_ptr) res_close = is_close(ctx, b1, val1, val2, rtol, atol) @@ -208,7 +243,7 @@ def all_close(ctx, builder, arr1, arr2, rtol=1e-05, atol=1e-08): return builder.load(all_ptr) -def create_allocation(builder, allocation, search_space, idx): +def create_sample(builder, allocation, search_space, idx): # Construct allocation corresponding to this index for i in reversed(range(len(search_space.type.pointee))): slot_ptr = builder.gep(allocation, [idx.type(0), idx.type(i)]) @@ -352,14 +387,19 @@ def call_elementwise_operation(ctx, builder, x, operation, output_ptr): def printf(builder, fmt, *args, override_debug=False): if "print_values" not in debug_env and not override_debug: return + #FIXME: Fix builtin printf and use that instead of this - try: - import llvmlite.binding as llvm - libc = util.find_library("c") - llvm.load_library_permanently(libc) - # Address will be none if the symbol is not found - printf_address = llvm.address_of_symbol("printf") - except Exception as e: + libc_name = "msvcrt" if sys.platform == "win32" else "c" + libc = util.find_library(libc_name) + if libc is None: + warnings.warn("Standard libc library not found, 'printf' not available!") + return + + llvm.load_library_permanently(libc) + # Address will be none if the symbol is not found + printf_address = llvm.address_of_symbol("printf") + if printf_address is None: + warnings.warn("'printf' symbol not found in libc, 'printf' not available!") return # Direct pointer constants don't work @@ -539,8 +579,10 @@ def generate_ran_this_trial(self, builder, cond_ptr, node): return builder.icmp_signed("==", node_trial, global_trial) + # TODO: replace num_exec_locs use with equivalent from nodes_states def generate_sched_condition(self, builder, condition, cond_ptr, node, - is_finished_callbacks, num_exec_locs): + is_finished_callbacks, num_exec_locs, + nodes_states): if isinstance(condition, Always): @@ -550,13 +592,13 @@ def generate_sched_condition(self, builder, condition, cond_ptr, node, return self.ctx.bool_ty(0) elif isinstance(condition, Not): - orig_condition = self.generate_sched_condition(builder, condition.condition, cond_ptr, node, is_finished_callbacks, num_exec_locs) + orig_condition = self.generate_sched_condition(builder, condition.condition, cond_ptr, node, is_finished_callbacks, num_exec_locs, nodes_states) return builder.not_(orig_condition) elif isinstance(condition, All): agg_cond = self.ctx.bool_ty(1) for cond in condition.args: - cond_res = self.generate_sched_condition(builder, cond, cond_ptr, node, is_finished_callbacks, num_exec_locs) + cond_res = self.generate_sched_condition(builder, cond, cond_ptr, node, is_finished_callbacks, num_exec_locs, nodes_states) agg_cond = builder.and_(agg_cond, cond_res) return agg_cond @@ -580,7 +622,7 @@ def generate_sched_condition(self, builder, condition, cond_ptr, node, elif isinstance(condition, Any): agg_cond = self.ctx.bool_ty(0) for cond in condition.args: - cond_res = self.generate_sched_condition(builder, cond, cond_ptr, node, is_finished_callbacks, num_exec_locs) + cond_res = self.generate_sched_condition(builder, cond, cond_ptr, node, is_finished_callbacks, num_exec_locs, nodes_states) agg_cond = builder.or_(agg_cond, cond_res) return agg_cond @@ -668,4 +710,47 @@ def generate_sched_condition(self, builder, condition, cond_ptr, node, return run_cond + elif isinstance(condition, Threshold): + target = condition.dependency + param = condition.parameter + threshold = condition.threshold + comparator = condition.comparator + indices = condition.indices + + # Convert execution_count to ('num_executions', TimeScale.LIFE). + # These two are identical in compiled semantics. + if param == 'execution_count': + assert indices is None + param = 'num_executions' + indices = TimeScale.LIFE + + assert param in target.llvm_state_ids, ( + f"Threshold for {target} only supports items in llvm_state_ids" + f" ({target.llvm_state_ids})" + ) + + node_idx = self.composition._get_node_index(target) + node_state = builder.gep(nodes_states, [self.ctx.int32_ty(0), self.ctx.int32_ty(node_idx)]) + param_ptr = get_state_ptr(builder, target, node_state, param) + + if isinstance(param_ptr.type.pointee, ir.ArrayType): + if indices is None: + indices = [0, 0] + elif isinstance(indices, TimeScale): + indices = [indices.value] + + indices = [self.ctx.int32_ty(x) for x in [0] + list(indices)] + param_ptr = builder.gep(param_ptr, indices) + + val = builder.load(param_ptr) + val = convert_type(builder, val, ir.DoubleType()) + threshold = val.type(threshold) + + if comparator == '==': + return is_close(self.ctx, builder, val, threshold, condition.rtol, condition.atol) + elif comparator == '!=': + return builder.not_(is_close(self.ctx, builder, val, threshold, condition.rtol, condition.atol)) + else: + return builder.fcmp_ordered(comparator, val, threshold) + assert False, "Unsupported scheduling condition: {}".format(condition) diff --git a/psyneulink/core/llvm/jit_engine.py b/psyneulink/core/llvm/jit_engine.py index faf7be4918a..23815b9aa45 100644 --- a/psyneulink/core/llvm/jit_engine.py +++ b/psyneulink/core/llvm/jit_engine.py @@ -90,8 +90,8 @@ def _cpu_jit_constructor(): # And an execution engine with a builtins backing module builtins_module = _generate_cpu_builtins_module(LLVMBuilderContext.get_current().float_ty) - if "llvm" in debug_env: - with open(builtins_module.name + '.parse.ll', 'w') as dump_file: + if "dump-llvm-gen" in debug_env: + with open(builtins_module.name + '.generated.ll', 'w') as dump_file: dump_file.write(str(builtins_module)) __backing_mod = binding.parse_assembly(str(builtins_module)) @@ -103,12 +103,14 @@ def _cpu_jit_constructor(): def _ptx_jit_constructor(): _binding_initialize() - opt_level = int(debug_env.get('opt', 0)) + opt_level = int(debug_env.get('opt', 2)) - # PassManagerBuilder can be shared + # PassManagerBuilder is used only for inlining simple functions __pass_manager_builder = binding.PassManagerBuilder() - __pass_manager_builder.opt_level = opt_level - __pass_manager_builder.size_level = 1 # Try to reduce size to reduce PTX parsing time + __pass_manager_builder.opt_level = 0 + __pass_manager_builder.size_level = 1 + # The threshold of '7' is empirically selected. + __pass_manager_builder.inlining_threshold = 7 # Use default device # TODO: Add support for multiple devices @@ -116,7 +118,7 @@ def _ptx_jit_constructor(): __ptx_sm = "sm_{}{}".format(__compute_capability[0], __compute_capability[1]) # Create compilation target, use 64bit triple __ptx_target = binding.Target.from_triple("nvptx64-nvidia-cuda") - __ptx_target_machine = __ptx_target.create_target_machine(cpu=__ptx_sm) + __ptx_target_machine = __ptx_target.create_target_machine(cpu=__ptx_sm, opt=opt_level) __ptx_pass_manager = binding.ModulePassManager() __ptx_target_machine.add_analysis_passes(__ptx_pass_manager) @@ -126,8 +128,8 @@ def _ptx_jit_constructor(): def _try_parse_module(module): - if "llvm" in debug_env: - with open(module.name + '.parse.ll', 'w') as dump_file: + if "dump-llvm-gen" in debug_env: + with open(module.name + '.generated.ll', 'w') as dump_file: dump_file.write(str(module)) # IR module is not the same as binding module. @@ -177,12 +179,12 @@ def opt_and_add_bin_module(self, module): if "time_stat" in debug_env: print("Time to optimize LLVM module bundle '{}': {}".format(module.name, finish - start)) - if "opt" in self.__debug_env: + if "dump-llvm-opt" in self.__debug_env: with open(self.__class__.__name__ + '-' + str(self.__optimized_modules) + '.opt.ll', 'w') as dump_file: dump_file.write(str(module)) # This prints generated x86 assembly - if "isa" in self.__debug_env: + if "dump-asm" in self.__debug_env: with open(self.__class__.__name__ + '-' + str(self.__optimized_modules) + '.S', 'w') as dump_file: dump_file.write(self._target_machine.emit_assembly(module)) @@ -208,7 +210,7 @@ def opt_and_append_bin_module(self, module): self.__mod.link_in(module) self.__linked_modules += 1 - if "llvm" in debug_env: + if "dump-llvm-gen" in debug_env: with open(mod_name + '.linked.ll', 'w') as dump_file: dump_file.write(str(self.__mod)) @@ -356,6 +358,6 @@ def get_kernel(self, name): self.stage_compilation({wrapper_mod}) self.compile_staged() kernel = self._engine._find_kernel(name + "_cuda_kernel") - kernel.set_cache_config(pycuda.driver.func_cache.PREFER_L1) +# kernel.set_cache_config(pycuda.driver.func_cache.PREFER_L1) return kernel diff --git a/psyneulink/core/scheduling/__init__.py b/psyneulink/core/scheduling/__init__.py index fc9dcf1fed3..34b37a0528e 100644 --- a/psyneulink/core/scheduling/__init__.py +++ b/psyneulink/core/scheduling/__init__.py @@ -58,7 +58,11 @@ cls = cls_name if cls.__doc__ is None: - cls.__doc__ = f'{getattr(ext_module, cls_name).__doc__}' + try: + cls.__doc__ = f'{getattr(ext_module, cls_name).__doc__}' + except AttributeError: + # PNL-exclusive object + continue cls.__doc__ = re.sub(pattern, repl, cls.__doc__, flags=re.MULTILINE | re.DOTALL) diff --git a/psyneulink/core/scheduling/condition.py b/psyneulink/core/scheduling/condition.py index 58015b7f589..aba519892b7 100644 --- a/psyneulink/core/scheduling/condition.py +++ b/psyneulink/core/scheduling/condition.py @@ -8,18 +8,25 @@ # ********************************************* Condition ************************************************************** +import collections +import copy import functools import inspect +import numbers +import warnings import dill import graph_scheduler +import numpy as np from psyneulink.core.globals.context import handle_external_context from psyneulink.core.globals.json import JSONDumpable -from psyneulink.core.globals.keywords import MODEL_SPEC_ID_TYPE +from psyneulink.core.globals.keywords import MODEL_SPEC_ID_TYPE, comparison_operators from psyneulink.core.globals.parameters import parse_context +from psyneulink.core.globals.utilities import parse_valid_identifier -__all__ = graph_scheduler.condition.__all__ +__all__ = copy.copy(graph_scheduler.condition.__all__) +__all__.extend(['Threshold']) def _create_as_pnl_condition(condition): @@ -67,32 +74,66 @@ def is_satisfied(self, *args, context=None, execution_id=None, **kwargs): **kwargs ) - @property - def _dict_summary(self): + def as_mdf_model(self): + import modeci_mdf.mdf as mdf from psyneulink.core.components.component import Component - if type(self) is graph_scheduler.Condition: + def _parse_condition_arg(arg): + if isinstance(arg, Component): + return parse_valid_identifier(arg.name) + elif isinstance(arg, graph_scheduler.Condition): + return arg.as_mdf_model() + elif arg is None or isinstance(arg, numbers.Number): + return arg + else: + try: + iter(arg) + except TypeError: + return str(arg) + else: + return arg + + if type(self) in {graph_scheduler.Condition, Condition}: try: func_val = inspect.getsource(self.func) except OSError: func_val = dill.dumps(self.func) + func_dict = {'function': func_val} else: - func_val = None + func_dict = {} - args_list = [] - for a in self.args: - if isinstance(a, Component): - a = a.name - elif isinstance(a, graph_scheduler.Condition): - a = a._dict_summary - args_list.append(a) + extra_args = {MODEL_SPEC_ID_TYPE: getattr(graph_scheduler.condition, type(self).__name__).__name__} - return { - MODEL_SPEC_ID_TYPE: self.__class__.__name__, - 'function': func_val, - 'args': args_list, - 'kwargs': self.kwargs, - } + sig = inspect.signature(self.__init__) + + for name, param in sig.parameters.items(): + if param.kind is inspect.Parameter.VAR_POSITIONAL: + args_list = [] + for a in self.args: + if isinstance(a, Component): + a = parse_valid_identifier(a.name) + elif isinstance(a, graph_scheduler.Condition): + a = a.as_mdf_model() + args_list.append(a) + extra_args[name] = args_list + + for i, (name, param) in enumerate(filter( + lambda item: item[1].kind is inspect.Parameter.POSITIONAL_OR_KEYWORD and item[0] not in self.kwargs, + sig.parameters.items() + )): + try: + extra_args[name] = self.args[i] + except IndexError: + # was specified with keyword not as positional arg + extra_args[name] = param.default + + return mdf.Condition( + **func_dict, + **{ + k: _parse_condition_arg(v) + for k, v in (*self.kwargs.items(), *extra_args.items()) + } + ) # below produces psyneulink versions of each Condition class so that @@ -152,3 +193,106 @@ def _dict_summary(self): ) ] } + + +class Threshold(graph_scheduler.condition._DependencyValidation, Condition): + """Threshold + + Attributes: + + dependency + the node on which the Condition depends + + parameter + the name of the parameter of **dependency** whose value is + to be compared to **threshold** + + threshold + the fixed value compared to the value of the **parameter** + + comparator + the string comparison operator determining the direction or + type of comparison of the value of the **parameter** + relative to **threshold** + + indices + if specified, a series of indices that reach the desired + number given an iterable value for **parameter** + + atol + absolute tolerance for the comparison + + rtol + relative tolerance (to **threshold**) for the comparison + + Satisfied when: + + The comparison between the value of the **parameter** and + **threshold** using **comparator** is true. If **comparator** is + an equality (==, !=), the comparison will be considered equal + within tolerances **atol** and **rtol**. + + Notes: + + The comparison must be done with scalars. If the value of + **parameter** contains more than one item, **indices** must be + specified. + """ + + def __init__(self, dependency, parameter, threshold, comparator, indices=None, atol=0, rtol=0): + if comparator not in comparison_operators: + raise graph_scheduler.ConditionError( + f'Operator must be one of {list(comparison_operators.keys())}' + ) + + if parameter not in dependency.parameters: + raise graph_scheduler.ConditionError( + f'{dependency} has no {parameter} parameter' + ) + + if (atol != 0 or rtol != 0) and comparator in {'<', '<=', '>', '>='}: + warnings.warn('Tolerances for inequality comparators are ignored') + + if ( + indices is not None + and not isinstance(indices, graph_scheduler.TimeScale) + and not isinstance(indices, collections.abc.Iterable) + ): + indices = [indices] + + def func(threshold, comparator, indices, atol, rtol, execution_id): + param_value = getattr(self.dependency.parameters, self.parameter).get(execution_id) + + if isinstance(indices, graph_scheduler.TimeScale): + param_value = param_value._get_by_time_scale(indices) + elif indices is not None: + for i in indices: + param_value = param_value[i] + + param_value = float(param_value) + + if comparator == '==': + return np.isclose(param_value, threshold, atol=atol, rtol=rtol) + elif comparator == '!=': + return not np.isclose(param_value, threshold, atol=atol, rtol=rtol) + else: + return comparison_operators[comparator](param_value, threshold) + + super().__init__( + func, + dependency=dependency, + parameter=parameter, + threshold=threshold, + comparator=comparator, + indices=indices, + atol=atol, + rtol=rtol, + ) + + def as_mdf_model(self): + m = super().as_mdf_model() + + if self.parameter == 'value': + m.args['parameter'] = f'{self.dependency.name}_OutputPort_0' + + return m diff --git a/psyneulink/core/scheduling/scheduler.py b/psyneulink/core/scheduling/scheduler.py index 28e8c9b48e0..f163dc19900 100644 --- a/psyneulink/core/scheduling/scheduler.py +++ b/psyneulink/core/scheduling/scheduler.py @@ -7,6 +7,7 @@ # ********************************************* Scheduler ************************************************************** +import copy import typing import graph_scheduler @@ -15,6 +16,7 @@ from psyneulink import _unit_registry from psyneulink.core.globals.context import Context, handle_external_context from psyneulink.core.globals.json import JSONDumpable +from psyneulink.core.globals.utilities import parse_valid_identifier from psyneulink.core.scheduling.condition import _create_as_pnl_condition __all__ = [ @@ -47,6 +49,9 @@ def __init__( if default_execution_id is None: default_execution_id = composition.default_execution_id + # TODO: consider integrating something like this into graph-scheduler? + self._user_specified_conds = copy.copy(conditions) + super().__init__( graph=graph, conditions=conditions, @@ -95,18 +100,17 @@ def run( skip_environment_state_update_time_increment=skip_trial_time_increment, ) - @property - def _dict_summary(self): - return { - 'conditions': { - 'termination': { - str.lower(k.name): v._dict_summary for k, v in self.termination_conds.items() - }, - 'node_specific': { - n.name: self.conditions[n]._dict_summary for n in self.nodes if n in self.conditions - } - } - } + def as_mdf_model(self): + import modeci_mdf.mdf as mdf + + return mdf.ConditionSet( + node_specific={ + parse_valid_identifier(n.name): self.conditions[n].as_mdf_model() for n in self.nodes if n in self.conditions + }, + termination={ + str.lower(k.name): v.as_mdf_model() for k, v in self.termination_conds.items() + }, + ) @handle_external_context() def get_clock(self, context): diff --git a/psyneulink/library/components/mechanisms/modulatory/control/agt/lccontrolmechanism.py b/psyneulink/library/components/mechanisms/modulatory/control/agt/lccontrolmechanism.py index e68c13b57d1..bcee443a12e 100644 --- a/psyneulink/library/components/mechanisms/modulatory/control/agt/lccontrolmechanism.py +++ b/psyneulink/library/components/mechanisms/modulatory/control/agt/lccontrolmechanism.py @@ -844,7 +844,7 @@ def _gen_llvm_invoke_function(self, ctx, builder, function, params, state, varia elements_ty = pnlvm.ir.LiteralStructType(elements) # allocate new output type - new_out = builder.alloca(elements_ty) + new_out = builder.alloca(elements_ty, name="function_out") # Load mechanism parameters params = builder.function.args[0] diff --git a/psyneulink/library/components/mechanisms/processing/integrator/ddm.py b/psyneulink/library/components/mechanisms/processing/integrator/ddm.py index 6702cccb373..c3bac361a1d 100644 --- a/psyneulink/library/components/mechanisms/processing/integrator/ddm.py +++ b/psyneulink/library/components/mechanisms/processing/integrator/ddm.py @@ -205,10 +205,10 @@ >>> my_DDM_DriftDiffusionAnalytical = pnl.DDM( ... function=pnl.DriftDiffusionAnalytical( ... drift_rate=0.08928, - ... starting_point=0.5, + ... starting_value=0.5, ... threshold=0.2645, ... noise=0.5, - ... t0=0.15 + ... non_decision_time=0.15 ... ), ... name='my_DDM_DriftDiffusionAnalytical' ... ) @@ -229,7 +229,7 @@ ... function=pnl.DriftDiffusionIntegrator( ... noise=0.5, ... initializer=1.0, - ... starting_point=2.0, + ... non_decision_time=2.0, ... rate=3.0 ... ), ... name='my_DDM_path_integrator' @@ -266,7 +266,7 @@ function=DriftDiffusionAnalytical(drift_rate=0.1), params={ DRIFT_RATE:(0.2, ControlProjection), - STARTING_POINT:-0.5 + STARTING_VALUE:-0.5 }, ) The parameters for the DDM when `function ` is set to `DriftDiffusionAnalytical` are: @@ -281,7 +281,7 @@ component, and the input its "stimulus" component. The product of all three determines the drift rate in effect for each time_step of the decision process. .. - * `STARTING_POINT ` (default 0.0) + * `STARTING_VALUE ` (default 0.0) - specifies the starting value of the decision variable. .. * `THRESHOLD` (default 1.0) @@ -292,7 +292,7 @@ - specifies the variance of the stochastic ("diffusion") component of the decision process. .. * `NON_DECISION_TIME` (default 0.2) - specifies the `t0` parameter of the decision process (in units of seconds). + specifies the `non_decision_time` parameter of the decision process (in units of seconds). [TBI - MULTIPROCESS DDM - REPLACE BELOW] When a DDM Mechanism is executed it computes the decision process, either analytically (in TRIAL mode) @@ -315,7 +315,7 @@ created) for the next execution. ADD NOTE ABOUT INTERROGATION PROTOCOL, USING ``terminate_function`` - ADD NOTE ABOUT RELATIONSHIP OF RT TO time_steps TO t0 TO ms + ADD NOTE ABOUT RELATIONSHIP OF RT TO time_steps TO non_decision_time TO ms COMMENT .. _DDM_Execution: @@ -358,6 +358,7 @@ Class Reference --------------- """ +import sys import logging import types from collections.abc import Iterable @@ -368,7 +369,7 @@ from psyneulink.core.components.functions.function import DEFAULT_SEED, _random_state_getter, _seed_setter from psyneulink.core.components.functions.stateful.integratorfunctions import \ DriftDiffusionIntegrator, IntegratorFunction -from psyneulink.core.components.functions.nonstateful.distributionfunctions import STARTING_POINT, \ +from psyneulink.core.components.functions.nonstateful.distributionfunctions import STARTING_VALUE, \ DriftDiffusionAnalytical from psyneulink.core.components.functions.nonstateful.combinationfunctions import Reduce from psyneulink.core.components.mechanisms.modulatory.control.controlmechanism import _is_control_spec @@ -382,10 +383,13 @@ from psyneulink.core.globals.parameters import Parameter from psyneulink.core.globals.preferences.basepreferenceset import is_pref_set, REPORT_OUTPUT_PREF from psyneulink.core.globals.preferences.preferenceset import PreferenceEntry, PreferenceLevel -from psyneulink.core.globals.utilities import convert_all_elements_to_np_array, is_numeric, is_same_function_spec, object_has_single_value +from psyneulink.core.globals.utilities import convert_all_elements_to_np_array, is_numeric, is_same_function_spec, object_has_single_value, get_global_seed +from psyneulink.core.scheduling.condition import AtTrialStart from psyneulink.core import llvm as pnlvm + + __all__ = [ 'ARRAY', 'DDM', 'DDMError', 'DECISION_VARIABLE', 'DECISION_VARIABLE_ARRAY', 'PROBABILITY_LOWER_THRESHOLD', 'PROBABILITY_UPPER_THRESHOLD', 'RESPONSE_TIME', @@ -449,11 +453,19 @@ class DDM(ProcessingMechanism): ` or carrying out `step-wise numerical integration `. See `Mechanism ` for additional arguments and attributes. + The default behaviour for the DDM is to reset its integration state on each new trial, this can be overridden by + setting the `reset_stateful_function_when ` attribute to a different condition. + In addition, unlike `TransferMechamism `, the DDM's + `execute_until_finished ` + attribute is set to :code:`True` by default. This will cause the DDM to execute multiple time steps per + call to its `execute ` method until the decision threshold is reached. This default behavior can + be changed by setting `execute_until_finished ` to :code:`False`. + Arguments --------- - default_variable : value, list or np.ndarray : default FUNCTION_PARAMS[STARTING_POINT] + default_variable : value, list or np.ndarray : default FUNCTION_PARAMS[STARTING_VALUE] the input to the Mechanism used if none is provided in a call to its `execute ` or `run ` methods; also serves as a template to specify the length of the `variable ` for its `function `, and the `primary OutputPort ` of the @@ -471,7 +483,7 @@ class DDM(ProcessingMechanism): Attributes ---------- - variable : value : default FUNCTION_PARAMS[STARTING_POINT] + variable : value : default FUNCTION_PARAMS[STARTING_VALUE] the input to Mechanism's execute method. Serves as the "stimulus" component of the `function `'s **drift_rate** parameter. @@ -707,10 +719,10 @@ class Parameters(ProcessingMechanism.Parameters): function = Parameter( DriftDiffusionAnalytical( drift_rate=1.0, - starting_point=0.0, + starting_value=0.0, threshold=1.0, noise=0.5, - t0=.200, + non_decision_time=.200, ), stateful=False, loggable=False @@ -802,9 +814,7 @@ def __init__(self, FUNCTION: lambda v: [float(v[2][0][0]), 0] \ if (v[1] - v[0]) < (v[1] + v[0]) \ else [0, float(v[2][0][1])] - } - ]) # Add StandardOutputPorts for Mechanism (after ones for DDM, so that their indices are not messed up) @@ -821,7 +831,7 @@ def __init__(self, # compared to other mechanisms: see TransferMechanism.py __init__ function for a more normal example. if default_variable is None and size is None: try: - default_variable = params[FUNCTION_PARAMS][STARTING_POINT] + default_variable = params[FUNCTION_PARAMS][STARTING_VALUE] if not is_numeric(default_variable): # set normally by default default_variable = None @@ -832,7 +842,17 @@ def __init__(self, # # Conflict with above # self.size = size - self.parameters.execute_until_finished.default_value = False + # New (1/19/2021) default behaviour of DDM mechanism is to execute until finished. That + # is, it should execute until it reaches its threshold. + self.parameters.execute_until_finished.default_value = True + + # New (1/19/2021) default behavior of DDM mechanism is to reset stateful functions + # on each new trial. + if 'reset_stateful_function_when' not in kwargs: + kwargs['reset_stateful_function_when'] = AtTrialStart() + + # FIXME: Set maximum executions absurdly large to avoid early termination + self.max_executions_before_finished = sys.maxsize super(DDM, self).__init__(default_variable=default_variable, seed=seed, @@ -847,7 +867,6 @@ def __init__(self, self._instantiate_plotting_functions() - def plot(self, stimulus=1.0, threshold=10.0): """ Generate a dynamic plot of the DDM integrating over time towards a threshold. @@ -1028,7 +1047,7 @@ def _execute( :rtype self.outputPort.value: (number) """ - if variable is None or np.isnan(variable): + if variable is None or any(np.isnan(i) for i in variable): # IMPLEMENT: MULTIPROCESS DDM: ??NEED TO DEAL WITH PARTIAL NANS variable = self.defaults.variable @@ -1081,10 +1100,11 @@ def _execute( return return_value def _gen_llvm_invoke_function(self, ctx, builder, function, params, state, variable, *, tags:frozenset): + mf_out, builder = super()._gen_llvm_invoke_function(ctx, builder, function, params, state, variable, tags=tags) mech_out_ty = ctx.convert_python_struct_to_llvm_ir(self.defaults.value) - mech_out = builder.alloca(mech_out_ty) + mech_out = builder.alloca(mech_out_ty, name="mech_out") if isinstance(self.function, IntegratorFunction): # Integrator version of the DDM mechanism converts the @@ -1131,7 +1151,7 @@ def _gen_llvm_invoke_function(self, ctx, builder, function, params, state, varia mech_state = builder.function.args[1] random_state = ctx.get_random_state_ptr(builder, self, mech_state, mech_params) random_f = ctx.get_uniform_dist_function_by_state(random_state) - random_val_ptr = builder.alloca(random_f.args[1].type.pointee) + random_val_ptr = builder.alloca(random_f.args[1].type.pointee, name="random_out") builder.call(random_f, [random_state, random_val_ptr]) random_val = builder.load(random_val_ptr) diff --git a/psyneulink/library/components/mechanisms/processing/objective/comparatormechanism.py b/psyneulink/library/components/mechanisms/processing/objective/comparatormechanism.py index 0e3d9b63310..50381e88984 100644 --- a/psyneulink/library/components/mechanisms/processing/objective/comparatormechanism.py +++ b/psyneulink/library/components/mechanisms/processing/objective/comparatormechanism.py @@ -224,9 +224,9 @@ class ComparatorMechanism(ObjectiveMechanism): (see `ComparatorMechanism_Structure` for additional details). function : CombinationFunction, function or method - used to compare the `sample` with the `target`. It can be any PsyNeuLink `CombinationFunction`, - or a python function that takes a 2d array with two items and returns a 1d array of the same length - as the two input items. + used to compare the `sample` with the `target`. It can be any `CombinationFunction `, + or a python function that takes a 2d array with two items and returns a 1d array of the same length as the + two input items. output_port : OutputPort contains the `primary ` OutputPort of the ComparatorMechanism; the default is diff --git a/psyneulink/library/components/mechanisms/processing/transfer/kwtamechanism.py b/psyneulink/library/components/mechanisms/processing/transfer/kwtamechanism.py index d534b2b9b68..12c1369996e 100644 --- a/psyneulink/library/components/mechanisms/processing/transfer/kwtamechanism.py +++ b/psyneulink/library/components/mechanisms/processing/transfer/kwtamechanism.py @@ -402,13 +402,6 @@ def __init__(self, ) def _parse_function_variable(self, variable, context=None): - if variable.dtype.char == "U": - raise KWTAError( - "input ({0}) to {1} was a string, which is not supported for {2}".format( - variable, self, self.__class__.__name__ - ) - ) - return self._kwta_scale(variable, context=context) # adds indexOfInhibitionInputPort to the attributes of KWTAMechanism diff --git a/psyneulink/library/components/mechanisms/processing/transfer/lcamechanism.py b/psyneulink/library/components/mechanisms/processing/transfer/lcamechanism.py index 6b2de869bdd..9402929ec4c 100644 --- a/psyneulink/library/components/mechanisms/processing/transfer/lcamechanism.py +++ b/psyneulink/library/components/mechanisms/processing/transfer/lcamechanism.py @@ -559,7 +559,7 @@ def _parse_threshold_args(self, kwargs): if threshold is not None: if termination_threshold is not None: raise LCAError(f"The {repr('threshold')} and {repr(TERMINATION_THRESHOLD)} " - f"args of {self.__name__} can't both be specified.") + f"args of {self.__class__} can't both be specified.") else: termination_threshold = threshold else: diff --git a/psyneulink/library/components/mechanisms/processing/transfer/recurrenttransfermechanism.py b/psyneulink/library/components/mechanisms/processing/transfer/recurrenttransfermechanism.py index 56cdc5ab265..bd300b0c98c 100644 --- a/psyneulink/library/components/mechanisms/processing/transfer/recurrenttransfermechanism.py +++ b/psyneulink/library/components/mechanisms/processing/transfer/recurrenttransfermechanism.py @@ -1292,8 +1292,8 @@ def _gen_llvm_function_reset(self, ctx, builder, params, state, arg_in, arg_out, reinit_func = ctx.import_llvm_function(self.function, tags=tags) reinit_params = pnlvm.helpers.get_param_ptr(builder, self, params, "function") reinit_state = pnlvm.helpers.get_state_ptr(builder, self, state, "function") - reinit_in = builder.alloca(reinit_func.args[2].type.pointee) - reinit_out = builder.alloca(reinit_func.args[3].type.pointee) + reinit_in = builder.alloca(reinit_func.args[2].type.pointee, name="reinit_in") + reinit_out = builder.alloca(reinit_func.args[3].type.pointee, name="reinit_out") builder.call(reinit_func, [reinit_params, reinit_state, reinit_in, reinit_out]) @@ -1301,8 +1301,8 @@ def _gen_llvm_function_reset(self, ctx, builder, params, state, arg_in, arg_out, if self.integrator_mode: reinit_f = ctx.import_llvm_function(self.integrator_function, tags=tags) - reinit_in = builder.alloca(reinit_f.args[2].type.pointee) - reinit_out = builder.alloca(reinit_f.args[3].type.pointee) + reinit_in = builder.alloca(reinit_f.args[2].type.pointee, name="integ_reinit_in") + reinit_out = builder.alloca(reinit_f.args[3].type.pointee, name="integ_reinit_out") reinit_params = pnlvm.helpers.get_param_ptr(builder, self, params, "integrator_function") reinit_state = pnlvm.helpers.get_state_ptr(builder, self, state, "integrator_function") builder.call(reinit_f, [reinit_params, reinit_state, reinit_in, diff --git a/psyneulink/library/models/Cohen_Huston1994.py b/psyneulink/library/models/Cohen_Huston1994.py index 7655230cdbd..ff455921d40 100644 --- a/psyneulink/library/models/Cohen_Huston1994.py +++ b/psyneulink/library/models/Cohen_Huston1994.py @@ -272,17 +272,11 @@ # Create threshold function ------------------------------------------------------------------------------------------- - -def pass_threshold(response_layer, thresh): - results1 = response_layer.get_output_values(Bidirectional_Stroop)[0][0] # red response - results2 = response_layer.get_output_values(Bidirectional_Stroop)[0][1] # green response - if results1 >= thresh or results2 >= thresh: - return True - return False - - terminate_trial = { - pnl.TimeScale.TRIAL: pnl.While(pass_threshold, response_layer, threshold) + pnl.TimeScale.TRIAL: pnl.Or( + pnl.Threshold(response_layer, 'value', threshold, '>=', (0, 0)), + pnl.Threshold(response_layer, 'value', threshold, '>=', (0, 1)), + ) } # Create test trials function ----------------------------------------------------------------------------------------- diff --git a/psyneulink/library/models/Cohen_Huston1994_horse_race.py b/psyneulink/library/models/Cohen_Huston1994_horse_race.py index 54774e9cfdd..39365f0c08d 100644 --- a/psyneulink/library/models/Cohen_Huston1994_horse_race.py +++ b/psyneulink/library/models/Cohen_Huston1994_horse_race.py @@ -185,43 +185,45 @@ # Bidirectional_Stroop.show_graph(show_dimensions=pnl.ALL)#,show_mechanism_structure=pnl.VALUES) # Uncomment to show graph of the system -# Create threshold function ------------------------------------------------------------------------------------------- -# context is automatically passed into Conditions, and references the execution context in which they are being run, -# which in this case is simply the Bidirectional_Stroop system -def pass_threshold(response_layer, thresh, context): - results1 = response_layer.get_output_values(context)[0][0] #red response - results2 = response_layer.get_output_values(context)[0][1] #green response - if results1 >= thresh or results2 >= thresh: - return True - return False - -# 2nd threshold function -def pass_threshold2(response_layer, thresh, terminate, context): - results1 = response_layer.get_output_values(context)[0][0] #red response - results2 = response_layer.get_output_values(context)[0][1] #green response - length = response_layer.log.nparray_dictionary()[context.execution_id]['value'].shape[0] - if results1 >= thresh or results2 >= thresh: - return True - if length ==terminate: - return True - return False + +def terminate_num_executions(length, context): + return response_layer.log.nparray_dictionary()[context.execution_id]['value'].shape[0] == length # Create different terminate trial conditions -------------------------------------------------------------------------- terminate_trial = { - pnl.TimeScale.TRIAL: pnl.While(pass_threshold, response_layer, threshold) + pnl.TimeScale.TRIAL: pnl.Or( + pnl.Threshold(response_layer, 'value', threshold, '>=', (0, 0)), + pnl.Threshold(response_layer, 'value', threshold, '>=', (0, 1)), + ) } terminate_trial2 = { - pnl.TimeScale.TRIAL: pnl.While(pass_threshold2, response_layer, threshold, terminate2) + pnl.TimeScale.TRIAL: pnl.Or( + pnl.Threshold(response_layer, 'value', threshold, '>=', (0, 0)), + pnl.Threshold(response_layer, 'value', threshold, '>=', (0, 1)), + pnl.While(terminate_num_executions, terminate2), + ) } terminate_trial3 = { - pnl.TimeScale.TRIAL: pnl.While(pass_threshold2, response_layer, threshold, terminate3) + pnl.TimeScale.TRIAL: pnl.Or( + pnl.Threshold(response_layer, 'value', threshold, '>=', (0, 0)), + pnl.Threshold(response_layer, 'value', threshold, '>=', (0, 1)), + pnl.While(terminate_num_executions, terminate3), + ) } terminate_trial4 = { - pnl.TimeScale.TRIAL: pnl.While(pass_threshold2, response_layer, threshold, terminate4) + pnl.TimeScale.TRIAL: pnl.Or( + pnl.Threshold(response_layer, 'value', threshold, '>=', (0, 0)), + pnl.Threshold(response_layer, 'value', threshold, '>=', (0, 1)), + pnl.While(terminate_num_executions, terminate4), + ) } terminate_trial5 = { - pnl.TimeScale.TRIAL: pnl.While(pass_threshold2, response_layer, threshold, terminate5) + pnl.TimeScale.TRIAL: pnl.Or( + pnl.Threshold(response_layer, 'value', threshold, '>=', (0, 0)), + pnl.Threshold(response_layer, 'value', threshold, '>=', (0, 1)), + pnl.While(terminate_num_executions, terminate5), + ) } terminate_list = [terminate_trial2, diff --git a/psyneulink/library/models/Kalanthroff_PCTC_2018.py b/psyneulink/library/models/Kalanthroff_PCTC_2018.py index 2c435eae76d..69269e01ea4 100644 --- a/psyneulink/library/models/Kalanthroff_PCTC_2018.py +++ b/psyneulink/library/models/Kalanthroff_PCTC_2018.py @@ -290,20 +290,13 @@ def my_conflict_function(variable): reinitialize_mechanisms_when=pnl.Never(), name='PCTC_MODEL') -# Create threshold function ------------------------------------------------------------------------------------------- - -def pass_threshold(response_layer, thresh, context): - results1 = response_layer.get_output_values(context)[0][0] # red response - results2 = response_layer.get_output_values(context)[0][1] # green response - # print(results1) - # print(results2) - if results1 >= thresh or results2 >= thresh: - return True - return False - +# Create threshold condition ------------------------------------------------------------------------------------------- terminate_trial = { - pnl.TimeScale.TRIAL: pnl.While(pass_threshold, response_layer, threshold) + pnl.TimeScale.TRIAL: pnl.Or( + pnl.Threshold(response_layer.output_ports['SPECIAL_LOGISTIC'], 'value', threshold, '>=', 0), + pnl.Threshold(response_layer.output_ports['SPECIAL_LOGISTIC'], 'value', threshold, '>=', 1), + ) } # Create test trials function ----------------------------------------------------------------------------------------- diff --git a/requirements.txt b/requirements.txt index 50b561f313d..02d2dd607e5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,18 +1,22 @@ autograd<=1.3 -graph-scheduler>=0.2.0, <1.0.1 +graph-scheduler>=0.2.0, <1.1.1 dill<=0.32 -elfi<0.8.3 +elfi<0.8.4 graphviz<0.20.0 grpcio<1.43.0 grpcio-tools<1.43.0 -llvmlite<0.38 -matplotlib<3.4.4 -networkx<2.6 +llvmlite<0.39 +matplotlib<3.5.2 +modeci_mdf>=0.3.2, <0.3.4 +modelspec<0.2.0 +networkx<2.8 numpy<1.21.4, >=1.17.0 -pillow<8.5.0 +pillow<9.1.0 pint<0.18 toposort<1.8 torch>=1.8.0, <2.0.0; (platform_machine == 'AMD64' or platform_machine == 'x86_64') and platform_python_implementation == 'CPython' and implementation_name == 'cpython' typecheck-decorator<=1.2 leabra-psyneulink<=0.3.2 rich>=10.1, <10.13 +pandas<=1.4.1 +fastkde==1.0.19 \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index 915da5ce962..9bc862ce6b8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -32,7 +32,8 @@ markers = composition: PsyNeuLink Composition tests llvm: Tests using LLVM runtime compiler cuda: Tests using LLVM runtime compiler and CUDA GPGPU backend - control: Tests including control mechanism + control: Tests including control mechanism and/or control projection + state_features: Tests for OptimizationControlMechanism state_features specifications projection nested: Tests including nested compositions function: Tests of Function classes @@ -93,7 +94,8 @@ exclude_lines = # Don't complain about missing debug-only code: def __repr__ if self\.debug - if .* in .*debug_env: + if .*dump.* in .*debug_env: + if .*compile.* in .*debug_env: # Don't complain if tests don't hit defensive assertion code: raise .*Error diff --git a/tests/components/test_component.py b/tests/components/test_component.py index bf6a8db16c0..54023ee3304 100644 --- a/tests/components/test_component.py +++ b/tests/components/test_component.py @@ -20,15 +20,14 @@ def test_detection_of_illegal_args_in_kwargs(self): assert "Unrecognized arguments in constructor for MY_MECH (type: ProcessingMechanism): 'flim_flam, grumblabble'" def test_component_execution_counts_for_standalone_mechanism(self): - """Note: input_port should not update execution count, since it has no afferents""" T = pnl.TransferMechanism() T.execute() assert T.execution_count == 1 - assert T.input_port.execution_count == 0 + assert T.input_port.execution_count == 1 # incremented by Mechanism.get_variable_from_input() - # skipped (0 executions) because we bypass execute when no afferents, and + # skipped (0 executions) because execution is bypassed when no afferents, and # function._is_identity is satisfied (here, Linear function with slope 0 and intercept 1) # This holds true for each below assert T.parameter_ports[pnl.SLOPE].execution_count == 0 @@ -36,13 +35,13 @@ def test_component_execution_counts_for_standalone_mechanism(self): T.execute() assert T.execution_count == 2 - assert T.input_port.execution_count == 0 + assert T.input_port.execution_count == 2 assert T.parameter_ports[pnl.SLOPE].execution_count == 0 assert T.output_port.execution_count == 0 T.execute() assert T.execution_count == 3 - assert T.input_port.execution_count == 0 + assert T.input_port.execution_count == 3 assert T.parameter_ports[pnl.SLOPE].execution_count == 0 assert T.output_port.execution_count == 0 diff --git a/tests/composition/test_composition.py b/tests/composition/test_composition.py index 71cdcffdce1..1f06cce8a50 100644 --- a/tests/composition/test_composition.py +++ b/tests/composition/test_composition.py @@ -1,3 +1,4 @@ +import collections import functools import logging from timeit import timeit @@ -18,19 +19,21 @@ from psyneulink.core.components.mechanisms.modulatory.control.optimizationcontrolmechanism import \ OptimizationControlMechanism from psyneulink.core.components.mechanisms.modulatory.learning.learningmechanism import LearningMechanism +from psyneulink.core.components.mechanisms.processing.compositioninterfacemechanism import CompositionInterfaceMechanism from psyneulink.core.components.mechanisms.processing.integratormechanism import IntegratorMechanism from psyneulink.core.components.mechanisms.processing.objectivemechanism import ObjectiveMechanism from psyneulink.core.components.mechanisms.processing.processingmechanism import ProcessingMechanism from psyneulink.core.components.mechanisms.processing.transfermechanism import TransferMechanism from psyneulink.core.components.ports.inputport import InputPort from psyneulink.core.components.ports.modulatorysignals.controlsignal import ControlSignal, CostFunctions +from psyneulink.core.components.projections.modulatory.controlprojection import ControlProjection from psyneulink.core.components.projections.pathway.mappingprojection import MappingProjection -from psyneulink.core.compositions.composition import Composition, CompositionError, NodeRole +from psyneulink.core.compositions.composition import Composition, NodeRole, CompositionError, RunError from psyneulink.core.compositions.pathway import Pathway, PathwayRole from psyneulink.core.globals.context import Context from psyneulink.core.globals.keywords import \ ADDITIVE, ALLOCATION_SAMPLES, BEFORE, DEFAULT, DISABLE, INPUT_PORT, INTERCEPT, LEARNING_MECHANISMS, \ - LEARNED_PROJECTIONS, RANDOM_CONNECTIVITY_MATRIX, \ + LEARNED_PROJECTIONS, RANDOM_CONNECTIVITY_MATRIX, CONTROL, \ NAME, PROJECTIONS, RESULT, OBJECTIVE_MECHANISM, OUTPUT_MECHANISM, OVERRIDE, SLOPE, TARGET_MECHANISM, VARIANCE from psyneulink.core.scheduling.condition import AtTimeStep, AtTrial, Never, TimeInterval from psyneulink.core.scheduling.condition import EveryNCalls @@ -362,13 +365,13 @@ def test_add_proj_weights_only(self): assert np.allclose(B.parameters.value.get(comp), [[22.4, 29.6]]) assert np.allclose(proj.matrix.base, weights) - test_args = [(None, ([1],[1],[1],[1])), - ('list', ([[0.60276338]],[[0.64589411]],[[0.96366276]])), - ('set', ([[0.60276338]],[[0.64589411]],[[0.96366276]]))] - @pytest.mark.parametrize('projs, expected_matrices', test_args, ids=[x[0] for x in test_args]) - def test_add_multiple_projections_for_nested_compositions(self, projs, expected_matrices): - """Test automatic creation and explicit specification of Projections from outer Composition to multiple - Nodes of a nested Composition, and between Nodes of nested Compositions. + test_args = [(None, ([1],[1],[1],[1]), 3.0), + ('list', ([[0.60276338]],[[0.64589411]],[[0.96366276]]), 2.02947612), + ('set', ([[0.60276338]],[[0.64589411]],[[0.96366276]]), 2.02947612)] + @pytest.mark.parametrize('projs, expected_matrices, expected_result', test_args, ids=[x[0] for x in test_args]) + def test_add_multiple_projections_for_nested_compositions(self, projs, expected_matrices, expected_result): + """Test both automatic creation as well as explicit specification of Projections from outer Composition to + multiple Nodes of a nested Composition, and between Nodes of nested Compositions. """ A = ProcessingMechanism(name='A') @@ -380,11 +383,11 @@ def test_add_multiple_projections_for_nested_compositions(self, projs, expected_ X = ProcessingMechanism(name='INPUT NODE') M = ProcessingMechanism(name='MIDDLE NODE') Y = ProcessingMechanism(name='OUTPUT NODE') - if projs is 'list': + if projs == 'list': iprojs = [MappingProjection(sender=C, receiver=D, matrix=RANDOM_CONNECTIVITY_MATRIX)] oprojs = [MappingProjection(sender=X, receiver=A, matrix=RANDOM_CONNECTIVITY_MATRIX), MappingProjection(sender=X, receiver=M, matrix=RANDOM_CONNECTIVITY_MATRIX)] - elif projs is 'set': + elif projs == 'set': iprojs = {MappingProjection(sender=C, receiver=D, matrix=RANDOM_CONNECTIVITY_MATRIX)} oprojs = {MappingProjection(sender=X, receiver=A, matrix=RANDOM_CONNECTIVITY_MATRIX), MappingProjection(sender=X, receiver=M, matrix=RANDOM_CONNECTIVITY_MATRIX)} @@ -404,8 +407,8 @@ def test_add_multiple_projections_for_nested_compositions(self, projs, expected_ opway = [[X, oprojs, mcomp, Y, C]] ocomp = Composition(pathways=opway, name='OUTER COMPOSITION') - # gv = ocomp.show_graph(output_fmt=source, show_CIM=True, show_node_structure=True) - # assert gv = expected + assert np.allclose(ocomp.run(inputs=[[1.5]]), expected_result) + if not projs: assert (comp1.output_CIM.output_ports[0].efferents[0].matrix.base == comp2.input_CIM.input_ports[0].path_afferents[0].matrix.base == expected_matrices[0]) @@ -505,8 +508,9 @@ def test_add_conflicting_projection_object(self): proj = MappingProjection(sender=A, receiver=B) with pytest.raises(CompositionError) as error: comp.add_projection(projection=proj, receiver=C) - assert "receiver assignment" in str(error.value) - assert "incompatible" in str(error.value) + assert '"Receiver (\'composition-pytests-C\') assigned to ' \ + '\'MappingProjection from composition-pytests-A[RESULT] to composition-pytests-B[InputPort-0] ' \ + 'is incompatible with the positions of these Components in \'Composition-0\'."' == str(error.value) @pytest.mark.stress @pytest.mark.parametrize( @@ -556,6 +560,20 @@ def test_timing_stress(self, count): print() logger.info('completed {0} addition{2} of a projection to a composition in {1:.8f}s'.format(count, t, 's' if count != 1 else '')) + def test_unused_projections_warning(self): + A = ProcessingMechanism(name='A') + B = ProcessingMechanism(name='B') + C = ProcessingMechanism(name='C', input_ports=[A]) + D = ProcessingMechanism(name='D') + icomp = Composition(name='iCOMP', pathways=[A, B]) + comp1 = Composition(name='COMP_1', pathways=[icomp]) + comp2 = Composition(name='COMP_2', pathways=[C, D]) + with pytest.warns(UserWarning) as warning: + ocomp = Composition(name='OUTER COMPOSITION',pathways=[comp1, comp2]) + ocomp.run() + assert repr(warning[0].message.args[0]) == '"\\nThe following Projections were specified but are not being used by Nodes in \'iCOMP\':\\n\\tMappingProjection from A[OutputPort-0] to C[InputPort-0] (from \'A\' to \'C\')."' + assert repr(warning[1].message.args[0]) == '"\\nThe following Projections were specified but are not being used by Nodes in \'COMP_2\':\\n\\tMappingProjection from A[OutputPort-0] to C[InputPort-0] (to \'C\' from \'A\')."' + class TestPathway: @@ -1247,6 +1265,56 @@ def test_composition_learning_pathway_dict_with_no_learning_fct_in_tuple_error(s assert ("The 2nd item" in str(error_text.value) and "must be a LearningFunction" in str(error_text.value)) +class TestProperties: + + @pytest.mark.control + @pytest.mark.parametrize("control_spec", [CONTROL, PROJECTIONS]) + def test_properties(self, control_spec): + + Input = pnl.TransferMechanism(name='Input') + Reward = pnl.TransferMechanism(output_ports=[pnl.RESULT, pnl.MEAN, pnl.VARIANCE], name='reward') + Decision = pnl.DDM(function=pnl.DriftDiffusionAnalytical, + output_ports=[pnl.DECISION_VARIABLE, + pnl.RESPONSE_TIME, + pnl.PROBABILITY_UPPER_THRESHOLD], + name='Decision') + task_execution_pathway = [Input, pnl.IDENTITY_MATRIX, (Decision, NodeRole.OUTPUT)] + comp = pnl.Composition(name="evc", retain_old_simulation_data=True, pathways=[task_execution_pathway, + Reward]) + comp.add_controller( + controller=pnl.OptimizationControlMechanism( + agent_rep=comp, + num_estimates=2, + state_features=[Input.input_port, Reward.input_port], + state_feature_function=pnl.AdaptiveIntegrator(rate=0.1), + monitor_for_control=[Reward, + Decision.output_ports[pnl.PROBABILITY_UPPER_THRESHOLD], + Decision.output_ports[pnl.RESPONSE_TIME]], + function=pnl.GridSearch(), + control_signals=[{control_spec: ("drift_rate", Decision), + ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3)}, + {control_spec: ("threshold", Decision), + ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3)}, + {control_spec: ("slope", Reward), + ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3)}])) + + assert len(comp.nodes) == len(comp.mechanisms) == 3 + assert len(list(comp._all_nodes)) == 7 + assert len(comp.input_ports) == len(comp.get_nodes_by_role(NodeRole.INPUT)) == 2 + assert len(comp.external_input_ports) == len(comp.input_ports) + assert len(comp.output_ports) / 3 == len(comp.get_nodes_by_role(NodeRole.OUTPUT)) == 2 + assert len(comp.shadowing_dict) == 2 + assert len(comp.stateful_nodes) == 0 + assert len(comp.stateful_parameters) == 10 + assert len(comp.random_variables) == 2 + assert len(comp._dependent_components) == 25 + assert len(comp.afferents) == len(comp.efferents) == 0 + assert isinstance(comp.controller, OptimizationControlMechanism) + assert len(comp.projections) == 18 + assert len([proj for proj in comp.projections if isinstance(proj, MappingProjection)]) == 14 + assert len([proj for proj in comp.projections if isinstance(proj, ControlProjection)]) == 4 + + class TestAnalyzeGraph: def test_empty_call(self): @@ -1324,6 +1392,7 @@ def test_two_origins_pointing_to_recursive_pair(self): assert B in comp.get_nodes_by_role(NodeRole.CYCLE) assert C in comp.get_nodes_by_role(NodeRole.RECURRENT_INIT) + @pytest.mark.control def test_controller_objective_mech_not_terminal(self): comp = Composition() A = ProcessingMechanism(name='A') @@ -1354,6 +1423,7 @@ def test_controller_objective_mech_not_terminal(self): # assert comp.controller.objective_mechanism in comp.get_nodes_by_role(NodeRole.OUTPUT) assert comp.controller.objective_mechanism not in comp.get_nodes_by_role(NodeRole.OUTPUT) + @pytest.mark.control def test_controller_objective_mech_not_terminal_fall_back(self): comp = Composition() A = ProcessingMechanism(name='A') @@ -2283,7 +2353,7 @@ def test_3_mechanisms_2_origins_1_disable_control_1_terminal(self, benchmark, co @pytest.mark.composition @pytest.mark.benchmark(group="Transfer") - def test_transfer_mechanism(self, benchmark, comp_mode): + def xtest_transfer_mechanism(self, benchmark, comp_mode): # mechanisms C = TransferMechanism(name="C", @@ -2536,6 +2606,82 @@ def test_input_not_provided_to_run(self): assert np.allclose(T.parameters.value.get(C), [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]) assert np.allclose(run_result, [[np.array([2.0, 4.0])]]) + input_args = [ + ('non_input_node', + '"The following items specified in the \'inputs\' arg of the run() method for \'Composition-1\' ' + 'are not INPUT Nodes of that Composition (nor InputPorts of them): \'OB\'."' + ), + ('non_input_port', + '"The following items specified in the \'inputs\' arg of the run() method for \'Composition-1\' ' + 'that are not a Mechanism, Composition, or an InputPort of one: \'OA[OutputPort-0]\'."' + ), + ('nested_non_input_node', + '"The following items specified in the \'inputs\' arg of the run() method for \'Composition-1\' ' + 'are not INPUT Nodes of that Composition (nor InputPorts of them): \'IB\'."' + ), + ('nested_non_input_port', + '"The following items specified in the \'inputs\' arg of the run() method for \'Composition-1\' ' + 'that are not a Mechanism, Composition, or an InputPort of one: \'IA[OutputPort-0]\'."' + ), + ('input_port_and_mech', + '"The \'inputs\' arg of the run() method for \'Composition-1\' includes specifications of ' + 'the following InputPorts *and* the Mechanisms to which they belong; ' + 'only one or the other can be specified as inputs to run(): OA[InputPort-0]."' + ), + ('nested_input_port_and_comp', + '"The \'inputs\' arg of the run() method for \'Composition-1\' includes specifications of ' + 'the following InputPorts or Mechanisms *and* the Composition within which they are nested: ' + '[(\'IA[InputPort-0]\', \'Composition-0\')]."' + ), + ('nested_mech_and_comp', + '"The \'inputs\' arg of the run() method for \'Composition-1\' includes specifications of ' + 'the following InputPorts or Mechanisms *and* the Composition within which they are nested: ' + '[(\'IA\', \'Composition-0\')]."' + ), + ('run_nested_with_inputs', None) + ] + @pytest.mark.parametrize('input_args', input_args, ids=[x[0] for x in input_args]) + def test_inputs_key_errors(self, input_args): + + condition = input_args[0] + expected_error_text = input_args[1] + + ia = ProcessingMechanism(name='IA') + ib = ProcessingMechanism(name='IB') + oa = ProcessingMechanism(name='OA') + ob = ProcessingMechanism(name='OB') + icomp = Composition([ia, ib]) + ocomp = Composition([oa, ob]) + ocomp.add_node(icomp) + + if condition in {'nested_non_input_node', 'nested_non_input_port'}: + X = ia + Y = ib + else: + X = oa + Y = ob + + if 'non_input_node' in condition: + inputs={X:[1], Y:[1]} + elif 'non_input_port' in condition: + inputs={X.output_port:[1]} + elif condition == 'input_port_and_mech': + inputs={X.input_port:[1], X:[1]} + elif condition == 'nested_input_port_and_comp': + inputs={ia.input_port:[1], icomp:[1]} + elif condition == 'nested_mech_and_comp': + inputs={ia:[1], icomp:[1]} + elif condition == 'run_nested': + inputs={ia:[1]} + + if expected_error_text: + with pytest.raises(RunError) as error_text: + ocomp.run(inputs=inputs) + assert expected_error_text in str(error_text.value) + else: + ocomp._analyze_graph() + icomp.run(inputs={ia:[1]}) + def test_some_inputs_not_specified(self): comp = Composition() @@ -2849,7 +2995,9 @@ def test_projection_assignment_mistake_swap(self): comp.add_projection(MappingProjection(sender=A, receiver=C), A, C) with pytest.raises(CompositionError) as error_text: comp.add_projection(MappingProjection(sender=B, receiver=D), B, C) - assert "is incompatible with the positions of these Components in the Composition" in str(error_text.value) + assert '"Receiver (\'composition-pytests-C\') assigned to ' \ + '\'MappingProjection from composition-pytests-B[RESULT] to composition-pytests-D[InputPort-0] ' \ + 'is incompatible with the positions of these Components in \'Composition-0\'."' == str(error_text.value) def test_projection_assignment_mistake_swap2(self): # A ----> C -- @@ -2869,8 +3017,9 @@ def test_projection_assignment_mistake_swap2(self): comp.add_projection(MappingProjection(sender=A, receiver=C), A, C) with pytest.raises(CompositionError) as error_text: comp.add_projection(MappingProjection(sender=B, receiver=C), B, D) - - assert "is incompatible with the positions of these Components in the Composition" in str(error_text.value) + assert '"Receiver (\'composition-pytests-D\') assigned to ' \ + '\'MappingProjection from composition-pytests-B[RESULT] to composition-pytests-C[InputPort-0] ' \ + 'is incompatible with the positions of these Components in \'Composition-0\'."' == str(error_text.value) @pytest.mark.composition def test_run_5_mechanisms_2_origins_1_terminal(self, comp_mode): @@ -3101,7 +3250,7 @@ def test_LPP_wrong_component(self): assert ("Bad Projection specification in \'pathway\' arg " in str(error_text.value) and "for add_linear_procesing_pathway method" in str(error_text.value) and "Attempt to assign Projection" in str(error_text.value) - and "to InputPort" in str(error_text.value) + and "using InputPort" in str(error_text.value) and "that is in deferred init" in str(error_text.value)) @pytest.mark.composition @@ -3508,7 +3657,7 @@ def test_run_recurrent_transfer_mechanism_integrator_2(self, benchmark, mode): benchmark(comp.execute, inputs={R: [[1.0, 2.0]]}, execution_mode=mode) def test_run_termination_condition_custom_context(self): - D = pnl.DDM(function=pnl.DriftDiffusionIntegrator) + D = pnl.DDM(function=pnl.DriftDiffusionIntegrator, execute_until_finished=False) comp = pnl.Composition() comp.add_node(node=D) @@ -4162,6 +4311,7 @@ def test_nested_run_differing_num_trials(self, comp_mode): outer.run(inputs=input, execution_mode=comp_mode) + @pytest.mark.control def test_invalid_projection_deletion_when_nesting_comps(self): oa = pnl.TransferMechanism(name='oa') ob = pnl.TransferMechanism(name='ob') @@ -4191,7 +4341,7 @@ def test_invalid_projection_deletion_when_nesting_comps(self): pnl.OptimizationControlMechanism( agent_rep=ocomp, state_features=[oa.input_port], - # state_feature_functions=pnl.Buffer(history=2), + # state_feature_function=pnl.Buffer(history=2), name="Controller", objective_mechanism=ocomp_objective_mechanism, function=pnl.GridSearch(direction=pnl.MINIMIZE), @@ -4211,7 +4361,7 @@ def test_invalid_projection_deletion_when_nesting_comps(self): pnl.OptimizationControlMechanism( agent_rep=icomp, state_features=[ia.input_port], - # state_feature_functions=pnl.Buffer(history=2), + # state_feature_function=pnl.Buffer(history=2), name="Controller", objective_mechanism=icomp_objective_mechanism, function=pnl.GridSearch(direction=pnl.MAXIMIZE), @@ -4637,6 +4787,7 @@ def test_three_level_deep_modulation_routing_two_mech(self): result = c1.run({c2: [[2], [2]], ctrl1: [5]}) assert result == [10, 10] + @pytest.mark.state_features def test_four_level_nested_transfer_mechanism_composition_parallel(self): # mechanisms A = ProcessingMechanism(name="A", @@ -4658,6 +4809,8 @@ def test_four_level_nested_transfer_mechanism_composition_parallel(self): ret = comp_lvl0.run(inputs={comp_lvl1: {comp_lvl2: {comp_lvl3a: [[1.0]], comp_lvl3b: [[1.0]]}}}) assert np.allclose(ret, [[[0.52497918747894]], [[0.52497918747894]]]) + @pytest.mark.state_features + @pytest.mark.control def test_four_level_nested_OCM_control(self): p_lvl3 = ProcessingMechanism(name='p_lvl3') @@ -4679,6 +4832,8 @@ def test_four_level_nested_OCM_control(self): result = c_lvl0.run([5]) assert result == [150] + @pytest.mark.state_features + @pytest.mark.control def test_four_level_nested_dual_OCM_control(self): p_lvl3 = ProcessingMechanism(name='p_lvl3') @@ -4709,10 +4864,10 @@ def test_four_level_nested_dual_OCM_control(self): intensity_cost_function=lambda _: 0, modulates=(SLOPE, p_lvl3), allocation_samples=[10, 20, 30]))) - result = c_lvl0.run([5]) assert result == [4500] + @pytest.mark.control @pytest.mark.parametrize('nesting', ("unnested", "nested")) def test_partially_overlapping_local_and_control_mech_control_specs_in_unnested_and_nested_comp(self, nesting): pnl.clear_registry() @@ -4732,8 +4887,8 @@ def test_partially_overlapping_local_and_control_mech_control_specs_in_unnested_ pnl.ALLOCATION_SAMPLES: samples, })), noise=0.5, - starting_point=0, - t0=0.45), + starting_value=0, + non_decision_time=0.45), output_ports=[pnl.DECISION_VARIABLE, pnl.RESPONSE_TIME, pnl.PROBABILITY_UPPER_THRESHOLD], @@ -4741,8 +4896,8 @@ def test_partially_overlapping_local_and_control_mech_control_specs_in_unnested_ Response = pnl.DDM(function=pnl.DriftDiffusionAnalytical(drift_rate=1.0, threshold=1.0, noise=0.5, - starting_point=0, - t0=0.45), + starting_value=0, + non_decision_time=0.45), output_ports=[pnl.DECISION_VARIABLE, pnl.RESPONSE_TIME, pnl.PROBABILITY_UPPER_THRESHOLD], @@ -4790,6 +4945,7 @@ def test_partially_overlapping_local_and_control_mech_control_specs_in_unnested_ assert all(isinstance(comp.controller.control_signals[i].efferents[0].receiver.owner, pnl.CompositionInterfaceMechanism) for i in range(4)) + class TestOverloadedCompositions: def test_mechanism_different_inputs(self): a = TransferMechanism(name='a', function=Linear(slope=2)) @@ -5581,11 +5737,19 @@ def test_function(trial_num): xor_comp.learn(inputs=test_function, num_trials=4) + @pytest.mark.control @pytest.mark.parametrize( - "with_outer_controller,with_inner_controller", - [(True, True), (True, False), (False, True), (False, False)] + "controllers, results",[ + ('none', [[-2], [1]]), + ('inner', [[-2], [10]]), + ('outer', [[-2], [10]]), + ('inner_and_outer', [[-2], [100]]), + ] ) - def test_input_type_equivalence(self, with_outer_controller, with_inner_controller): + @pytest.mark.parametrize( + "inputs_arg",['inputs_dict','generator_function','generator_instance'] + ) + def test_input_type_equivalence(self, controllers, results, inputs_arg): # instantiate mechanisms and inner comp ia = pnl.TransferMechanism(name='ia') ib = pnl.TransferMechanism(name='ib') @@ -5597,7 +5761,7 @@ def test_input_type_equivalence(self, with_outer_controller, with_inner_controll icomp.add_projection(pnl.MappingProjection(), sender=ia, receiver=ib) # add controller to inner comp - if with_inner_controller: + if controllers in {'inner', 'inner_and_outer'}: icomp.add_controller( pnl.OptimizationControlMechanism( agent_rep=icomp, @@ -5606,7 +5770,7 @@ def test_input_type_equivalence(self, with_outer_controller, with_inner_controll objective_mechanism=pnl.ObjectiveMechanism( monitor=ib.output_port, function=pnl.SimpleIntegrator, - name="oController Objective Mechanism" + name="iController Objective Mechanism" ), function=pnl.GridSearch(direction=pnl.MAXIMIZE), control_signals=[pnl.ControlSignal(projections=[(pnl.SLOPE, ia)], @@ -5624,7 +5788,7 @@ def test_input_type_equivalence(self, with_outer_controller, with_inner_controll ocomp.add_node(icomp) # add controller to outer comp - if with_outer_controller: + if controllers in {'outer', 'inner_and_outer'}: ocomp.add_controller( pnl.OptimizationControlMechanism( agent_rep=ocomp, @@ -5646,9 +5810,9 @@ def test_input_type_equivalence(self, with_outer_controller, with_inner_controll ) # set up input using three different formats: - # 1) generator function - # 2) instance of generator function - # 3) inputs dict + # 1) inputs dict + # 2) generator function + # 3) instance of generator function inputs_dict = { icomp: { @@ -5667,19 +5831,109 @@ def inputs_generator_function(): inputs_generator_instance = inputs_generator_function() + inputs_source = { + 'inputs_dict': inputs_dict, + 'generator_function': inputs_generator_function, + 'generator_instance': inputs_generator_instance + }[inputs_arg] + + # # Version with reporting for debugging purposes: + # ib.reportOutputPref=[pnl.VALUE, pnl.VARIABLE] + # icomp.controller.reportOutputPref = pnl.ReportOutput.ON + # ocomp.controller.reportOutputPref = pnl.ReportOutput.FULL + # ocomp.run(inputs=inputs_dict, + # report_output=pnl.ReportOutput.FULL, + # report_progress=pnl.ReportProgress.ON, + # report_simulations=pnl.ReportSimulations.ON, + # report_to_devices=pnl.ReportDevices.DIVERT + # ) + # actual_output = ocomp.rich_diverted_reports + # run Composition with all three input types and assert that results are as expected. - ocomp.run(inputs=inputs_generator_function) - ocomp.run(inputs=inputs_generator_instance) - ocomp.run(inputs=inputs_dict) - - # assert results are as expected - if not with_inner_controller and not with_outer_controller: - assert ocomp.results[0:2] == ocomp.results[2:4] == ocomp.results[4:6] == [[-2], [1]] - elif with_inner_controller and not with_outer_controller or \ - with_outer_controller and not with_inner_controller: - assert ocomp.results[0:2] == ocomp.results[2:4] == ocomp.results[4:6] == [[-2], [10]] + ocomp.run(inputs=inputs_source) + assert ocomp.results == results + + expected_format_strings = \ + [ + '{\n\tX: [ [[0.0, 0.0, 0.0],[0.0, 0.0, 0.0]], [[0.0, 0.0, 0.0],[0.0, 0.0, 0.0]] ],' + '\n\tICOMP: [ [[0.0],[0.0, 0.0, 0.0],[0.0, 0.0, 0.0]], [[0.0],[0.0, 0.0, 0.0],[0.0, 0.0, 0.0]] ],' + '\n\tY: [ [[0.0, 0.0, 0.0],[0.0, 0.0, 0.0]], [[0.0, 0.0, 0.0],[0.0, 0.0, 0.0]] ]\n}', + + "\nInputs to (nested) INPUT Nodes of OCOMP for 3 trials:\n\tX: [ [[0.0, 0.0, 0.0],[0.0, 0.0, 0.0]], [[0.0, " + "0.0, 0.0],[0.0, 0.0, 0.0]], [[0.0, 0.0, 0.0],[0.0, 0.0, 0.0]] ]" + "\n\tICOMP: \n\t\tA: [ ['red'], ['green'], ['red'] ]" + "\n\t\tC: [ ['red','blue'], ['green','yellow'], ['orange','purple'] ]" + "\n\tY: [ ['red','red'], ['green','green'], ['red','red'] " + "\n\nFormat as follows for inputs to run():" + "\n{\n\tX: [ [[0.0, 0.0, 0.0],[0.0, 0.0, 0.0]], " + "[[0.0, 0.0, 0.0],[0.0, 0.0, 0.0]], " + "[[0.0, 0.0, 0.0],[0.0, 0.0, 0.0]] ]," + "\n\tICOMP: [ [[0.0],[0.0, 0.0, 0.0],[0.0, 0.0, 0.0]], " + "[[0.0],[0.0, 0.0, 0.0],[0.0, 0.0, 0.0]], " + "[[0.0],[0.0, 0.0, 0.0],[0.0, 0.0, 0.0]] ]," + "\n\tY: [ [[0.0, 0.0, 0.0],[0.0, 0.0, 0.0]], " + "[[0.0, 0.0, 0.0],[0.0, 0.0, 0.0]], " + "[[0.0, 0.0, 0.0],[0.0, 0.0, 0.0]] ]\n}" + ] + test_args = [ + # form, labels, nested, num_trials, expected_format_string + (pnl.TEXT, False, False, 2, expected_format_strings[0]), + (pnl.TEXT, True, True, pnl.FULL, expected_format_strings[1]), + (pnl.DICT, False, False, 1, None), + (pnl.DICT, False, False, pnl.FULL, None), + (pnl.DICT, True, True, 1, None), + (pnl.DICT, True, False, pnl.FULL, None) + ] + @pytest.mark.parametrize('form, use_labels, show_nested, num_trials, expected_format_string', test_args, + ids = [f"{'dict' if x[0] else 'string'} " + f"{'use_labels_true' if x[1] else 'use_labels_false'} " + f"{'show_nested_true' if x[2] else 'show_nested_false'} " + f"num_trials-{x[3]} " + f"{'expected_format_string' if x[4] else 'None'}" for x in test_args] + ) + def test_get_input_format(self, form, use_labels, show_nested, num_trials, expected_format_string): + """Also tests input_labels_dict""" + + A = pnl.ProcessingMechanism(size=1, name='A', + input_labels={0:{'red':0, 'green':1}, + 1:{'blue':2, 'yellow':3}}) + B = pnl.ProcessingMechanism(size=2, name='B') + C = pnl.ProcessingMechanism(size=[3,3], + input_ports=['C INPUT 1', 'C INPUT 2'], + input_labels={'C INPUT 1':{'red':[0,0,0], 'green':[1,1,1], 'orange':[2,2,2]}, + 'C INPUT 2':{'blue':[3,3,3], 'yellow':[4,4,4], 'purple':[5,5,5]}}, + name='C') + assert C.variable.shape == (2,3) + X = ProcessingMechanism(size=[3,3], + input_ports=['X INPUT 1', 'X INPUT 2'], + name='X', + # input_labels={0:{'red':[0,0,0], 'green':[1,1,1]}} # Specify dict for only one port + ) + # Use TransferMechanism so that 2nd OutputPort uses 2nd item of Mechanism's value + # (i.e. ,without having to specify that explicitly, as would be the case for ProcessingMechanism) + Y = pnl.TransferMechanism(input_ports=[{NAME:'Y INPUT 1', pnl.SIZE: 3, pnl.FUNCTION: pnl.Reduce}, + {NAME:'Y INPUT 2', pnl.SIZE: 3}], + # Test specification of labels for all InputPorts of Mechanism: + input_labels={'red':[0,0,0], 'green':[1,1,1]}, + name='Y') + assert len(Y.input_ports[0].variable) == 3 + assert len(Y.input_ports[0].value) == 1 + assert len(Y.input_ports[1].variable) == 3 + assert len(Y.input_ports[1].value) == 3 + icomp = Composition(pathways=[[A,B],[C]], name='ICOMP') + ocomp = Composition(nodes=[X, icomp, Y], name='OCOMP') + + inputs_dict = ocomp.get_input_format(form=form, + num_trials=num_trials, + use_labels=use_labels, + show_nested_input_nodes=show_nested) + if form == pnl.TEXT: + assert inputs_dict == expected_format_string else: - assert ocomp.results[0:2] == ocomp.results[2:4] == ocomp.results[4:6] == [[-2], [100]] + ocomp.run(inputs=inputs_dict) + if num_trials == pnl.FULL: + num_trials = 2 + len(ocomp.results)==num_trials class TestProperties: @@ -5923,7 +6177,6 @@ def test_shadow_internal_projections(self): assert B.value == [[2.0]] assert C.value == [[2.0]] - _test_shadow_nested_nodes_arg =\ [ ('shadow_nodes_one_and_two_levels_deep', 0), @@ -5971,6 +6224,19 @@ def test_shadow_nested_nodes(self, condition): 'that is not an INPUT Node of that Composition is not currently supported.' \ in err.value.error_value + def test_failure_to_find_node_to_shadow(self): + A = ProcessingMechanism(name='A') + B = ProcessingMechanism(name='B') + C = ProcessingMechanism(name='C', input_ports=[A.input_port]) + D = ProcessingMechanism(name='D') + icomp = Composition(name='iCOMP', nodes=[A, B]) + comp1 = Composition(name='COMP_1', pathways=[icomp]) + err_msg = "Unable to find port specified to be shadowed by 'C' (A[InputPort-0]) within the same Composition" + with pytest.raises(CompositionError) as error_value: + comp2 = Composition(name='COMP_2', pathways=[C, D]) + ocomp = Composition(name='OUTER COMPOSITION',pathways=[comp1, comp2]) + assert err_msg in str(error_value) + def test_monitor_input_ports(self): comp = Composition(name='comp') @@ -6116,6 +6382,7 @@ def test_initialize_cycles_warning(self): with pytest.warns(UserWarning, match=warning_text): comp.run(initialize_cycle_values={a: 1}) + class TestResetValues: def test_reset_one_mechanism_through_run(self): @@ -6268,7 +6535,7 @@ def test_save_state_before_simulations(self): integration_rate=0.2 ) - B = IntegratorMechanism(name='B', function=DriftDiffusionIntegrator(rate=0.1)) + B = IntegratorMechanism(name='B', function=DriftDiffusionIntegrator(rate=0.1, time_step_size=1.0)) C = TransferMechanism(name='C') comp = Composition() @@ -6374,13 +6641,13 @@ def test_input_labels_and_results_by_node_and_no_orphaning_of_nested_output_node result = ocomp.run(inputs={mcomp:[[0],[0]]}) assert len(result)==4 - input_format = ocomp.get_input_format() + input_format = ocomp.get_input_format(form=pnl.TEXT) assert repr(input_format) == '\'{\\n\\tMIDDLE COMP: [[0.0],[0.0]],\\n\\tQ: [[0.0]]\\n}\'' - input_format = ocomp.get_input_format(num_trials=3, use_labels=True) - assert repr(input_format) == '"{\\n\\tMIDDLE COMP: [ [[[0.0]],[\'red\']], [[[0.0]],[\'green\']], [[[0.0]],[\'red\']] ],\\n\\tQ: [ [\'red\'], [\'green\'], [\'red\'] ]\\n}"' - input_format = ocomp.get_input_format(num_trials=2, show_nested_input_nodes=True) + input_format = ocomp.get_input_format(form=pnl.TEXT, num_trials=3, use_labels=True) + assert repr(input_format) == '"{\\n\\tMIDDLE COMP: [ [[0.0],[\'red\']], [[0.0],[\'green\']], [[0.0],[\'red\']] ],\\n\\tQ: [ [\'red\'], [\'green\'], [\'red\'] ]\\n}"' + input_format = ocomp.get_input_format(form=pnl.TEXT, num_trials=2, show_nested_input_nodes=True) assert input_format == '\nInputs to (nested) INPUT Nodes of OUTER COMP for 2 trials:\n\tMIDDLE COMP: \n\t\tX: [ [[0.0]], [[0.0]] ]\n\t\tINNER COMP: \n\t\t\tA: [ [[0.0]], [[0.0]] ]\n\tQ: [ [[0.0]], [[0.0]] \n\nFormat as follows for inputs to run():\n{\n\tMIDDLE COMP: [ [[0.0],[0.0]], [[0.0],[0.0]] ],\n\tQ: [ [[0.0]], [[0.0]] ]\n}' - input_format = ocomp.get_input_format(num_trials=2, show_nested_input_nodes=True, use_labels=True) + input_format = ocomp.get_input_format(form=pnl.TEXT, num_trials=2, show_nested_input_nodes=True, use_labels=True) assert input_format == "\nInputs to (nested) INPUT Nodes of OUTER COMP for 2 trials:\n\tMIDDLE COMP: \n\t\tX: [ [[0.0]], [[0.0]] ]\n\t\tINNER COMP: \n\t\t\tA: [ ['red'], ['green'] ]\n\tQ: [ ['red'], ['green'] \n\nFormat as follows for inputs to run():\n{\n\tMIDDLE COMP: [ [[0.0],[0.0]], [[0.0],[0.0]] ],\n\tQ: [ [[0.0]], [[0.0]] ]\n}" result = ocomp.run(inputs={mcomp:[[.2],['green']], Q:[4.6]}) @@ -6419,9 +6686,8 @@ def test_input_labels_and_results_by_node_and_no_orphaning_of_nested_output_node ocomp.get_results_by_nodes(nodes=['N']) assert no_such_node_error_msg in str(error_text.value) - - def test_unnested_PROBE(self): + """Assigning PROBE to a Node should add OutputPort to output_CIM even if Node is not in a nested Composition""" A = ProcessingMechanism(name='A') B = ProcessingMechanism(name='B') C = ProcessingMechanism(name='C') @@ -6853,6 +7119,7 @@ def test_LEARNING_bp(self): # Validate that TERMINAL is LearningMechanism that Projects to first MappingProjection in learning_pathway (comp.get_nodes_by_role(NodeRole.TERMINAL))[0].efferents[0].receiver.owner.sender.owner == A + @pytest.mark.control def test_controller_role(self): comp = Composition() A = ProcessingMechanism(name='A') @@ -6926,8 +7193,8 @@ def test_danglingControlledMech(self): drift_rate=(1.0), threshold=(0.1654), noise=(0.5), - starting_point=(0), - t0=0.25, + starting_value=(0), + non_decision_time=0.25, ), name='Decision', ) @@ -6956,8 +7223,8 @@ def test_danglingControlledMech(self): ), ), noise=(0.5), - starting_point=(0), - t0=0.45 + starting_value=(0), + non_decision_time=0.45 ), name='second_DDM', ) @@ -6978,6 +7245,147 @@ def test_danglingControlledMech(self): comp.add_node(Reward) # no assert, should only complete without error + @pytest.mark.parametrize( + 'removed_nodes, expected_dependencies', + [ + (['A'], {'B': set(), 'C': set('B'), 'D': set('C'), 'E': set('C')}), + (['C'], {'A': set(), 'B': set(), 'D': set(), 'E': set()}), + (['E'], {'A': set(), 'B': set(), 'C': {'A', 'B'}, 'D': set('C')}), + (['A', 'B'], {'C': set(), 'D': set('C'), 'E': set('C')}), + (['D', 'E'], {'A': set(), 'B': set(), 'C': {'A', 'B'}}), + (['A', 'B', 'C', 'D', 'E'], {}), + ] + ) + def test_remove_node(self, removed_nodes, expected_dependencies): + def stringify_dependency_dict(dd): + return {node.name: {n.name for n in deps} for node, deps in dd.items()} + + A = pnl.TransferMechanism(name='A') + B = pnl.TransferMechanism(name='B') + C = pnl.TransferMechanism(name='C') + D = pnl.TransferMechanism(name='D') + E = pnl.TransferMechanism(name='E') + + locs = locals() + removed_nodes = [locs[n] for n in removed_nodes] + + comp = pnl.Composition( + pathways=[ + [A, C, D], + [A, C, D], + [B, C, D], + [B, C, E], + ] + ) + + comp.remove_nodes(removed_nodes) + + assert stringify_dependency_dict(comp.scheduler.dependency_dict) == expected_dependencies + assert stringify_dependency_dict(comp.graph_processing.dependency_dict) == expected_dependencies + + proj_dependencies = collections.defaultdict(set) + for node in comp.nodes: + if node not in removed_nodes: + for proj in node.afferents: + if ( + proj.sender.owner not in removed_nodes + and proj.receiver.owner not in removed_nodes + and not isinstance(proj.sender.owner, CompositionInterfaceMechanism) + and not isinstance(proj.receiver.owner, CompositionInterfaceMechanism) + ): + proj_dependencies[node.name].add(proj.name) + proj_dependencies[proj.name].add(proj.sender.owner.name) + assert stringify_dependency_dict(comp.graph.dependency_dict) == {**expected_dependencies, **proj_dependencies} + + for node in removed_nodes: + assert node not in comp.nodes + assert node not in comp.nodes_to_roles + assert node not in comp.graph.comp_to_vertex + assert node not in comp.graph_processing.comp_to_vertex + assert node not in comp.scheduler.conditions + + for proj in node.afferents + node.efferents: + assert proj not in comp.projections + assert not proj.is_active_in_composition(comp) + + comp.run(inputs={n: [0] for n in comp.get_nodes_by_role(pnl.NodeRole.INPUT)}) + + @pytest.mark.parametrize('slope_A', [1, (1, pnl.CONTROL)]) + @pytest.mark.parametrize('slope_B', [1, (1, pnl.CONTROL)]) + @pytest.mark.parametrize('removed_nodes', [['A'], ['B'], ['A', 'B']]) + def test_remove_node_control(self, slope_A, slope_B, removed_nodes): + A = pnl.TransferMechanism(name='A', function=pnl.Linear(slope=slope_A)) + B = pnl.TransferMechanism(name='B', function=pnl.Linear(slope=slope_B)) + + locs = locals() + removed_nodes = [locs[n] for n in removed_nodes] + + search_space_len = sum(1 if isinstance(s, tuple) else 0 for s in [slope_A, slope_B]) + + comp = pnl.Composition(pathways=[A, B]) + comp.add_controller( + pnl.OptimizationControlMechanism( + agent_rep=comp, search_space=[0, 1] * search_space_len + ) + ) + comp.remove_nodes(removed_nodes) + + for n in removed_nodes: + for proj in n.parameter_ports['slope'].all_afferents: + assert not proj.is_active_in_composition(comp), f'{n.name} {proj.name}' + + def test_remove_node_from_conditions(self): + def assert_conditions_do_not_contain(*args): + conds_queue = list(comp.scheduler.conditions.conditions.values()) + while len(conds_queue) > 0: + cur_cond = conds_queue.pop() + deps = [] + + try: + deps = [cur_cond.dependency] + except AttributeError: + try: + deps = cur_cond.dependencies + except AttributeError: + pass + + for d in deps: + if isinstance(d, pnl.Condition): + conds_queue.append(d) + assert d not in args + + A = pnl.TransferMechanism(name='A') + B = pnl.TransferMechanism(name='B') + C = pnl.TransferMechanism(name='C') + D = pnl.TransferMechanism(name='D') + + comp = pnl.Composition(pathways=[[A, D], [B, D], [C, D]]) + + comp.run(inputs={A: [0], B: [0], C: [0]}) + comp.remove_node(A) + comp.run(inputs={B: [0], C: [0]}) + assert_conditions_do_not_contain(A) + + comp.remove_node(B) + comp.run(inputs={C: [0]}) + assert_conditions_do_not_contain(A, B) + + def test_remove_node_learning(self): + A = ProcessingMechanism(name='A') + B = ProcessingMechanism(name='B') + C = ProcessingMechanism(name='C') + D = ProcessingMechanism(name='D') + + comp = Composition() + comp.add_linear_learning_pathway(pathway=[A, B], learning_function=BackPropagation) + comp.add_linear_learning_pathway(pathway=[C, D], learning_function=Reinforcement) + + comp.remove_node(A) + comp.learn(inputs={n: [0] for n in comp.get_nodes_by_role(pnl.NodeRole.INPUT)}) + + comp.remove_node(D) + comp.learn(inputs={n: [0] for n in comp.get_nodes_by_role(pnl.NodeRole.INPUT)}) + class TestInputSpecsDocumentationExamples: diff --git a/tests/composition/test_control.py b/tests/composition/test_control.py index da45a9d2d8f..26169e34515 100644 --- a/tests/composition/test_control.py +++ b/tests/composition/test_control.py @@ -4,12 +4,15 @@ import pytest import psyneulink as pnl -from psyneulink.core.globals.keywords import ALLOCATION_SAMPLES, PROJECTIONS +from psyneulink.core.globals.keywords import ALLOCATION_SAMPLES, CONTROL, PROJECTIONS from psyneulink.core.globals.log import LogCondition from psyneulink.core.globals.sampleiterator import SampleIterator, SampleIteratorError, SampleSpec from psyneulink.core.globals.utilities import _SeededPhilox +from psyneulink.core.components.mechanisms.modulatory.control.optimizationcontrolmechanism import \ + _deferred_agent_rep_input_port_name, _deferred_state_feature_spec_msg, \ + _state_input_port_name, _numeric_state_input_port_name, _shadowed_state_input_port_name - +@pytest.mark.control class TestControlSpecification: # These test the coordination of adding a node with a control specification to a Composition # with adding a controller that may also specify control of that node. @@ -18,11 +21,6 @@ class TestControlSpecification: # 2) specification of control in controller supercedes any conflicting specification on a node; # 3) order of addition to the composition does not matter (i.e., Principle 2 always applies) - # FIX: OUTSTANDING ISSUES - - # When control is specified in a controller for a Mechanism that is not yet a node in the Composition - # it neverhtless gets activated (in call to controller._activate_projections_for_compositions; - # instead, it should either be put in deferred_init or added to node's aux_components attribute - def test_add_node_with_control_specified_then_add_controller(self): # First add Mechanism with control specification to Composition, # then add controller with NO control specification to Composition @@ -89,14 +87,19 @@ def test_redundant_control_spec_add_controller_in_comp_constructor_then_add_node pnl.ControlProjection( function=pnl.Linear, control_signal_params={ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3)})))) - comp = pnl.Composition(controller=pnl.ControlMechanism(control_signals=("drift_rate", ddm))) + expected_warning = "The controller of 'Composition-0' has been specified to project to 'DDM-0', but 'DDM-0' " \ + "is not in 'Composition-0' or any of its nested Compositions. This projection will be " \ + "deactivated until 'DDM-0' is added to' Composition-0' in a compatible way." + with pytest.warns(UserWarning, match=expected_warning): + comp = pnl.Composition(controller=pnl.ControlMechanism(control_signals=("drift_rate", ddm))) comp.add_node(ddm) assert comp.controller.control_signals[0].efferents[0].receiver == ddm.parameter_ports['drift_rate'] assert ddm.parameter_ports['drift_rate'].mod_afferents[0].sender.owner == comp.controller assert comp.controller.control_signals[0].allocation_samples is None - def test_redundant_control_spec_add_controller_in_comp_constructor_then_add_node_with_alloc_samples_specified(self): - # First create Composition with controller that has HAS control specification, + @pytest.mark.parametrize("control_spec", [CONTROL, PROJECTIONS]) + def test_redundant_control_spec_add_controller_in_comp_constructor_then_add_node_with_alloc_samples_specified(self,control_spec): + # First create Composition with controller that has HAS control specification that includes allocation_samples, # then add Mechanism with control specification to Composition; # Control specification on controller should supercede one on Mechanism (which should be ignored) ddm = pnl.DDM(function=pnl.DriftDiffusionAnalytical( @@ -104,14 +107,58 @@ def test_redundant_control_spec_add_controller_in_comp_constructor_then_add_node pnl.ControlProjection( function=pnl.Linear, control_signal_params={ALLOCATION_SAMPLES: np.arange(0.1, 1.01,0.3)})))) - comp = pnl.Composition(controller=pnl.ControlMechanism(control_signals={ALLOCATION_SAMPLES:np.arange(0.2,1.01, 0.3), - PROJECTIONS:('drift_rate', ddm)})) + expected_warning = "The controller of 'Composition-0' has been specified to project to 'DDM-0', but 'DDM-0' " \ + "is not in 'Composition-0' or any of its nested Compositions. This projection will be " \ + "deactivated until 'DDM-0' is added to' Composition-0' in a compatible way." + with pytest.warns(UserWarning, match=expected_warning): + comp = pnl.Composition(controller=pnl.ControlMechanism(control_signals={ALLOCATION_SAMPLES:np.arange(0.2,1.01, 0.3), + control_spec:('drift_rate', ddm)})) comp.add_node(ddm) assert comp.controller.control_signals[0].efferents[0].receiver == ddm.parameter_ports['drift_rate'] assert ddm.parameter_ports['drift_rate'].mod_afferents[0].sender.owner == comp.controller assert np.allclose(comp.controller.control[0].allocation_samples(), [0.2, 0.5, 0.8]) - def test_deferred_init(self): + # def test_missing_mech_referenced_by_controller_warning(self): + # mech = pnl.ProcessingMechanism() + # warning_msg_1 = '' + # with pytest.warns(UserWarning) as warning: + # comp = pnl.Composition(controller=pnl.ControlMechanism(objective_mechanism=mech)) + # assert repr(warning[1].message.args[0]) == warning_msg_1 + + def test_bad_objective_mechanism_spec(self): + mech = pnl.ProcessingMechanism() + expected_error = 'Specification of objective_mechanism arg for \'ControlMechanism-0\' ' \ + '(ProcessingMechanism-0) must be an ObjectiveMechanism or a list of Mechanisms ' \ + 'and/or OutputPorts to be monitored for control.' + with pytest.raises(pnl.ControlMechanismError) as error: + pnl.Composition(controller=pnl.ControlMechanism(objective_mechanism=mech)) + error_msg = error.value.error_value + assert expected_error in error_msg + + def test_objective_mechanism_spec_as_monitor_for_control_error(self): + expected_error = 'The \'monitor_for_control\' arg of \'ControlMechanism-0\' contains a specification ' \ + 'for an ObjectiveMechanism ([(ObjectiveMechanism ObjectiveMechanism-0)]). ' \ + 'This should be specified in its \'objective_mechanism\' argument.' + with pytest.raises(pnl.ControlMechanismError) as error: + pnl.Composition(controller=pnl.ControlMechanism(monitor_for_control=pnl.ObjectiveMechanism())) + error_msg = error.value.error_value + assert expected_error in error_msg + + @pytest.mark.state_features + @pytest.mark.parametrize("control_spec", [CONTROL, PROJECTIONS]) + @pytest.mark.parametrize("state_features_arg", [ + 'none', + 'default_none', + 'list_none', + 'list_ports', + 'list_reversed', + 'list_numeric', + 'list_partial', + 'dict', + 'dict_reversed', + 'dict_partial', + ]) + def test_deferred_init(self, control_spec, state_features_arg): # Test to insure controller works the same regardless of whether it is added to a composition before or after # the nodes it connects to @@ -119,49 +166,177 @@ def test_deferred_init(self): Input = pnl.TransferMechanism(name='Input') reward = pnl.TransferMechanism(output_ports=[pnl.RESULT, pnl.MEAN, pnl.VARIANCE], name='reward') - Decision = pnl.DDM(function=pnl.DriftDiffusionAnalytical(drift_rate=(1.0, - pnl.ControlProjection(function=pnl.Linear, - control_signal_params={ - pnl.ALLOCATION_SAMPLES: np.arange( - 0.1, - 1.01, - 0.3)})), - threshold=(1.0, - pnl.ControlProjection(function=pnl.Linear, - control_signal_params={ - pnl.ALLOCATION_SAMPLES: - np.arange( - 0.1, - 1.01, - 0.3)})), - noise=0.5, - starting_point=0, - t0=0.45), - output_ports=[pnl.DECISION_VARIABLE, - pnl.RESPONSE_TIME, - pnl.PROBABILITY_UPPER_THRESHOLD], - name='Decision') + Decision = pnl.DDM( + function=pnl.DriftDiffusionAnalytical(drift_rate=(1.0, + pnl.ControlProjection( + function=pnl.Linear, + control_signal_params={ + pnl.ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3) + })), + threshold=(1.0, + pnl.ControlProjection( + function=pnl.Linear, + control_signal_params={ + pnl.ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3) + })), + noise=0.5, + starting_value=0, + non_decision_time=0.45), + output_ports=[pnl.DECISION_VARIABLE, + pnl.RESPONSE_TIME, + pnl.PROBABILITY_UPPER_THRESHOLD], + name='Decision') comp = pnl.Composition(name="evc", retain_old_simulation_data=True) - # add the controller to the Composition before adding the relevant Mechanisms - comp.add_controller(controller=pnl.OptimizationControlMechanism( - agent_rep=comp, - state_features=[Input.input_port, reward.input_port], - state_feature_functions=pnl.AdaptiveIntegrator(rate=0.5), - objective_mechanism=pnl.ObjectiveMechanism( + state_features = { + 'none' : None, + 'default_none' : 'DEFAULT NONE', + 'list_none': [None, None], + 'list_ports': [reward.input_port, Input.input_port], + 'list_reversed': [Input.input_port, reward.input_port], + 'list_partial': [reward.input_port], + 'list_numeric': [[1.1],[2.2]], + 'dict': {reward: reward.input_port, + Input: Input.input_port}, + 'dict_reversed': {reward: Input.input_port, + Input: reward.input_port}, + 'dict_partial': {reward: reward.input_port} + }[state_features_arg] + + if state_features == 'DEFAULT NONE': + state_feature_default = None + else: + state_feature_default = pnl.SHADOW_INPUTS + + if state_features_arg in {'none', 'default_none', + 'list_none', 'list_ports', 'list_reversed', 'list_numeric', 'list_partial'}: + expected_warning = f"The '{pnl.STATE_FEATURES}' arg for 'OptimizationControlMechanism-0' has been specified " \ + f"before any Nodes have been assigned to its agent_rep ('evc'). Their order must " \ + f"be the same as the order of the corresponding INPUT Nodes for 'evc' once they are " \ + f"added, or unexpected results may occur. It is safer to assign all Nodes to the " \ + f"agent_rep of a controller before specifying its 'state_features'." + elif state_features_arg in {'dict', 'dict_reversed'}: + # expected_warning = f"The 'state_features' specified for 'OptimizationControlMechanism-0' " \ + # f"contains items (Input, reward) that are not in its agent_rep ('evc'). " \ + # f"Executing 'evc' before they are added will generate an error ." + expected_warning = f"that are not in its agent_rep ('evc'). " \ + f"Executing 'evc' before they are added will generate an error ." + elif state_features_arg == 'dict_partial': + expected_warning = f"The '{pnl.STATE_FEATURES}' specified for 'OptimizationControlMechanism-0' " \ + f"contains an item (reward) that is not in its agent_rep ('evc'). " \ + f"Executing 'evc' before it is added will generate an error ." + else: + assert False, f"TEST ERROR: unrecognized state_features_arg '{state_features_arg}'" + + with pytest.warns(UserWarning) as warning: + # add the controller to the Composition before adding the relevant Mechanisms + if 'default_none' in state_features_arg: + comp.add_controller(controller=pnl.OptimizationControlMechanism( + agent_rep=comp, + # state_features = state_features, # Don't specify in order to test default assignments + state_feature_default=state_feature_default, + state_feature_function=pnl.AdaptiveIntegrator(rate=0.5), + objective_mechanism=pnl.ObjectiveMechanism( function=pnl.LinearCombination(operation=pnl.PRODUCT), monitor=[reward, Decision.output_ports[pnl.PROBABILITY_UPPER_THRESHOLD], (Decision.output_ports[pnl.RESPONSE_TIME], -1, 1)]), - function=pnl.GridSearch(), - control_signals=[{PROJECTIONS: ("drift_rate", Decision), - ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3)}, - {PROJECTIONS: ("threshold", Decision), - ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3)}]) - ) + function=pnl.GridSearch(), + control_signals=[{control_spec: ("drift_rate", Decision), + ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3)}, + {control_spec: ("threshold", Decision), + ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3)}]) + ) + else: + comp.add_controller(controller=pnl.OptimizationControlMechanism( + agent_rep=comp, + state_features = state_features, + state_feature_default=state_feature_default, + state_feature_function=pnl.AdaptiveIntegrator(rate=0.5), + objective_mechanism=pnl.ObjectiveMechanism( + function=pnl.LinearCombination(operation=pnl.PRODUCT), + monitor=[reward, + Decision.output_ports[pnl.PROBABILITY_UPPER_THRESHOLD], + (Decision.output_ports[pnl.RESPONSE_TIME], -1, 1)]), + function=pnl.GridSearch(), + control_signals=[{control_spec: ("drift_rate", Decision), + ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3)}, + {control_spec: ("threshold", Decision), + ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3)}]) + ) + assert any(expected_warning in repr(w.message) for w in warning.list) + + deferred_reward_input_port = _deferred_state_feature_spec_msg('reward[InputPort-0]', 'evc') + deferred_Input_input_port = _deferred_state_feature_spec_msg('Input[InputPort-0]', 'evc') + deferred_node_0 = _deferred_agent_rep_input_port_name('0','evc') + deferred_node_1 = _deferred_agent_rep_input_port_name('1','evc') + deferred_shadowed_0 = _shadowed_state_input_port_name('reward[InputPort-0]' , deferred_node_0) + deferred_shadowed_1 = _shadowed_state_input_port_name('Input[InputPort-0]' , deferred_node_1) + deferred_shadowed_0_rev = _shadowed_state_input_port_name('Input[InputPort-0]' , deferred_node_0) + deferred_shadowed_1_rev = _shadowed_state_input_port_name('reward[InputPort-0]' , deferred_node_1) + deferred_numeric_input_port_0 = _numeric_state_input_port_name(deferred_node_0) + deferred_numeric_input_port_1 = _numeric_state_input_port_name(deferred_node_1) + deferred_reward_node = _deferred_agent_rep_input_port_name('reward[InputPort-0]', 'evc') + deferred_Input_node = _deferred_agent_rep_input_port_name('Input[InputPort-0]', 'evc') + shadowed_reward_node = _shadowed_state_input_port_name('reward[InputPort-0]', 'reward[InputPort-0]') + shadowed_Input_node = _shadowed_state_input_port_name('Input[InputPort-0]', 'Input[InputPort-0]') + shadowed_reward_node_rev = _shadowed_state_input_port_name('reward[InputPort-0]', 'Input[InputPort-0]') + shadowed_Input_node_rev = _shadowed_state_input_port_name('Input[InputPort-0]', 'reward[InputPort-0]') + numeric_reward_node = _numeric_state_input_port_name('reward[InputPort-0]') + numeric_Input_node = _numeric_state_input_port_name('Input[InputPort-0]') + assert comp._controller_initialization_status == pnl.ContextFlags.DEFERRED_INIT + if state_features_arg in {'none', 'default_none'}: + assert comp.controller.state_input_ports.names == [] + assert comp.controller.state_features == {} + assert comp.controller.state_feature_values == {} + elif state_features_arg == 'list_none': + assert comp.controller.state_input_ports.names == [] + assert comp.controller.state_features == {deferred_node_0: None, deferred_node_1: None} + assert comp.controller.state_feature_values == {} + elif state_features_arg == 'list_ports': + assert comp.controller.state_input_ports.names == [deferred_shadowed_0, deferred_shadowed_1] + assert comp.controller.state_features == {deferred_node_0: deferred_reward_input_port, + deferred_node_1: deferred_Input_input_port} + assert comp.controller.state_feature_values == {deferred_node_0: deferred_reward_input_port, + deferred_node_1: deferred_Input_input_port} + elif state_features_arg == 'list_reversed': + assert comp.controller.state_input_ports.names == [deferred_shadowed_0_rev, deferred_shadowed_1_rev] + assert comp.controller.state_features == {deferred_node_0: deferred_Input_input_port, + deferred_node_1: deferred_reward_input_port} + assert comp.controller.state_feature_values == {deferred_node_0: deferred_Input_input_port, + deferred_node_1: deferred_reward_input_port} + elif state_features_arg == 'list_partial': + assert comp.controller.state_input_ports.names == [deferred_shadowed_0] + assert comp.controller.state_features == {deferred_node_0: deferred_reward_input_port} + assert comp.controller.state_feature_values == {deferred_node_0: deferred_reward_input_port} + elif state_features_arg == 'list_numeric': + assert comp.controller.state_input_ports.names == [deferred_numeric_input_port_0, + deferred_numeric_input_port_1] + assert comp.controller.state_features == {deferred_node_0: [1.1], deferred_node_1: [2.2]} + assert np.allclose(list(comp.controller.state_feature_values.values()), [[0.9625],[1.925]]) + assert list(comp.controller.state_feature_values.keys()) == [deferred_node_0, deferred_node_1] + elif state_features_arg == 'dict': + assert comp.controller.state_input_ports.names == [deferred_shadowed_0, deferred_shadowed_1] + assert comp.controller.state_features == {deferred_reward_node: deferred_reward_input_port, + deferred_Input_node: deferred_Input_input_port} + assert comp.controller.state_feature_values == {deferred_reward_node: deferred_reward_input_port, + deferred_Input_node: deferred_Input_input_port} + elif state_features_arg == 'dict_reversed': + assert comp.controller.state_input_ports.names == [deferred_shadowed_0_rev, deferred_shadowed_1_rev] + assert comp.controller.state_features == {deferred_reward_node: deferred_Input_input_port, + deferred_Input_node: deferred_reward_input_port} + assert comp.controller.state_feature_values == {deferred_reward_node: deferred_Input_input_port, + deferred_Input_node: deferred_reward_input_port} + elif state_features_arg == 'dict_partial': + assert comp.controller.state_input_ports.names == [deferred_shadowed_0] + assert comp.controller.state_features == {deferred_reward_node: deferred_reward_input_port} + assert comp.controller.state_feature_values == {deferred_reward_node: deferred_reward_input_port} + else: + assert False, f"TEST ERROR: unrecognized state_features_arg '{state_features_arg}'" + comp.add_node(reward, required_roles=[pnl.NodeRole.OUTPUT]) comp.add_node(Decision, required_roles=[pnl.NodeRole.OUTPUT]) task_execution_pathway = [Input, pnl.IDENTITY_MATRIX, Decision] @@ -169,6 +344,37 @@ def test_deferred_init(self): comp.enable_controller = True + if state_features_arg == 'default_none': + assert not any(p.path_afferents for p in comp.controller.state_input_ports) + assert comp.controller.state_features == {} + assert comp.controller.state_feature_values == {} + assert comp.controller.state_input_ports.names == [] + elif state_features_arg == 'list_none': + assert not any(p.path_afferents for p in comp.controller.state_input_ports) + assert comp.controller.state_features == {'reward[InputPort-0]': None, + 'Input[InputPort-0]': None} + assert comp.controller.state_feature_values == {} + assert comp.controller.state_input_ports.names == [] + elif state_features_arg == 'list_numeric': + assert not any(p.path_afferents for p in comp.controller.state_input_ports) + assert comp.controller.state_input_ports.names == [numeric_reward_node, numeric_Input_node] + assert comp.controller.state_features == {'reward[InputPort-0]': [1.1], + 'Input[InputPort-0]': [2.2]} + assert np.allclose(list(comp.controller.state_feature_values.values()), [[1.065625],[2.13125]]) + assert list(comp.controller.state_feature_values.keys()) == [reward.input_port, Input.input_port] + elif state_features_arg in {'list_reversed', 'dict_reversed'}: + assert all(p.path_afferents for p in comp.controller.state_input_ports) + assert comp.controller.state_features == {'reward[InputPort-0]': 'Input[InputPort-0]', + 'Input[InputPort-0]': 'reward[InputPort-0]'} + assert comp.controller.state_feature_values == {Input.input_port: [0], reward.input_port: [0]} + assert comp.controller.state_input_ports.names == [shadowed_Input_node_rev, shadowed_reward_node_rev] + else: + assert all(p.path_afferents for p in comp.controller.state_input_ports) + assert comp.controller.state_features == {'reward[InputPort-0]': 'reward[InputPort-0]', + 'Input[InputPort-0]': 'Input[InputPort-0]'} + assert comp.controller.state_feature_values == {reward.input_port: [0], Input.input_port: [0]} + assert comp.controller.state_input_ports.names == [shadowed_reward_node, shadowed_Input_node] + # comp._analyze_graph() stim_list_dict = { @@ -178,41 +384,143 @@ def test_deferred_init(self): comp.run(inputs=stim_list_dict) - # Note: Removed decision variable OutputPort from simulation results because sign is chosen randomly - expected_sim_results_array = [ - [[10.], [10.0], [0.0], [0.48999867], [0.50499983]], - [[10.], [10.0], [0.0], [1.08965888], [0.51998934]], - [[10.], [10.0], [0.0], [2.40680493], [0.53494295]], - [[10.], [10.0], [0.0], [4.43671978], [0.549834]], - [[10.], [10.0], [0.0], [0.48997868], [0.51998934]], - [[10.], [10.0], [0.0], [1.08459402], [0.57932425]], - [[10.], [10.0], [0.0], [2.36033556], [0.63645254]], - [[10.], [10.0], [0.0], [4.24948962], [0.68997448]], - [[10.], [10.0], [0.0], [0.48993479], [0.53494295]], - [[10.], [10.0], [0.0], [1.07378304], [0.63645254]], - [[10.], [10.0], [0.0], [2.26686573], [0.72710822]], - [[10.], [10.0], [0.0], [3.90353015], [0.80218389]], - [[10.], [10.0], [0.0], [0.4898672], [0.549834]], - [[10.], [10.0], [0.0], [1.05791834], [0.68997448]], - [[10.], [10.0], [0.0], [2.14222978], [0.80218389]], - [[10.], [10.0], [0.0], [3.49637662], [0.88079708]], - [[15.], [15.0], [0.0], [0.48999926], [0.50372993]], - [[15.], [15.0], [0.0], [1.08981011], [0.51491557]], - [[15.], [15.0], [0.0], [2.40822035], [0.52608629]], - [[15.], [15.0], [0.0], [4.44259627], [0.53723096]], - [[15.], [15.0], [0.0], [0.48998813], [0.51491557]], - [[15.], [15.0], [0.0], [1.0869779], [0.55939819]], - [[15.], [15.0], [0.0], [2.38198336], [0.60294711]], - [[15.], [15.0], [0.0], [4.33535807], [0.64492386]], - [[15.], [15.0], [0.0], [0.48996368], [0.52608629]], - [[15.], [15.0], [0.0], [1.08085171], [0.60294711]], - [[15.], [15.0], [0.0], [2.32712843], [0.67504223]], - [[15.], [15.0], [0.0], [4.1221271], [0.7396981]], - [[15.], [15.0], [0.0], [0.48992596], [0.53723096]], - [[15.], [15.0], [0.0], [1.07165729], [0.64492386]], - [[15.], [15.0], [0.0], [2.24934228], [0.7396981]], - [[15.], [15.0], [0.0], [3.84279648], [0.81637827]] - ] + if state_features_arg in {'default_none', 'list_none'}: + expected_sim_results_array = [ + [[0.], [0.], [0.], [0.49], [0.5]], + [[0.], [0.], [0.], [1.09], [0.5]], + [[0.], [0.], [0.], [2.41], [0.5]], + [[0.], [0.], [0.], [4.45], [0.5]], + [[0.], [0.], [0.], [0.49], [0.5]], + [[0.], [0.], [0.], [1.09], [0.5]], + [[0.], [0.], [0.], [2.41], [0.5]], + [[0.], [0.], [0.], [4.45], [0.5]], + [[0.], [0.], [0.], [0.49], [0.5]], + [[0.], [0.], [0.], [1.09], [0.5]], + [[0.], [0.], [0.], [2.41], [0.5]], + [[0.], [0.], [0.], [4.45], [0.5]], + [[0.], [0.], [0.], [0.49], [0.5]], + [[0.], [0.], [0.], [1.09], [0.5]], + [[0.], [0.], [0.], [2.41], [0.5]], + [[0.], [0.], [0.], [4.45], [0.5]], + [[0.], [0.], [0.], [0.49], [0.5]], + [[0.], [0.], [0.], [1.09], [0.5]], + [[0.], [0.], [0.], [2.41], [0.5]], + [[0.], [0.], [0.], [4.45], [0.5]], + [[0.], [0.], [0.], [0.49], [0.5]], + [[0.], [0.], [0.], [1.09], [0.5]], + [[0.], [0.], [0.], [2.41], [0.5]], + [[0.], [0.], [0.], [4.45], [0.5]], + [[0.], [0.], [0.], [0.49], [0.5]], + [[0.], [0.], [0.], [1.09], [0.5]], + [[0.], [0.], [0.], [2.41], [0.5]], + [[0.], [0.], [0.], [4.45], [0.5]], + [[0.], [0.], [0.], [0.49], [0.5]], + [[0.], [0.], [0.], [1.09], [0.5]], + [[0.], [0.], [0.], [2.41], [0.5]], + [[0.], [0.], [0.], [4.45], [0.5]]] + elif state_features_arg == 'list_numeric': + expected_sim_results_array = [ + [[1.09785156], [1.09785156], [0.], [0.48989747], [0.5438015]], + [[1.09946289], [1.09946289], [0.], [1.06483807], [0.66899791]], + [[1.09986572], [1.09986572], [0.], [2.19475384], [0.77414214]], + [[1.09996643], [1.09996643], [0.], [3.66103375], [0.85320293]], + [[1.09999161], [1.09999161], [0.], [0.48842594], [0.66907284]], + [[1.0999979], [1.0999979], [0.], [0.85321354], [0.94353405]], + [[1.09999948], [1.09999948], [0.], [1.23401798], [0.99281107]], + [[1.09999987], [1.09999987], [0.], [1.58437432], [0.99912464]], + [[1.09999997], [1.09999997], [0.], [0.48560629], [0.77416842]], + [[1.09999999], [1.09999999], [0.], [0.70600576], [0.99281108]], + [[1.1], [1.1], [0.], [0.90438208], [0.99982029]], + [[1.1], [1.1], [0.], [1.09934486], [0.99999554]], + [[1.1], [1.1], [0.], [0.48210997], [0.85320966]], + [[1.1], [1.1], [0.], [0.63149987], [0.99912464]], + [[1.1], [1.1], [0.], [0.76817898], [0.99999554]], + [[1.1], [1.1], [0.], [0.90454543], [0.99999998]], + [[1.1], [1.1], [0.], [0.48989707], [0.54388677]], + [[1.1], [1.1], [0.], [1.06481464], [0.66907403]], + [[1.1], [1.1], [0.], [2.19470819], [0.77416843]], + [[1.1], [1.1], [0.], [3.66099691], [0.85320966]], + [[1.1], [1.1], [0.], [0.48842592], [0.66907403]], + [[1.1], [1.1], [0.], [0.85321303], [0.94353433]], + [[1.1], [1.1], [0.], [1.23401763], [0.99281108]], + [[1.1], [1.1], [0.], [1.58437418], [0.99912464]], + [[1.1], [1.1], [0.], [0.48560629], [0.77416843]], + [[1.1], [1.1], [0.], [0.70600576], [0.99281108]], + [[1.1], [1.1], [0.], [0.90438208], [0.99982029]], + [[1.1], [1.1], [0.], [1.09934486], [0.99999554]], + [[1.1], [1.1], [0.], [0.48210997], [0.85320966]], + [[1.1], [1.1], [0.], [0.63149987], [0.99912464]], + [[1.1], [1.1], [0.], [0.76817898], [0.99999554]], + [[1.1], [1.1], [0.], [0.90454543], [0.99999998]]] + elif state_features_arg in {'list_reversed', 'dict_reversed'}: + expected_sim_results_array = [ + [[0.25], [0.25], [0.], [0.4879949], [0.68997448]], + [[0.25], [0.25], [0.], [0.81866742], [0.96083428]], + [[0.25], [0.25], [0.], [1.14484206], [0.99631576]], + [[0.25], [0.25], [0.], [1.4493293], [0.99966465]], + [[0.25], [0.25], [0.], [0.47304171], [0.96083428]], + [[0.25], [0.25], [0.], [0.54999945], [0.99999724]], + [[0.25], [0.25], [0.], [0.625], [1.]], + [[0.25], [0.25], [0.], [0.7], [1.]], + [[0.25], [0.25], [0.], [0.46418045], [0.99631576]], + [[0.25], [0.25], [0.], [0.50714286], [1.]], + [[0.25], [0.25], [0.], [0.55], [1.]], + [[0.25], [0.25], [0.], [0.59285714], [1.]], + [[0.25], [0.25], [0.], [0.45999329], [0.99966465]], + [[0.25], [0.25], [0.], [0.49], [1.]], + [[0.25], [0.25], [0.], [0.52], [1.]], + [[0.25], [0.25], [0.], [0.55], [1.]], + [[0.1865], [0.1865], [0.], [0.4858033], [0.76852478]], + [[0.1865], [0.1865], [0.], [0.7123133], [0.99183743]], + [[0.1865], [0.1865], [0.], [0.91645684], [0.99977518]], + [[0.1865], [0.1865], [0.], [1.11665847], [0.99999386]], + [[0.1865], [0.1865], [0.], [0.46639458], [0.99183743]], + [[0.1865], [0.1865], [0.], [0.51666667], [1.]], + [[0.1865], [0.1865], [0.], [0.56666667], [1.]], + [[0.1865], [0.1865], [0.], [0.61666667], [1.]], + [[0.1865], [0.1865], [0.], [0.45951953], [0.99977518]], + [[0.1865], [0.1865], [0.], [0.48809524], [1.]], + [[0.1865], [0.1865], [0.], [0.51666667], [1.]], + [[0.1865], [0.1865], [0.], [0.5452381], [1.]], + [[0.1865], [0.1865], [0.], [0.45666658], [0.99999386]], + [[0.1865], [0.1865], [0.], [0.47666667], [1.]], + [[0.1865], [0.1865], [0.], [0.49666667], [1.]], + [[0.1865], [0.1865], [0.], [0.51666667], [1.]]] + else: + # Note: Removed decision variable OutputPort from simulation results because sign is chosen randomly + expected_sim_results_array = [ + [[10.], [10.0], [0.0], [0.48999867], [0.50499983]], + [[10.], [10.0], [0.0], [1.08965888], [0.51998934]], + [[10.], [10.0], [0.0], [2.40680493], [0.53494295]], + [[10.], [10.0], [0.0], [4.43671978], [0.549834]], + [[10.], [10.0], [0.0], [0.48997868], [0.51998934]], + [[10.], [10.0], [0.0], [1.08459402], [0.57932425]], + [[10.], [10.0], [0.0], [2.36033556], [0.63645254]], + [[10.], [10.0], [0.0], [4.24948962], [0.68997448]], + [[10.], [10.0], [0.0], [0.48993479], [0.53494295]], + [[10.], [10.0], [0.0], [1.07378304], [0.63645254]], + [[10.], [10.0], [0.0], [2.26686573], [0.72710822]], + [[10.], [10.0], [0.0], [3.90353015], [0.80218389]], + [[10.], [10.0], [0.0], [0.4898672], [0.549834]], + [[10.], [10.0], [0.0], [1.05791834], [0.68997448]], + [[10.], [10.0], [0.0], [2.14222978], [0.80218389]], + [[10.], [10.0], [0.0], [3.49637662], [0.88079708]], + [[15.], [15.0], [0.0], [0.48999926], [0.50372993]], + [[15.], [15.0], [0.0], [1.08981011], [0.51491557]], + [[15.], [15.0], [0.0], [2.40822035], [0.52608629]], + [[15.], [15.0], [0.0], [4.44259627], [0.53723096]], + [[15.], [15.0], [0.0], [0.48998813], [0.51491557]], + [[15.], [15.0], [0.0], [1.0869779], [0.55939819]], + [[15.], [15.0], [0.0], [2.38198336], [0.60294711]], + [[15.], [15.0], [0.0], [4.33535807], [0.64492386]], + [[15.], [15.0], [0.0], [0.48996368], [0.52608629]], + [[15.], [15.0], [0.0], [1.08085171], [0.60294711]], + [[15.], [15.0], [0.0], [2.32712843], [0.67504223]], + [[15.], [15.0], [0.0], [4.1221271], [0.7396981]], + [[15.], [15.0], [0.0], [0.48992596], [0.53723096]], + [[15.], [15.0], [0.0], [1.07165729], [0.64492386]], + [[15.], [15.0], [0.0], [2.24934228], [0.7396981]], + [[15.], [15.0], [0.0], [3.84279648], [0.81637827]]] for simulation in range(len(expected_sim_results_array)): assert np.allclose(expected_sim_results_array[simulation], @@ -228,33 +536,39 @@ def test_deferred_init(self): np.testing.assert_allclose(comp.results[trial], expected_results_array[trial], atol=1e-08, err_msg='Failed on expected_output[{0}]'.format(trial)) - def test_partial_deferred_init(self): - deferred_node = pnl.ProcessingMechanism(name='deferred') + @pytest.mark.state_features + @pytest.mark.parametrize('state_features_option', ['list','set','dict','shadow_inputs_dict']) + def test_partial_deferred_init(self, state_features_option): initial_node_a = pnl.TransferMechanism(name='ia') initial_node_b = pnl.ProcessingMechanism(name='ib') + deferred_node = pnl.ProcessingMechanism(name='deferred') ocomp = pnl.Composition(name='ocomp', pathways=[initial_node_a, initial_node_b], controller_mode=pnl.BEFORE) - member_node_control_signal = pnl.ControlSignal(projections=[(pnl.SLOPE, initial_node_a)], + member_node_control_signal = pnl.ControlSignal(control=[(pnl.SLOPE, initial_node_a)], variable=1.0, intensity_cost_function=pnl.Linear(slope=0.0), - allocation_samples=pnl.SampleSpec(start=1.0, - stop=5.0, - num=5)) + allocation_samples=pnl.SampleSpec(start=1.0, stop=5.0, num=5)) deferred_node_control_signal = pnl.ControlSignal(projections=[(pnl.SLOPE, deferred_node)], variable=1.0, intensity_cost_function=pnl.Linear(slope=0.0), - allocation_samples=pnl.SampleSpec(start=1.0, - stop=5.0, - num=5)) + allocation_samples=pnl.SampleSpec(start=1.0, stop=5.0, num=5)) + state_features = { + 'list': [initial_node_a.input_port, + deferred_node.input_port], + 'set': {initial_node_a, + deferred_node}, + 'dict': {initial_node_a: initial_node_a.input_port, + deferred_node: deferred_node.input_port}, + 'shadow_inputs_dict': {pnl.SHADOW_INPUTS: [initial_node_a, deferred_node]} + }[state_features_option] ocomp.add_controller( pnl.OptimizationControlMechanism( agent_rep=ocomp, - state_features=[initial_node_a.input_port, - deferred_node.input_port], + state_features = state_features, name="Controller", objective_mechanism=pnl.ObjectiveMechanism( monitor=initial_node_b.output_port, @@ -267,205 +581,163 @@ def test_partial_deferred_init(self): deferred_node_control_signal ]) ) + deferred_input_port = _deferred_state_feature_spec_msg('deferred[InputPort-0]', 'ocomp') + deferred_node_0 = _deferred_agent_rep_input_port_name('0','ocomp') + deferred_shadowed_0 = _shadowed_state_input_port_name('deferred[InputPort-0]' , deferred_node_0) + deferred_node_deferred = _deferred_agent_rep_input_port_name('deferred[InputPort-0]','ocomp') + shadowed_ia_node = _shadowed_state_input_port_name('ia[InputPort-0]' ,'ia[InputPort-0]') + shadowed_deferred_node_0 = _shadowed_state_input_port_name('deferred[InputPort-0]', deferred_node_0) + shadowed_deferred_node_deferred = _shadowed_state_input_port_name('deferred[InputPort-0]', + 'deferred[InputPort-0]') + + assert ocomp.controller.state_input_ports.names == [shadowed_ia_node, shadowed_deferred_node_0] + + if state_features_option in {'list', 'shadow_inputs_dict'}: + assert ocomp.controller.state_features == {'ia[InputPort-0]': 'ia[InputPort-0]', + deferred_node_0: deferred_input_port} + assert ocomp.controller.state_feature_values == {initial_node_a.input_port: [0.], + deferred_node_0: deferred_input_port} + elif state_features_option in {'dict', 'set'}: + assert ocomp.controller.state_features == {'ia[InputPort-0]': 'ia[InputPort-0]', + deferred_node_deferred: deferred_input_port} + assert ocomp.controller.state_feature_values == {initial_node_a.input_port: [0.], + deferred_node_deferred: deferred_input_port} + else: + assert False, f"TEST ERROR: unrecognized option '{state_features_option}'" + + + if state_features_option in {'list', 'shadow_inputs_dict'}: + # expected_text = 'The number of \'state_features\' specified for Controller (2) is more than the ' \ + # 'number of INPUT Nodes (1) of the Composition assigned as its agent_rep (\'ocomp\').' + # + expected_text = 'The number of \'state_features\' specified for Controller (2) is more than the ' \ + 'number of INPUT Nodes (1) of the Composition assigned as its agent_rep (\'ocomp\'), ' \ + 'that includes the following: \'deferred\' missing from ocomp.' + + else: + expected_text = 'The \'state_features\' specified for \'Controller\' contains an item (deferred) ' \ + 'that is not an INPUT Node within its agent_rep (\'ocomp\'); only INPUT Nodes can be ' \ + 'in a set or used as keys in a dict used to specify \'state_features\'.' - expected_text_1 = f"{ocomp.controller.name}, being used as controller for " \ - f"model-based optimization of {ocomp.name}, has 'state_features' specified " - expected_text_2 = f"that are missing from the Composition or any nested within it" with pytest.raises(pnl.OptimizationControlMechanismError) as error_text: ocomp.run({initial_node_a: [1]}) - error_text = error_text.value.error_value - assert expected_text_1 in error_text and expected_text_2 in error_text + assert expected_text in error_text.value.error_value ocomp.add_linear_processing_pathway([deferred_node, initial_node_b]) + assert ocomp.controller.state_features == {'ia[InputPort-0]': 'ia[InputPort-0]', + 'deferred[InputPort-0]': 'deferred[InputPort-0]'} + assert ocomp.controller.state_feature_values == {initial_node_a.input_port: [0.], + deferred_node.input_port: [0.]} + assert all(p.path_afferents for p in ocomp.controller.state_input_ports) + assert ocomp.controller.state_input_ports.names == [shadowed_ia_node, shadowed_deferred_node_deferred] + result = ocomp.run({ initial_node_a: [1], deferred_node: [1] }) - # result = 10, the sum of the input (1) multiplied by the value of the ControlSignals projecting, respectively, to Node "ia" and Node "deferred_node" + # result = 10, the sum of the input (1) multiplied by the value of the ControlSignals projecting, + # respectively, to Node "ia" and Node "deferred_node" # Control Signal "ia": Maximizes over the search space consisting of ints 1-5 # Control Signal "deferred_node": Maximizes over the search space consisting of ints 1-5 assert result == [[10]] - # FIX: DEPRACATE THIS TEST - IT ALLOWS A COMPOSITION TO EXECUTE WITH A BAD MONITOR FOR CONTROL SPECIFICATION - # SUPERCEDED BY test_args_specific_to_ocm outcome_input_ports WHICH TESTS FOR THIS - # def test_deferred_objective_mech(self): - # initial_node = pnl.TransferMechanism(name='initial_node') - # deferred_node = pnl.ProcessingMechanism(name='deferred') - # ocomp = pnl.Composition(name='ocomp', - # pathways=[initial_node], - # controller_mode=pnl.BEFORE) - # - # initial_node_control_signal = pnl.ControlSignal(projections=[(pnl.SLOPE, initial_node)], - # variable=1.0, - # intensity_cost_function=pnl.Linear(slope=0.0), - # allocation_samples=pnl.SampleSpec(start=1.0, - # stop=5.0, - # num=5)) - # - # ocomp.add_controller( - # pnl.OptimizationControlMechanism( - # agent_rep=ocomp, - # state_features=[initial_node.input_port], - # name="Controller", - # objective_mechanism=pnl.ObjectiveMechanism( - # monitor=deferred_node.output_port, - # function=pnl.SimpleIntegrator, - # name="oController Objective Mechanism" - # ), - # function=pnl.GridSearch(direction=pnl.MAXIMIZE), - # control_signals=[ - # initial_node_control_signal - # ]) - # ) - # - # text = 'The controller of ocomp has a specification that includes the '\ - # 'Mechanism oController Objective Mechanism, but oController '\ - # 'Objective Mechanism is not in ocomp or any of its nested Compositions. '\ - # 'This Mechanism will be deactivated until oController Objective Mechanism is '\ - # 'added to ocomp or one of its nested Compositions in a compatible way.' - # with pytest.warns(UserWarning, match=text): - # result = ocomp.run({initial_node: [1]}) - # - # assert result == [[1]] - # # result = 1, the input (1) multiplied by the first value in the SearchSpace of the ControlSignal projecting to - # # initial_node (1) - # - # # The objective Mechanism is disabled because one of its aux components is a projection to - # # deferred_node, which is not currently a member node of the composition. Therefore, the Controller - # # has no basis to determine which set of values it should use for its efferent ControlProjections and - # # simply goes with the first in the search space, which is 1. - # - # # add deferred_node to the Composition - # ocomp.add_linear_processing_pathway([initial_node, deferred_node]) - # - # # The objective mechanism's aux components are now all legal, so it will be activated on the following run - # result = ocomp.run({initial_node: [[1]]}) - # assert result == [[5]] - # # result = 5, the input (1) multiplied by the value of the ControlSignal projecting to Node "ia" - # # Control Signal "ia": Maximizes over the search space consisting of ints 1-5 - - # id, agent_rep, state_feat, mon_for_ctl, allow_probes, obj_mech err_type, error_msg - params = [ - ("allowable1", - "icomp", "I", "I", True, None, None, None - ), - ("allowable2", - "mcomp", "Ii A", "I B", True, None, None, None - ), - ("state_features_test_internal", - "icomp", "B", "I", True, None, pnl.CompositionError, - "Attempt to shadow the input to a node (B) in a nested Composition of OUTER COMP " - "that is not an INPUT Node of that Composition is not currently supported." - ), - ("state_features_test_not_in_agent_rep", - "icomp", "A", "I", True, None, pnl.OptimizationControlMechanismError, - "OCM, being used as controller for model-based optimization of INNER COMP, has 'state_features' " - "specified (['Shadowed input of A']) that are missing from the Composition or any nested within it." - ), - ("monitor_for_control_test_not_in_agent_rep", - "icomp", "I", "B", True, None, pnl.OptimizationControlMechanismError, - "OCM has 'outcome_ouput_ports' that receive Projections from the following Components " - "that do not belong to its agent_rep (INNER COMP): ['B']." - ), - ("monitor_for_control_with_obj_mech_test", - "icomp", "I", None, True, True, pnl.OptimizationControlMechanismError, - "OCM has 'outcome_ouput_ports' that receive Projections from the following Components " - "that do not belong to its agent_rep (INNER COMP): ['B']." - ), - ("probe_error_test", - "mcomp", "I", "B", False, None, pnl.CompositionError, - "B found in nested Composition of OUTER COMP (MIDDLE COMP) but without " - "required NodeRole.OUTPUT. Try setting 'allow_probes' argument of OCM to 'True'." - ), - ("probe_error_obj_mech_test", - "mcomp", "I", None, False, True, pnl.CompositionError, - "B found in nested Composition of OUTER COMP (MIDDLE COMP) but without required NodeRole.OUTPUT. " - "Try setting 'allow_probes' argument of ObjectiveMechanism for OCM to 'True'." - ) - ] - @pytest.mark.parametrize('id, agent_rep, state_features, monitor_for_control, allow_probes, objective_mechanism, error_type, err_msg', - params, ids=[x[0] for x in params]) - def test_args_specific_to_ocm(self, id, agent_rep, state_features, monitor_for_control, - allow_probes, objective_mechanism, error_type,err_msg): - """Test args specific to OptimizationControlMechanism - - state_feature must be in agent_rep - - monitor_for_control must be in agent_rep, whether specified directly or for ObjectiveMechanism - - allow_probes allows INTERNAL Nodes of nested comp to be monitored, otherwise generates and error - - probes are not included in Composition.results - """ - - # FIX: ADD VERSION WITH agent_rep = CompositionFuntionApproximator - # ADD TESTS FOR SEPARATE AND CONCATENATE - - from psyneulink.core.globals.utilities import convert_to_list - - I = pnl.ProcessingMechanism(name='I') - icomp = pnl.Composition(nodes=I, name='INNER COMP') - - A = pnl.ProcessingMechanism(name='A') - B = pnl.ProcessingMechanism(name='B') - C = pnl.ProcessingMechanism(name='C') - mcomp = pnl.Composition(pathways=[[A,B,C],icomp], - name='MIDDLE COMP') - ocomp = pnl.Composition(nodes=[mcomp], name='OUTER COMP', allow_probes=allow_probes) + def test_deferred_objective_mech(self): + initial_node = pnl.TransferMechanism(name='initial_node') + deferred_node = pnl.ProcessingMechanism(name='deferred') + ocomp = pnl.Composition(name='ocomp', + pathways=[initial_node], + controller_mode=pnl.BEFORE) - agent_rep = {"mcomp":mcomp, - "icomp":icomp - }[agent_rep] + initial_node_control_signal = pnl.ControlSignal(projections=[(pnl.SLOPE, initial_node)], + variable=1.0, + intensity_cost_function=pnl.Linear(slope=0.0), + allocation_samples=pnl.SampleSpec(start=1.0, + stop=5.0, + num=5)) + ocomp.add_controller( + pnl.OptimizationControlMechanism( + agent_rep=ocomp, + state_features=[initial_node.input_port], + name="Controller", + objective_mechanism=pnl.ObjectiveMechanism( + monitor=deferred_node.output_port, + function=pnl.SimpleIntegrator, + name="oController Objective Mechanism" + ), + function=pnl.GridSearch(direction=pnl.MAXIMIZE), + control_signals=[ + initial_node_control_signal + ]) + ) - state_features = {"I":I, - "Ii A":[I.input_port, A], - "A":A, - "B":B, - }[state_features] + text = '"Controller has \'outcome_ouput_ports\' that receive Projections from the following Components ' \ + 'that do not belong to its agent_rep (ocomp): [\'deferred\']."' + with pytest.raises(pnl.OptimizationControlMechanismError) as error: + ocomp.run({initial_node: [1]}) + assert text == str(error.value) - if monitor_for_control: - monitor_for_control = {"I":I, - "I B":[I, B], - "B":B, - }[monitor_for_control] + # The objective Mechanism is disabled because one of its aux components is a projection to + # deferred_node, which is not currently a member node of the composition. Therefore, the Controller + # has no basis to determine which set of values it should use for its efferent ControlProjections and + # simply goes with the first in the search space, which is 1. - if objective_mechanism: - objective_mechanism = pnl.ObjectiveMechanism(monitor=B) + # add deferred_node to the Composition + ocomp.add_linear_processing_pathway([initial_node, deferred_node]) - if not err_msg: - ocm = pnl.OptimizationControlMechanism(name='OCM', - agent_rep=agent_rep, - state_features=state_features, - monitor_for_control=monitor_for_control, - objective_mechanism=objective_mechanism, - allow_probes=allow_probes, - function=pnl.GridSearch(), - control_signals=pnl.ControlSignal(modulates=(pnl.SLOPE,I), - allocation_samples=[10, 20, 30]) - ) - ocomp.add_controller(ocm) - ocomp._analyze_graph() - if allow_probes and B in convert_to_list(monitor_for_control): - # If this fails, could be due to ordering of ports in ocomp.output_CIM (current assumes probe is on 0) - assert ocomp.output_CIM._sender_is_probe(ocomp.output_CIM.output_ports[0]) - # Affirm that PROBE (included in ocomp's output_ports via its output_CIM - # but is *not* included in Composition.output_values (which is used for Composition.results) - assert len(ocomp.output_values) == len(ocomp.output_ports) - 1 + # The objective mechanism's aux components are now all legal, so it will be activated on the following run + result = ocomp.run({initial_node: [[1]]}) + assert result == [[5]] + # result = 5, the input (1) multiplied by the value of the ControlSignal projecting to Node "ia" + # Control Signal "ia": Maximizes over the search space consisting of ints 1-5 - else: - with pytest.raises(error_type) as err: - ocm = pnl.OptimizationControlMechanism(name='OCM', - agent_rep=agent_rep, - state_features=state_features, - monitor_for_control=monitor_for_control, - objective_mechanism=objective_mechanism, - allow_probes=allow_probes, - function=pnl.GridSearch(), - control_signals=pnl.ControlSignal(modulates=(pnl.SLOPE, - I), - allocation_samples=[10, 20, 30]) - ) - ocomp.add_controller(ocm) - ocomp._analyze_graph() - assert err.value.error_value == err_msg + def test_warning_for_add_controller_twice(self): + mech = pnl.ProcessingMechanism() + ctlr_1 = pnl.ControlMechanism() + comp = pnl.Composition() + comp.add_node(mech) + comp.add_controller(ctlr_1) + with pytest.warns(UserWarning, match="ControlMechanism-0 has already been assigned as the controller " + "for Composition-0; assignment ignored."): + comp.add_controller(ctlr_1) + + def test_warning_for_controller_assigned_to_another_comp(self): + mech_1 = pnl.ProcessingMechanism() + ctlr_1 = pnl.ControlMechanism() + comp_1 = pnl.Composition() + comp_1.add_node(mech_1) + comp_1.add_controller(ctlr_1) + mech_2 = pnl.ProcessingMechanism() + comp_2 = pnl.Composition() + comp_2.add_node(mech_2) + with pytest.warns(UserWarning, match="'ControlMechanism-0' has already been assigned as the controller " + "for 'Composition-0'; assignment to 'Composition-1' ignored."): + comp_2.add_controller(ctlr_1) + + def test_warning_for_replacement_of_controller(self): + mech = pnl.ProcessingMechanism() + ctlr_1 = pnl.ControlMechanism() + comp = pnl.Composition() + comp.add_node(mech) + comp.add_controller(ctlr_1) + ctlr_2 = pnl.ControlMechanism() + expected_warning = "The existing controller for 'Composition-0' ('ControlMechanism-0') " \ + "is being replaced by 'ControlMechanism-1'." + with pytest.warns(UserWarning) as warning: + comp.add_controller(ctlr_2) + assert expected_warning in repr(warning[0].message.args[0]) + + def test_controller_has_no_input(self): + mech = pnl.ProcessingMechanism() + ctlr = pnl.ControlMechanism() + comp = pnl.Composition() + comp.add_node(mech) + expected_warning = 'ControlMechanism-0 for Composition-0 is enabled but has no inputs.' + with pytest.warns(UserWarning) as warning: + comp.enable_controller = True + comp.add_controller(ctlr) + assert expected_warning in repr(warning[0].message.args[0]) - def test_agent_rep_assignement_as_controller_and_replacement(self): + def test_agent_rep_assignment_as_controller_and_replacement(self): mech = pnl.ProcessingMechanism() comp = pnl.Composition(name='comp', pathways=[mech], @@ -665,8 +937,788 @@ def test_transfer_mechanism_and_ocm_variations( else: assert 'a[intercept] ControlSignal' not in ocm.control.names +@pytest.mark.control class TestControlMechanisms: + # id, agent_rep, state_feat, mon_for_ctl, allow_probes, obj_mech err_type, error_msg + params = [ + ("allowable1", + "icomp", "I", "I", True, None, None, None + ), + ("allowable2", + "mcomp", "Ii A", "I B", True, None, None, None + ), + ("state_features_test_internal", + "icomp", "B", "I", True, None, pnl.CompositionError, + "Attempt to shadow the input to a node (B) in a nested Composition of OUTER COMP " + "that is not an INPUT Node of that Composition is not currently supported." + ), + ("state_features_test_not_in_agent_rep", + "icomp", "A", "I", True, None, pnl.OptimizationControlMechanismError, + '\'OCM\' has \'state_features\' specified ([\'SHADOWED INPUT OF A[InputPort-0] FOR I[InputPort-0]\']) ' + 'that are missing from both its `agent_rep` (\'INNER COMP\') as well as \'OUTER COMP\' ' + 'and any Compositions nested within it.' + ), + ("monitor_for_control_test_not_in_agent_rep", + "icomp", "I", "B", True, None, pnl.OptimizationControlMechanismError, + "OCM has 'outcome_ouput_ports' that receive Projections from the following Components " + "that do not belong to its agent_rep (INNER COMP): ['B']." + ), + ("monitor_for_control_with_obj_mech_test", + "icomp", "I", None, True, True, pnl.OptimizationControlMechanismError, + "OCM has 'outcome_ouput_ports' that receive Projections from the following Components " + "that do not belong to its agent_rep (INNER COMP): ['B']." + ), + ("probe_error_test", + "mcomp", "I", "B", False, None, pnl.CompositionError, + "B found in nested Composition of OUTER COMP (MIDDLE COMP) but without " + "required NodeRole.OUTPUT. Try setting 'allow_probes' argument of OCM to 'True'." + ), + ("probe_error_obj_mech_test", + "mcomp", "I", None, False, True, pnl.CompositionError, + "B found in nested Composition of OUTER COMP (MIDDLE COMP) but without required NodeRole.OUTPUT. " + "Try setting 'allow_probes' argument of ObjectiveMechanism for OCM to 'True'." + ), + ("cfa_as_agent_rep_error", + "cfa", "dict", None, False, True, pnl.OptimizationControlMechanismError, + 'The agent_rep specified for OCM is a CompositionFunctionApproximator, so its \'state_features\' argument ' + 'must be a list, not a dict ({(ProcessingMechanism A): (InputPort InputPort-0), ' + '(ProcessingMechanism B): (InputPort InputPort-0)}).' + ) + ] + @pytest.mark.parametrize('id, agent_rep, state_features, monitor_for_control, allow_probes, ' + 'objective_mechanism, error_type, err_msg', + params, ids=[x[0] for x in params]) + def test_args_specific_to_ocm(self, id, agent_rep, state_features, monitor_for_control, + allow_probes, objective_mechanism, error_type,err_msg): + """Test args specific to OptimizationControlMechanism + NOTE: state_features and associated warning and errors tested more fully in + test_ocm_state_feature_specs_and_warnings_and_errors() below + - state_feature must be in agent_rep + - monitor_for_control must be in agent_rep, whether specified directly or for ObjectiveMechanism + - allow_probes allows INTERNAL Nodes of nested comp to be monitored, otherwise generates and error + - probes are not included in Composition.results + """ + + # FIX: ADD VERSION WITH agent_rep = CompositionFuntionApproximator + # ADD TESTS FOR SEPARATE AND CONCATENATE + + from psyneulink.core.globals.utilities import convert_to_list + + I = pnl.ProcessingMechanism(name='I') + icomp = pnl.Composition(nodes=I, name='INNER COMP') + + A = pnl.ProcessingMechanism(name='A') + B = pnl.ProcessingMechanism(name='B') + C = pnl.ProcessingMechanism(name='C') + mcomp = pnl.Composition(pathways=[[A,B,C],icomp], + name='MIDDLE COMP') + ocomp = pnl.Composition(nodes=[mcomp], name='OUTER COMP', allow_probes=allow_probes) + cfa = pnl.RegressionCFA + + agent_rep = {"mcomp":mcomp, + "icomp":icomp, + "cfa": cfa + }[agent_rep] + + state_features = {"I":I, + "Ii A":[I.input_port, A], + "A":A, + "B":B, + "dict":{A:A.input_port, B:B.input_port} + }[state_features] + + if monitor_for_control: + monitor_for_control = {"I":I, + "I B":[I, B], + "B":B, + }[monitor_for_control] + + if objective_mechanism: + objective_mechanism = pnl.ObjectiveMechanism(monitor=B) + + if not err_msg: + ocm = pnl.OptimizationControlMechanism(name='OCM', + agent_rep=agent_rep, + state_features=state_features, + monitor_for_control=monitor_for_control, + objective_mechanism=objective_mechanism, + allow_probes=allow_probes, + function=pnl.GridSearch(), + control_signals=pnl.ControlSignal(modulates=(pnl.SLOPE,I), + allocation_samples=[10, 20, 30]) + ) + ocomp.add_controller(ocm) + ocomp._analyze_graph() + if allow_probes and B in convert_to_list(monitor_for_control): + # If this fails, could be due to ordering of ports in ocomp.output_CIM (current assumes probe is on 0) + assert ocomp.output_CIM._sender_is_probe(ocomp.output_CIM.output_ports[0]) + # Affirm that PROBE (included in ocomp's output_ports via its output_CIM + # but is *not* included in Composition.output_values (which is used for Composition.results) + assert len(ocomp.output_values) == len(ocomp.output_ports) - 1 + + else: + with pytest.raises(error_type) as err: + ocm = pnl.OptimizationControlMechanism(name='OCM', + agent_rep=agent_rep, + state_features=state_features, + monitor_for_control=monitor_for_control, + objective_mechanism=objective_mechanism, + allow_probes=allow_probes, + function=pnl.GridSearch(), + control_signals=pnl.ControlSignal(modulates=(pnl.SLOPE, + I), + allocation_samples=[10, 20, 30]) + ) + ocomp.add_controller(ocm) + ocomp._analyze_graph() + ocomp.run() + assert err.value.error_value == err_msg + + messages = [ + # 0 + f"There are fewer '{pnl.STATE_FEATURES}' specified for 'OptimizationControlMechanism-0' than the number " + f"of InputPort's for all of the INPUT Nodes of its agent_rep ('OUTER COMP'); the remaining inputs will be " + f"assigned default values when 'OUTER COMP`s 'evaluate' method is executed. If this is not the desired " + f"behavior, use its get_inputs_format() method to see the format for its inputs.", + + # 1 + f'\'Attempt to shadow the input to a node (IB) in a nested Composition of OUTER COMP ' + f'that is not an INPUT Node of that Composition is not currently supported.\'', + + # 2 + f'"\'OptimizationControlMechanism-0\' has \'state_features\' specified ([\'SHADOWED INPUT OF EXT[InputPort-0] ' + f'FOR IA[InputPort-0]\']) that are missing from \'OUTER COMP\' and any Compositions nested within it."', + + # 3 + '"\'OptimizationControlMechanism-0\' has \'state_features\' specified ([\'INPUT FROM EXT[OutputPort-0] ' + 'FOR IA[InputPort-0]\']) that are missing from \'OUTER COMP\' and any Compositions nested within it."', + + # 4 + f"The '{pnl.STATE_FEATURES}' argument has been specified for 'OptimizationControlMechanism-0' that is using " + f"a Composition ('OUTER COMP') as its agent_rep, but some of the specifications are not compatible with the " + f"inputs required by its 'agent_rep': 'Input stimulus ([0.0]) for OB is incompatible with the shape of its " + f"external input ([0.0 0.0 0.0]).' Use the get_inputs_format() method of 'OUTER COMP' to see the required " + f"format, or remove the specification of 'state_features' from the constructor for " + f"OptimizationControlMechanism-0 to have them automatically assigned.", + + # 5 + f"The '{pnl.STATE_FEATURES}' specified for OptimizationControlMechanism-0 is associated with a number of " + f"InputPorts (4) that is greater than for the InputPorts of the INPUT Nodes (3) for the Composition assigned " + f"as its agent_rep ('OUTER COMP'). Executing OptimizationControlMechanism-0 before the additional item(s) are " + f"added as (part of) INPUT Nodes will generate an error.", + + # 6 + f"The '{pnl.STATE_FEATURES}' specified for OptimizationControlMechanism-0 is associated with a number of " + f"InputPorts (4) that is greater than for the InputPorts of the INPUT Nodes (3) for the Composition assigned " + f"as its agent_rep ('OUTER COMP'), which includes the following that are not (yet) in 'OUTER COMP': 'EXT'. " + f"Executing OptimizationControlMechanism-0 before the additional item(s) are added as (part of) INPUT Nodes " + f"will generate an error.", + + # 7 + f'"The number of \'state_features\' specified for OptimizationControlMechanism-0 (4) is more than the number ' + f'of INPUT Nodes (3) of the Composition assigned as its agent_rep (\'OUTER COMP\')."', + + # 8 + f'The \'state_features\' specified for \'OptimizationControlMechanism-0\' contains an item (OC) ' + f'that is not an INPUT Node within its agent_rep (\'OUTER COMP\'); only INPUT Nodes can be in a set or ' + f'used as keys in a dict used to specify \'state_features\'.', + + # 9 + f'The \'state_features\' specified for \'OptimizationControlMechanism-0\' contains an item (IA) ' + f'that is not an INPUT Node within its agent_rep (\'OUTER COMP\'); only INPUT Nodes can be in a set ' + f'or used as keys in a dict used to specify \'state_features\'.', + + # 10 + f"The '{pnl.STATE_FEATURES}' argument for 'OptimizationControlMechanism-0' includes one or more Compositions " + f"('INNER COMP') in the list specified for its '{pnl.STATE_FEATURES}' argument; these must be replaced by " + f"direct references to the Mechanisms (or their InputPorts) within them to be shadowed.", + + # 11 + f"The '{pnl.STATE_FEATURES}' argument for 'OptimizationControlMechanism-0' includes one or more Compositions " + f"('INNER COMP') in the SHADOW_INPUTS dict specified for its '{pnl.STATE_FEATURES}' argument; these must be " + f"replaced by direct references to the Mechanisms (or their InputPorts) within them to be shadowed.", + + # 12 + f"The '{pnl.STATE_FEATURES}' argument for 'OptimizationControlMechanism-0' has one or more items in the " + f"list specified for 'SHADOW_INPUTS' ('IA') that are not (part of) any INPUT Nodes of its 'agent_rep' " + f"('OUTER COMP').", + + # 13 + f"'OptimizationControlMechanism-0' has '{pnl.STATE_FEATURES}' specified " + f"(['SHADOWED INPUT OF EXT[InputPort-0] FOR IA[InputPort-0]', " + f"'SHADOWED INPUT OF EXT[InputPort-0] FOR OA[InputPort-0]', " + f"'SHADOWED INPUT OF EXT[InputPort-0] FOR OB[InputPort-0]']) " + f"that are missing from 'OUTER COMP' and any Compositions nested within it." + ] + state_feature_args = [ + # STATE_FEATURE_ARGS, STATE_FEATURE_DEFAULT, ERROR_OR_WARNING_MSG, EXCEPTION_TYPE + ('single_none_spec', pnl.SHADOW_INPUTS, None, None), + ('single_shadow_spec', pnl.SHADOW_INPUTS, None, None), + ('single_tuple_shadow_spec', pnl.SHADOW_INPUTS, None, None), + ('partial_legal_list_spec', pnl.SHADOW_INPUTS, messages[0], UserWarning), + ('full_list_spec', pnl.SHADOW_INPUTS, None, None), + ('list_spec_with_none', pnl.SHADOW_INPUTS, None, None), + ('input_dict_spec', pnl.SHADOW_INPUTS, None, None), + ('input_dict_spec_short', pnl.SHADOW_INPUTS, None, None), + ('set_spec_short', None, None, None), + ('set_spec', pnl.SHADOW_INPUTS, None, None), + ('set_spec_port', pnl.SHADOW_INPUTS, None, None), + ('no_specs', None, None, None), + ('shadow_inputs_dict_spec', pnl.SHADOW_INPUTS, None, None), + ('shadow_inputs_dict_spec_w_none', pnl.SHADOW_INPUTS, None, None), + ('misplaced_shadow', pnl.SHADOW_INPUTS, messages[1], pnl.CompositionError), + ('ext_shadow', pnl.SHADOW_INPUTS, messages[2], pnl.OptimizationControlMechanismError), + ('ext_output_port', pnl.SHADOW_INPUTS, messages[3], pnl.OptimizationControlMechanismError), + ('input_format_wrong_shape', pnl.SHADOW_INPUTS, messages[4], pnl.OptimizationControlMechanismError), + ('too_many_inputs_warning', pnl.SHADOW_INPUTS, messages[5], UserWarning), + ('too_many_w_node_not_in_composition_warning', pnl.SHADOW_INPUTS, messages[6], UserWarning), + ('too_many_inputs_error', pnl.SHADOW_INPUTS, messages[7], pnl.OptimizationControlMechanismError), + ('bad_single_spec', pnl.SHADOW_INPUTS, messages[13], pnl.OptimizationControlMechanismError), + ('bad_dict_spec_warning', pnl.SHADOW_INPUTS, messages[8], UserWarning), + ('bad_dict_spec_error', pnl.SHADOW_INPUTS, messages[8], pnl.OptimizationControlMechanismError), + ('bad_shadow_inputs_dict_spec_error', pnl.SHADOW_INPUTS, messages[12], pnl.OptimizationControlMechanismError), + ('comp_in_list_spec', pnl.SHADOW_INPUTS, messages[10], pnl.OptimizationControlMechanismError), + ('comp_in_shadow_inupts_spec', pnl.SHADOW_INPUTS, messages[11], pnl.OptimizationControlMechanismError) + ] + if len(state_feature_args) != 27: + print("\n\n************************************************************************************************") + print("*** UNCOMMENT state_feature_args IN test_ocm_state_feature_specs_and_warnings_and_errors() *****") + print("************************************************************************************************") + @pytest.mark.state_features + @pytest.mark.control + @pytest.mark.parametrize('state_feature_args', state_feature_args, ids=[x[0] for x in state_feature_args]) + @pytest.mark.parametrize('obj_mech', ['obj_mech', 'mtr_for_ctl', None]) + def test_ocm_state_feature_specs_and_warnings_and_errors(self, state_feature_args, obj_mech): + """See test_nested_composition_as_agent_rep() for additional tests of state_features specification.""" + + test_condition = state_feature_args[0] + state_feature_default = state_feature_args[1] + error_or_warning_message = state_feature_args[2] + exception_type = state_feature_args[3] + + ia = pnl.ProcessingMechanism(name='IA') + ib = pnl.ProcessingMechanism(name='IB') + ic = pnl.ProcessingMechanism(name='IC') + oa = pnl.ProcessingMechanism(name='OA') + ob = pnl.ProcessingMechanism(name='OB', size=3) + oc = pnl.ProcessingMechanism(name='OC') + ext = pnl.ProcessingMechanism(name='EXT') + icomp = pnl.Composition(pathways=[ia,ib,ic], name='INNER COMP') + ocomp = pnl.Composition(pathways=[icomp], name='OUTER COMP') + ocomp.add_linear_processing_pathway([oa,oc]) + ocomp.add_linear_processing_pathway([ob,oc]) + + state_features_dict = { + + # Legal state_features specifications + 'single_none_spec': None, + 'single_shadow_spec': pnl.SHADOW_INPUTS, + 'single_tuple_shadow_spec': (pnl.SHADOW_INPUTS, pnl.Logistic), # state_feature_values should be 0.5 + 'partial_legal_list_spec': [oa.output_port], # only specifies ia; oa and ob assigned default inputs + 'full_list_spec': [ia.input_port, oa.output_port, [3,1,2]], + 'list_spec_with_none': [ia.input_port, None, [3,1,2]], + 'input_dict_spec': {oa:oc.input_port, icomp:ia, ob:ob.output_port}, # use icomp & out of order is OK + 'input_dict_spec_short': {ob:ob.output_port, oa:oc.input_port}, # missing ia spec and out of order + 'set_spec_short': {oa}, + 'set_spec': {ob, icomp, oa.input_port}, # out of order, use of Nested comp and InputPort as specs all OK + 'set_spec_port': {ob.input_port, icomp, oa}, + 'no_specs': 'THIS IS IGNORED', + 'shadow_inputs_dict_spec': {pnl.SHADOW_INPUTS:[ia, oa, ob]}, # ia & ob OK because just for shadowing + 'shadow_inputs_dict_spec_w_none': {pnl.SHADOW_INPUTS:[ia, None, ob]}, + + # Illegal state_features specifications + 'misplaced_shadow': [ib.input_port], + 'ext_shadow': [ext.input_port], + 'ext_output_port': [ext.output_port], + 'input_format_wrong_shape': [ia.input_port, oa.output_port, oc.output_port], + 'too_many_inputs_warning': [ia.input_port, oa.output_port, ob.output_port, oc.output_port], + 'too_many_inputs_error': [ia.input_port, oa.output_port, ob.output_port, oc.output_port], + 'too_many_w_node_not_in_composition_warning': [ia, oa, ob, ext], + 'bad_single_spec': ext.input_port, + 'bad_single_numeric_spec': [3], + 'bad_dict_spec_warning': {oa:oc.input_port, ia:ia, oc:ob.output_port}, # oc is not an INPUT Node + 'bad_dict_spec_error': {oa:oc.input_port, ia:ia, oc:ob.output_port}, # ia & oc are not *ocomp* INPUT Nodes + 'bad_shadow_inputs_dict_spec_error': {pnl.SHADOW_INPUTS:[ia.output_port, None, ob]}, # not INPUT InputPort + 'comp_in_list_spec':[icomp, oa.output_port, [3,1,2]], # FIX: REMOVE ONCE TUPLE FORMAT SUPPORTED + 'comp_in_shadow_inupts_spec':{pnl.SHADOW_INPUTS:[icomp, oa, ob]} + } + objective_mechanism = [ic,ib] if obj_mech == 'obj_mech' else None + monitor_for_control = [ic] if obj_mech == 'mtr_for_ctl' else None # Needs to be a single item for GridSearch + state_features = state_features_dict[test_condition] + + ia_node = _state_input_port_name('OA[OutputPort-0]', 'IA[InputPort-0]') + oa_node = _state_input_port_name('OA[OutputPort-0]', 'OA[InputPort-0]') + ob_node = _state_input_port_name('OB[OutputPort-0]', 'OB[InputPort-0]') + numeric_ob = _numeric_state_input_port_name('OB[InputPort-0]') + shadowed_ia_node = _shadowed_state_input_port_name('IA[InputPort-0]', 'IA[InputPort-0]') + shadowed_oa_node = _shadowed_state_input_port_name('OA[InputPort-0]', 'OA[InputPort-0]') + shadowed_oa_oc = _shadowed_state_input_port_name('OC[InputPort-0]', 'OA[InputPort-0]') + shadowed_ob_node = _shadowed_state_input_port_name('OB[InputPort-0]', 'OB[InputPort-0]') + + if test_condition == 'no_specs': + ocm = pnl.OptimizationControlMechanism(objective_mechanism=objective_mechanism, + monitor_for_control=monitor_for_control, + function=pnl.GridSearch(), + control_signals=[pnl.ControlSignal(modulates=(pnl.SLOPE,ia), + allocation_samples=[10, 20, 30]), + pnl.ControlSignal(modulates=(pnl.INTERCEPT,oc), + allocation_samples=[10, 20, 30])]) + + else: + ocm = pnl.OptimizationControlMechanism(state_features=state_features, + state_feature_default=state_feature_default, + objective_mechanism=objective_mechanism, + monitor_for_control=monitor_for_control, + function=pnl.GridSearch(), + control_signals=[pnl.ControlSignal(modulates=(pnl.SLOPE,ia), + allocation_samples=[10, 20, 30]), + pnl.ControlSignal(modulates=(pnl.INTERCEPT,oc), + allocation_samples=[10, 20, 30])]) + if not exception_type: + + ocomp.add_controller(ocm) + ocomp.run() + + if test_condition == 'single_none_spec': + assert len(ocm.state_input_ports) == 0 + assert ocm.state_features == {'IA[InputPort-0]': None, + 'OA[InputPort-0]': None, + 'OB[InputPort-0]': None} + assert ocm.state_feature_values == {} + + if test_condition in {'single_shadow_spec', + 'set_spec', + 'set_spec_port', + 'shadow_inputs_dict_spec' + 'no_specs'}: + assert len(ocm.state_input_ports) == 3 + assert ocm.state_input_ports.names == [shadowed_ia_node, shadowed_oa_node, shadowed_ob_node] + assert ocm.state_features == {'IA[InputPort-0]': 'IA[InputPort-0]', + 'OA[InputPort-0]': 'OA[InputPort-0]', + 'OB[InputPort-0]': 'OB[InputPort-0]'} + assert {k:v.tolist() for k,v in ocm.state_feature_values.items()} == {ia.input_port: [0.], + oa.input_port: [0.], + ob.input_port: [0., 0., 0.]} + + if test_condition == 'single_tuple_shadow_spec': + assert ocm.state_input_ports.names == [shadowed_ia_node, shadowed_oa_node, shadowed_ob_node] + assert ocm.state_features == {'IA[InputPort-0]': 'IA[InputPort-0]', + 'OA[InputPort-0]': 'OA[InputPort-0]', + 'OB[InputPort-0]': 'OB[InputPort-0]'} + assert {k:v.tolist() for k,v in ocm.state_feature_values.items()} == {ia.input_port: [0.5], + oa.input_port: [0.5], + ob.input_port: [0.5, 0.5, 0.5]} + assert all('Logistic' in port.function.name for port in ocm.state_input_ports) + + if test_condition == 'full_list_spec': + assert len(ocm.state_input_ports) == 3 + assert ocm.state_input_ports.names == [shadowed_ia_node, oa_node, numeric_ob] + assert ocm.state_features == {'IA[InputPort-0]': 'IA[InputPort-0]', + 'OA[InputPort-0]': 'OA[OutputPort-0]', + 'OB[InputPort-0]': [3, 1, 2]} + assert {k:v.tolist() for k,v in ocm.state_feature_values.items()} == {ia.input_port: [0.0], + oa.input_port: [0.0], + ob.input_port: [3.0, 1.0, 2.0]} + + if test_condition == 'list_spec_with_none': + assert len(ocm.state_input_ports) == 2 + assert ocm.state_input_ports.names == [shadowed_ia_node, numeric_ob] + assert ocm.state_features == {'IA[InputPort-0]': 'IA[InputPort-0]', + 'OA[InputPort-0]': None, + 'OB[InputPort-0]': [3, 1, 2]} + assert all(np.allclose(expected, actual) + for expected, actual in zip(list(ocm.state_feature_values.values()), + [[0.], [3, 1, 2]])) + + elif test_condition in {'input_dict_spec', 'input_dict_spec_short'}: + assert len(ocm.state_input_ports) == 3 + assert ocm.state_input_ports.names == [shadowed_ia_node, shadowed_oa_oc, ob_node] + assert ocm.state_features == {'IA[InputPort-0]': 'IA[InputPort-0]', + 'OA[InputPort-0]': 'OC[InputPort-0]', + 'OB[InputPort-0]': 'OB[OutputPort-0]'} + assert all(np.allclose(expected, actual) + for expected, actual in zip(list(ocm.state_feature_values.values()), + [[0.], [0.], [0, 0, 0]])) + + elif test_condition == 'set_spec_short': + assert len(ocm.state_input_ports) == 1 + assert ocm.state_input_ports.names == [shadowed_oa_node] + # 'set_spec': {ob, icomp, oa}, # Note: out of order is OK + assert ocm.state_features == {'IA[InputPort-0]': None, + 'OA[InputPort-0]': 'OA[InputPort-0]', + 'OB[InputPort-0]': None} + assert all(np.allclose(expected, actual) + for expected, actual in zip(list(ocm.state_feature_values.values()), + [[0.], [0.], [0, 0, 0]])) + + elif test_condition == 'shadow_inputs_dict_spec_w_none': + assert len(ocm.state_input_ports) == 2 + assert ocm.state_input_ports.names == [shadowed_ia_node, shadowed_ob_node] + assert ocm.state_features == {'IA[InputPort-0]': 'IA[InputPort-0]', + 'OA[InputPort-0]': None, + 'OB[InputPort-0]': 'OB[InputPort-0]'} + assert all(np.allclose(expected, actual) + for expected, actual in zip(list(ocm.state_feature_values.values()), + [[0.], [0.], [0, 0, 0]])) + + elif exception_type is UserWarning: + # These also produce errors, tested below + if test_condition in {'too_many_inputs_warning', + 'too_many_w_node_not_in_composition_warning', + 'bad_dict_spec_warning'}: + with pytest.warns(UserWarning) as warning: + ocomp.add_controller(ocm) + assert error_or_warning_message in [warning[i].message.args[0] for i in range(len(warning))] + else: + with pytest.warns(UserWarning) as warning: + ocomp.add_controller(ocm) + ocomp.run() + if test_condition == 'partial_legal_list_spec': + assert len(ocm.state_input_ports) == 3 + assert ocm.state_input_ports.names == [ia_node, shadowed_oa_node, shadowed_ob_node] + # Note: oa is assigned to icomp due to ordering: + assert ocm.state_features == {'IA[InputPort-0]': 'OA[OutputPort-0]', + 'OA[InputPort-0]': 'OA[InputPort-0]', + 'OB[InputPort-0]': 'OB[InputPort-0]'} + assert all(np.allclose(expected, actual) + for expected, actual in zip(list(ocm.state_feature_values.values()), + [[0.], [0.], [0, 0, 0]])) + + assert error_or_warning_message in [warning[i].message.args[0] for i in range(len(warning))] + + else: + with pytest.raises(exception_type) as error: + ocomp.add_controller(ocm) + ocomp.run() + assert error_or_warning_message in str(error.value) + + state_features_arg = [ + 'single_numeric_spec', # <- same numeric input for all INPUT Node InputPorts + 'single_tuple_numeric_spec', # <- same value and function assigned to all INPUT Node InputPorts + 'single_port_spec', # <- same Port for all INPUT Node InputPorts + 'single_mech_spec', # <- same Mech's InputPort for INPUT Node InputPorts + 'nested_partial_list', # <- specify 1st 3 INPUT Node InputPorts; 4th (I2) should get shaddowed + 'nested_partial_set', # <- only 2 of 3 INPUT Nodes of nested Comp in set format; + 'nested_partial_dict', # <- only 2 of 3 INPUT Nodes of nested Comp in dict format + 'nested_full_set', # <- all 3 INPUT Nodes of nested Comp in set format + 'nested_full_dict', # <- both of 2 INPUT Nodes of nested Comp in dict format + 'nested_comp_set', # <- nested Comp as itself in set format + 'nested_comp_dict', # <- nested Comp as itself in dict format with a single spec for all INPUT Nodes + 'no_spec', # <- Assign state_feature_default to all Nodes + 'bad' # <- Mechanism not in agent_rep + ] + if len(state_feature_args) != 13: + print("\n\n**********************************************************************************************") + print("*** RESTORE state_feature_args IN test_state_features_in_nested_composition_as_agent_rep() *****") + print("***********************************************************************************************") + @pytest.mark.state_features + @pytest.mark.control + @pytest.mark.composition + @pytest.mark.parametrize('nested_agent_rep',[(False, 'OUTER COMP'),(True, 'MIDDLE COMP')], + ids=['unnested','nested']) + @pytest.mark.parametrize('state_features_arg', state_features_arg, + ids= [f"state_feature-{x}" for x in state_features_arg] + ) + def test_state_features_in_nested_composition_as_agent_rep(self, nested_agent_rep, state_features_arg): + """Test state_features for agent_rep that is a nested Composition and also has one nested with in. + Also test for single state_feature_spec and INPUT Node with multiple InputPorts, not tested in + test_ocm_state_feature_specs_and_warnings_and_errors() (see that for tests of basic state_features specs). + """ + + I1 = pnl.ProcessingMechanism(name='I1') + I2 = pnl.ProcessingMechanism(name='I2') + icomp = pnl.Composition(nodes=[I1,I2], name='INNER COMP') + A = pnl.ComparatorMechanism(name='A') + B = pnl.ProcessingMechanism(name='B') + C = pnl.ProcessingMechanism(name='C', size=3) + D = pnl.ProcessingMechanism(name='D') + mcomp = pnl.Composition(pathways=[[A,B,C], icomp], name='MIDDLE COMP') + ocomp = pnl.Composition(nodes=[mcomp], name='OUTER COMP') + + # Test args: + if nested_agent_rep is True: + agent_rep = mcomp + error_text = f"'OCM' has '{pnl.STATE_FEATURES}' specified (['D[OutputPort-0]']) that are missing from both " \ + f"its `agent_rep` ('{nested_agent_rep[1]}') as well as 'OUTER COMP' and any " \ + f"Compositions nested within it." + else: + agent_rep = None + error_text = f"'OCM' has '{pnl.STATE_FEATURES}' specified (['INPUT FROM D[OutputPort-0] FOR A[SAMPLE]']) " \ + f"that are missing from 'OUTER COMP' and any Compositions nested within it." + + state_features = { + 'single_numeric_spec': [3], + 'single_tuple_numeric_spec': ([3], pnl.Linear(slope=5)), + 'single_port_spec': I1.output_port, + 'single_mech_spec': I1, + 'nested_partial_list': [I1.output_port, [2], I2], + 'nested_partial_set': {A.input_ports[pnl.SAMPLE], I2}, + 'nested_full_set': {A, I1, I2}, + 'nested_partial_dict': {A.input_ports[pnl.SAMPLE]:[3.5], I2:I1.input_port}, + 'nested_full_dict': {A:A.input_port, I1:I2.input_port, I2:I1.input_port}, + 'nested_comp_set': {mcomp}, + 'nested_comp_dict': {mcomp: I1}, + 'no_spec': 'SHOULD SHADOW INPUT Node InputPorts', + 'bad': [D.output_port] + }[state_features_arg] + + if state_features_arg == 'nested_partial_set': + state_feature_default = None # Test assignment of SHADOW_INPUTS to specs in set, and None to others + else: + state_feature_default = pnl.SHADOW_INPUTS + + if state_features_arg == 'no_spec': + ocm = pnl.OptimizationControlMechanism(name='OCM', + agent_rep=agent_rep, + objective_mechanism=pnl.ObjectiveMechanism(monitor=[B]), + allow_probes=True, + function=pnl.GridSearch(), + control_signals=pnl.ControlSignal(modulates=(pnl.SLOPE,I1), + allocation_samples=[10, 20, 30])) + else: + ocm = pnl.OptimizationControlMechanism(name='OCM', + agent_rep=agent_rep, + state_features=state_features, + state_feature_default=state_feature_default, + objective_mechanism=pnl.ObjectiveMechanism(monitor=[B]), + allow_probes=True, + function=pnl.GridSearch(), + control_signals=pnl.ControlSignal(modulates=(pnl.SLOPE,I1), + allocation_samples=[10, 20, 30])) + if state_features_arg == 'bad': + with pytest.raises(pnl.OptimizationControlMechanismError) as error: + ocomp.add_controller(ocm) + ocomp.run() + assert error_text in str(error.value) + else: + ocomp.add_controller(ocm) + ocomp.run() + + if state_features_arg == 'single_numeric_spec': + assert ocm.state_features == {'A[SAMPLE]': [3], + 'A[TARGET]': [3], + 'I1[InputPort-0]': [3], + 'I2[InputPort-0]': [3]} + assert {k:v.tolist() for k,v in ocm.state_feature_values.items()} == {A.input_ports[pnl.SAMPLE]: [3], + A.input_ports[pnl.TARGET]: [3], + I1.input_port: [3], + I2.input_port: [3]} + elif state_features_arg == 'single_tuple_numeric_spec': + assert ocm.state_features == {'A[SAMPLE]': [3], + 'A[TARGET]': [3], + 'I1[InputPort-0]': [3], + 'I2[InputPort-0]': [3]} + assert {k:v.tolist() for k,v in ocm.state_feature_values.items()} == {A.input_ports[pnl.SAMPLE]: [15], + A.input_ports[pnl.TARGET]: [15], + I1.input_port: [15], + I2.input_port: [15]} + elif state_features_arg in {'single_port_spec'}: + assert ocm.state_features == {'A[SAMPLE]': 'I1[OutputPort-0]', + 'A[TARGET]': 'I1[OutputPort-0]', + 'I1[InputPort-0]': 'I1[OutputPort-0]', + 'I2[InputPort-0]': 'I1[OutputPort-0]'} + assert {k:v.tolist() for k,v in ocm.state_feature_values.items()} == {A.input_ports[pnl.SAMPLE]: [0], + A.input_ports[pnl.TARGET]: [0], + I1.input_port: [0], + I2.input_port: [0]} + elif state_features_arg in {'single_mech_spec'}: + assert ocm.state_features == {'A[SAMPLE]': 'I1[InputPort-0]', + 'A[TARGET]': 'I1[InputPort-0]', + 'I1[InputPort-0]': 'I1[InputPort-0]', + 'I2[InputPort-0]': 'I1[InputPort-0]'} + assert {k:v.tolist() for k,v in ocm.state_feature_values.items()} == {A.input_ports[pnl.SAMPLE]: [0], + A.input_ports[pnl.TARGET]: [0], + I1.input_port: [0], + I2.input_port: [0]} + elif state_features_arg in 'nested_partial_list': + assert ocm.state_features == {'A[SAMPLE]': 'I1[OutputPort-0]', + 'A[TARGET]': [2], + 'I1[InputPort-0]': 'I2[InputPort-0]', + 'I2[InputPort-0]': 'I2[InputPort-0]'} + assert {k:v.tolist() for k,v in ocm.state_feature_values.items()} == {A.input_ports[pnl.SAMPLE]: [0], + A.input_ports[pnl.TARGET]: [2], + I1.input_port: [0], + I2.input_port: [0]} + elif state_features_arg in 'nested_partial_set': + assert ocm.state_features == {'A[SAMPLE]': 'A[SAMPLE]', + 'A[TARGET]': None, + 'I1[InputPort-0]': None, + 'I2[InputPort-0]': 'I2[InputPort-0]'} + assert {k:v.tolist() for k,v in ocm.state_feature_values.items()} == {A.input_ports[pnl.SAMPLE]: [0], + I2.input_port: [0]} + + elif state_features_arg == 'nested_partial_dict': + assert ocm.state_features == {'A[SAMPLE]': [3.5], + 'A[TARGET]': 'A[TARGET]', + 'I1[InputPort-0]': 'I1[InputPort-0]', + 'I2[InputPort-0]': 'I1[InputPort-0]'} + assert {k:v.tolist() for k,v in ocm.state_feature_values.items()} == {A.input_ports[pnl.SAMPLE]: [3.5], + A.input_ports[pnl.TARGET]: [0], + I1.input_port: [0], + I2.input_port: [0]} + elif state_features_arg in {'nested_full_set', 'nested_comp_set', 'no_spec'}: + assert ocm.state_features == {'A[SAMPLE]': 'A[SAMPLE]', + 'A[TARGET]': 'A[TARGET]', + 'I1[InputPort-0]': 'I1[InputPort-0]', + 'I2[InputPort-0]': 'I2[InputPort-0]'} + assert {k:v.tolist() for k,v in ocm.state_feature_values.items()} == {A.input_ports[pnl.SAMPLE]: [0], + A.input_ports[pnl.TARGET]: [0], + I1.input_port: [0], + I2.input_port: [0]} + elif state_features_arg == 'nested_full_dict': + assert ocm.state_features == {'A[SAMPLE]': 'A[SAMPLE]', + 'A[TARGET]': 'A[SAMPLE]', + 'I1[InputPort-0]': 'I2[InputPort-0]', + 'I2[InputPort-0]': 'I1[InputPort-0]'} + assert {k:v.tolist() for k,v in ocm.state_feature_values.items()} == {A.input_ports[0]: [0], + A.input_ports[1]: [0], + I1.input_port: [0], + I2.input_port: [0]} + elif state_features_arg == 'nested_comp_dict': + assert ocm.state_features == {'A[SAMPLE]': 'I1[InputPort-0]', + 'A[TARGET]': 'I1[InputPort-0]', + 'I1[InputPort-0]': 'I1[InputPort-0]', + 'I2[InputPort-0]': 'I1[InputPort-0]'} + assert {k:v.tolist() for k,v in ocm.state_feature_values.items()} == {A.input_ports[pnl.SAMPLE]: [0], + A.input_ports[pnl.TARGET]: [0], + I1.input_port: [0], + I2.input_port: [0]} + + @pytest.mark.state_features + @pytest.mark.control + @pytest.mark.parametrize('state_fct_assignments', [ + 'partial_w_dict', + 'partial_w_params_dict', + 'tuple_override_dict', + 'tuple_override_params_dict', + 'port_spec_dict_in_feat_dict', + 'all', + None + ]) + def test_state_feature_function_specs(self, state_fct_assignments): + """Test assignment of state_feature_functions in various configurations + Also test use of InputPort specification dictionary as state_feature_specification""" + + fct_a = pnl.AdaptiveIntegrator + fct_b = pnl.Buffer(history=2) + fct_c = pnl.SimpleIntegrator + A = pnl.ProcessingMechanism(name='A') + B = pnl.ProcessingMechanism(name='B') + C = pnl.ProcessingMechanism(name='C') + R = pnl.ProcessingMechanism(name='D') + + if state_fct_assignments == 'partial_w_dict': + state_features = [{pnl.PROJECTIONS: A, # Note: specification of A in dict is still interpreted as shadowing + pnl.FUNCTION: fct_a}, + (B, fct_b), + C] + state_feature_function = fct_c + elif state_fct_assignments == 'partial_w_params_dict': + state_features = [{pnl.PARAMS: {pnl.PROJECTIONS: A, + pnl.FUNCTION: fct_a}}, + (B, fct_b), + C] + state_feature_function = fct_c + elif state_fct_assignments == 'tuple_override_dict': + state_features = [({pnl.PROJECTIONS: A, + pnl.FUNCTION: pnl.Buffer}, + fct_a), + (B, fct_b), + C] + state_feature_function = fct_c + elif state_fct_assignments == 'tuple_override_params_dict': + state_features = [({pnl.PARAMS: {pnl.PROJECTIONS: A, + pnl.FUNCTION: pnl.Buffer}}, fct_a), + (B, fct_b), + C] + state_feature_function = fct_c + elif state_fct_assignments == 'port_spec_dict_in_feat_dict': + state_features = {A:{pnl.PROJECTIONS: A, + pnl.FUNCTION: fct_a}, + B: ({pnl.PROJECTIONS: B}, fct_b), + C: C} + state_feature_function = fct_c + elif state_fct_assignments == 'all': + state_features = [(A, fct_a), (B, fct_b), (C, fct_c)] + state_feature_function = None + else: + state_features = [A, B, C] + state_feature_function = None + + comp = pnl.Composition(name='comp', pathways=[[A,R],[B,R],[C,R]]) + ocm = pnl.OptimizationControlMechanism(state_features=state_features, + state_feature_function=state_feature_function, + function=pnl.GridSearch(), + # monitor_for_control=A, + control_signals=[pnl.ControlSignal(modulates=(pnl.SLOPE, A), + allocation_samples=[10, 20, 30])]) + comp.add_controller(ocm) + if state_fct_assignments: + assert isinstance(ocm.state_input_ports[0].function, fct_a) + assert isinstance(ocm.state_input_ports[1].function, fct_b.__class__) + assert isinstance(ocm.state_input_ports[2].function, fct_c) + inputs = {A:[1,2], B:[1,2], C:[1,2]} + result = comp.run(inputs=inputs, context='test') + assert result == [[24.]] + assert all(np.allclose(actual, expected) + for actual, expected in zip(list(ocm.parameters.state_feature_values.get('test').values()), + [[2],[[1],[2]],[3]])) + else: + assert isinstance(ocm.state_input_ports[0].function, pnl.LinearCombination) + assert isinstance(ocm.state_input_ports[1].function, pnl.LinearCombination) + assert isinstance(ocm.state_input_ports[2].function, pnl.LinearCombination) + inputs = {A:[1,2], B:[1,2], C:[1,2]} + result = comp.run(inputs=inputs, context='test') + assert result == [[24.]] + assert all(np.allclose(expected, actual) + for actual, expected in zip(list(ocm.parameters.state_feature_values.get('test').values()), + [[2],[2],[2]])) + + @pytest.mark.state_features + @pytest.mark.control + def test_ocm_state_and_state_dict(self): + ia = pnl.ProcessingMechanism(name='IA') + ib = pnl.ProcessingMechanism(name='IB') + ic = pnl.ProcessingMechanism(name='IC') + oa = pnl.ProcessingMechanism(name='OA') + ob = pnl.ProcessingMechanism(name='OB', size=3) + oc = pnl.ProcessingMechanism(name='OC') + icomp = pnl.Composition(pathways=[ia,ib,ic], name='INNER COMP') + ocomp = pnl.Composition(pathways=[icomp], name='OUTER COMP') + ocomp.add_linear_processing_pathway([oa,oc]) + ocomp.add_linear_processing_pathway([ob,oc]) + ocm = pnl.OptimizationControlMechanism( + state_features=[ia.input_port, + oa.output_port, + [3,1,2]], # <- ob + objective_mechanism=[ic,ib], + function=pnl.GridSearch(), + allow_probes=True, + control_signals=[pnl.ControlSignal(modulates=(pnl.SLOPE,ia), + allocation_samples=[10, 20, 30]), + pnl.ControlSignal(modulates=[(pnl.INTERCEPT,oc),(pnl.SLOPE, oc)], + allocation_samples=[10, 20, 30]), + ] + ) + ocomp.add_controller(ocm) + assert all(np.allclose(x,y) for x,y in zip(ocm.state, [[0.0], [0.0], [3.0, 1.0, 2.0], [1.0], [1.0]])) + assert len(ocm.state_distal_sources_and_destinations_dict) == 6 + keys = list(ocm.state_distal_sources_and_destinations_dict.keys()) + values = list(ocm.state_distal_sources_and_destinations_dict.values()) + for key, value in ocm.state_distal_sources_and_destinations_dict.items(): + ocm.state[key[3]] == value + assert keys[0] == (ia.input_port, ia, icomp ,0) + assert keys[1] == (oa.output_port, oa, ocomp, 1) + assert keys[2] == ('default_variable', None, None, 2) + assert keys[3] == (ia.parameter_ports[pnl.SLOPE], ia, icomp, 3) + assert keys[4] == (oc.parameter_ports[pnl.INTERCEPT], oc, ocomp, 4) + assert keys[5] == (oc.parameter_ports[pnl.SLOPE], oc, ocomp, 4) + ocomp.run() + assert all(np.allclose(expected, actual) + for expected, actual in zip(list(ocm.state_feature_values.values()), + [[0.], [0.], [3, 1, 2]])) + def test_modulation_of_control_signal_intensity_cost_function_MULTIPLICATIVE(self): # tests multiplicative modulation of default intensity_cost_function (Exponential) of # a ControlMechanism's default function (TransferWithCosts); @@ -746,9 +1798,9 @@ def test_lvoc(self): monitor=[m1, m2]), function=pnl.GridSearch(max_iterations=1), control_signals=[ - {PROJECTIONS: (pnl.SLOPE, m1), + {CONTROL: (pnl.SLOPE, m1), ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3)}, - {PROJECTIONS: (pnl.SLOPE, m2), + {CONTROL: (pnl.SLOPE, m2), ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3)}]) c.add_node(lvoc) input_dict = {m1: [[1], [1]], m2: [1]} @@ -770,9 +1822,9 @@ def test_lvoc_both_predictors_specs(self): monitor=[m1, m2]), function=pnl.GridSearch(max_iterations=1), control_signals=[ - {PROJECTIONS: (pnl.SLOPE, m1), + {CONTROL: (pnl.SLOPE, m1), ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3)}, - {PROJECTIONS: (pnl.SLOPE, m2), + {CONTROL: (pnl.SLOPE, m2), ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3)}]) c.add_node(lvoc) input_dict = {m1: [[1], [1]], m2: [1]} @@ -790,7 +1842,7 @@ def test_lvoc_features_function(self): c._analyze_graph() lvoc = pnl.OptimizationControlMechanism(agent_rep=pnl.RegressionCFA, state_features=[m1.input_ports[0], m1.input_ports[1], m2.input_port, m2], - state_feature_functions=pnl.LinearCombination(offset=10.0), + state_feature_function=pnl.LinearCombination(offset=10.0), objective_mechanism=pnl.ObjectiveMechanism( monitor=[m1, m2]), function=pnl.GradientOptimization(max_iterations=1), @@ -832,7 +1884,7 @@ def test_multilevel_ocm_gridsearch_conflicting_directions(self, mode, benchmark) pnl.OptimizationControlMechanism( agent_rep=ocomp, state_features=[oa.input_port], - # state_feature_functions=pnl.Buffer(history=2), + # state_feature_function=pnl.Buffer(history=2), name="Controller", objective_mechanism=pnl.ObjectiveMechanism( monitor=ib.output_port, @@ -849,7 +1901,7 @@ def test_multilevel_ocm_gridsearch_conflicting_directions(self, mode, benchmark) pnl.OptimizationControlMechanism( agent_rep=icomp, state_features=[ia.input_port], - # state_feature_functions=pnl.Buffer(history=2), + # state_feature_function=pnl.Buffer(history=2), name="Controller", objective_mechanism=pnl.ObjectiveMechanism( monitor=ib.output_port, @@ -895,7 +1947,7 @@ def test_multilevel_ocm_gridsearch_maximize(self, mode, benchmark): pnl.OptimizationControlMechanism( agent_rep=ocomp, state_features=[oa.input_port], - # state_feature_functions=pnl.Buffer(history=2), + # state_feature_function=pnl.Buffer(history=2), name="Controller", objective_mechanism=pnl.ObjectiveMechanism( monitor=ib.output_port, @@ -914,7 +1966,7 @@ def test_multilevel_ocm_gridsearch_maximize(self, mode, benchmark): pnl.OptimizationControlMechanism( agent_rep=icomp, state_features=[ia.input_port], - # state_feature_functions=pnl.Buffer(history=2), + # state_feature_function=pnl.Buffer(history=2), name="Controller", objective_mechanism=pnl.ObjectiveMechanism( monitor=ib.output_port, @@ -962,7 +2014,7 @@ def test_multilevel_ocm_gridsearch_minimize(self, mode, benchmark): pnl.OptimizationControlMechanism( agent_rep=ocomp, state_features=[oa.input_port], - # state_feature_functions=pnl.Buffer(history=2), + # state_feature_function=pnl.Buffer(history=2), name="oController", objective_mechanism=pnl.ObjectiveMechanism( monitor=ib.output_port, @@ -981,7 +2033,7 @@ def test_multilevel_ocm_gridsearch_minimize(self, mode, benchmark): pnl.OptimizationControlMechanism( agent_rep=icomp, state_features=[ia.input_port], - # state_feature_functions=pnl.Buffer(history=2), + # state_feature_function=pnl.Buffer(history=2), name="iController", objective_mechanism=pnl.ObjectiveMechanism( monitor=ib.output_port, @@ -1005,7 +2057,7 @@ def test_multilevel_ocm_gridsearch_minimize(self, mode, benchmark): def test_two_tier_ocm(self): integrationConstant = 0.8 # Time Constant DRIFT = 0.25 # Drift Rate - STARTING_POINT = 0.0 # Starting Point + STARTING_VALUE = 0.0 # Starting Point THRESHOLD = 0.05 # Threshold NOISE = 0.1 # Noise T0 = 0.2 # T0 @@ -1060,10 +2112,10 @@ def test_two_tier_ocm(self): name="Drift = Wa*(S1 + S2) + (S1*Act1 + S2*Act2)") decisionMaker = pnl.DDM(function=pnl.DriftDiffusionAnalytical(drift_rate=DRIFT, - starting_point=STARTING_POINT, + starting_value=STARTING_VALUE, threshold=THRESHOLD, noise=NOISE, - t0=T0), + non_decision_time=T0), output_ports=[pnl.DECISION_VARIABLE, pnl.RESPONSE_TIME, pnl.PROBABILITY_UPPER_THRESHOLD, pnl.PROBABILITY_LOWER_THRESHOLD], @@ -1120,7 +2172,6 @@ def test_two_tier_ocm(self): pnl.OptimizationControlMechanism(agent_rep=stabilityFlexibility, state_features=[taskLayer.input_port, stimulusInfo.input_port], - state_feature_functions=pnl.Buffer(history=2), name="Controller", objective_mechanism=pnl.ObjectiveMechanism( monitor=[(pnl.PROBABILITY_UPPER_THRESHOLD, @@ -1146,7 +2197,6 @@ def test_two_tier_ocm(self): outerComposition.add_controller( pnl.OptimizationControlMechanism(agent_rep=stabilityFlexibility, state_features=[taskLayer.input_port, stimulusInfo.input_port], - state_feature_functions=pnl.Buffer(history=2), name="OuterController", objective_mechanism=pnl.ObjectiveMechanism( monitor=[(pnl.PROBABILITY_UPPER_THRESHOLD, decisionMaker)], @@ -1270,18 +2320,82 @@ def test_recurrent_control(self, comp_mode): @pytest.mark.control @pytest.mark.composition - def test_control_of_mech_port(self, comp_mode): + @pytest.mark.parametrize("modulation, expected", [ + (pnl.OVERRIDE, 0.375), + (pnl.DISABLE, 0.4375), + (pnl.MULTIPLICATIVE, 0.484375), + (pnl.ADDITIVE, 0.25), + ]) + def test_control_of_mech_port(self, comp_mode, modulation, expected): mech = pnl.TransferMechanism(termination_threshold=0.1, execute_until_finished=True, integrator_mode=True) control_mech = pnl.ControlMechanism( - control_signals=pnl.ControlSignal(modulation=pnl.OVERRIDE, + control_signals=pnl.ControlSignal(modulation=modulation, modulates=(pnl.TERMINATION_THRESHOLD, mech))) comp = pnl.Composition() comp.add_nodes([(mech, pnl.NodeRole.INPUT), (control_mech, pnl.NodeRole.INPUT)]) inputs = {mech:[[0.5]], control_mech:[0.2]} results = comp.run(inputs=inputs, num_trials=1, execution_mode=comp_mode) - assert np.allclose(comp.results, [[[0.375]]]) + assert np.allclose(results, expected) + + @pytest.mark.control + @pytest.mark.composition + @pytest.mark.parametrize("modulation, expected", [ + (pnl.OVERRIDE, 0.2), + (pnl.DISABLE, 0.5), + (pnl.MULTIPLICATIVE, 0.1), + (pnl.ADDITIVE, 0.7), + ]) + def test_control_of_mech_input_port(self, comp_mode, modulation, expected): + mech = pnl.TransferMechanism() + control_mech = pnl.ControlMechanism( + control_signals=pnl.ControlSignal(modulation=modulation, + modulates=mech.input_port)) + comp = pnl.Composition() + comp.add_nodes([(mech, pnl.NodeRole.INPUT), (control_mech, pnl.NodeRole.INPUT)]) + inputs = {mech:[[0.5]], control_mech:[0.2]} + results = comp.run(inputs=inputs, num_trials=1, execution_mode=comp_mode) + assert np.allclose(results, expected) + + @pytest.mark.control + @pytest.mark.composition + @pytest.mark.parametrize("modulation, expected", [ + (pnl.OVERRIDE, 0.2), + (pnl.DISABLE, 0.5), + (pnl.MULTIPLICATIVE, 0.1), + (pnl.ADDITIVE, 0.7), + ]) + @pytest.mark.parametrize("specification", [ pnl.OWNER_VALUE, (pnl.OWNER_VALUE, 0)]) + def test_control_of_mech_output_port(self, comp_mode, modulation, expected, specification): + mech = pnl.TransferMechanism(output_ports=[pnl.OutputPort(variable=specification)]) + control_mech = pnl.ControlMechanism( + control_signals=pnl.ControlSignal(modulation=modulation, + modulates=mech.output_port)) + comp = pnl.Composition() + comp.add_nodes([(mech, pnl.NodeRole.INPUT), (control_mech, pnl.NodeRole.INPUT)]) + inputs = {mech:[[0.5]], control_mech:[0.2]} + results = comp.run(inputs=inputs, num_trials=1, execution_mode=comp_mode) + assert np.allclose(results, expected) + + @pytest.mark.control + @pytest.mark.composition + def test_add_node_with_controller_spec_and_control_mech_but_not_a_controller(self): + mech = pnl.ProcessingMechanism(name='MECH', function=pnl.Linear(slope=(2, pnl.CONTROL))) + ctl = pnl.ControlMechanism(name='CONTROL MECHANISM') + warning_msg_1 = '"OutputPort (\'ControlSignal-0\') of \'CONTROL MECHANISM\' doesn\'t have any efferent ' \ + 'Projections in \'COMPOSITION\'."' + warning_msg_2 = '"The \'slope\' parameter of \'MECH\' is specified for control, but the Composition it is in ' \ + '(\'COMPOSITION\') does not have a controller; if a controller is not added to COMPOSITION ' \ + 'the control specification will be ignored."' + warning_msg_3 = '"\\nThe following Projections were specified but are not being used by Nodes in ' \ + '\'COMPOSITION\':\\n\\tControlProjection for MECH[slope]"' + with pytest.warns(UserWarning) as warning: + comp = pnl.Composition(name='COMPOSITION', pathways=[ctl]) + comp.add_node(mech) + comp.run() + assert all(msg in [repr(w.message.args[0]) for w in warning] + for msg in {warning_msg_1, warning_msg_2, warning_msg_3}) @pytest.mark.control @pytest.mark.composition @@ -1316,14 +2430,18 @@ def test_modulation_simple(self, cost, expected, exp_values, comp_mode): modulation=pnl.OVERRIDE, allocation_samples=pnl.SampleSpec(start=1, stop=5, step=1), cost_options=cost, - ) + ), + + # Need to specify GridSearch since save_values is False by default and we + # going to check these values later in the test. + function=pnl.GridSearch(save_values=True) ) ) ret = comp.run(inputs={mech: [2]}, num_trials=1, execution_mode=comp_mode) assert np.allclose(ret, expected) if comp_mode == pnl.ExecutionMode.Python: - assert np.allclose([float(x) for x in comp.controller.function.saved_values], exp_values) + assert np.allclose(comp.controller.function.saved_values.flatten(), exp_values) @pytest.mark.benchmark @pytest.mark.control @@ -1361,7 +2479,7 @@ def test_modulation_of_random_state_direct(self, comp_mode, benchmark, prng): @pytest.mark.parametrize('prng', ['Default', 'Philox']) def test_modulation_of_random_state_DDM(self, comp_mode, benchmark, prng): # set explicit seed to make sure modulation is different - mech = pnl.DDM(function=pnl.DriftDiffusionIntegrator(noise=5.), + mech = pnl.DDM(function=pnl.DriftDiffusionIntegrator(noise=np.sqrt(5.0)), reset_stateful_function_when=pnl.AtPass(0), execute_until_finished=True) if prng == 'Philox': @@ -1372,7 +2490,9 @@ def test_modulation_of_random_state_DDM(self, comp_mode, benchmark, prng): comp.add_node(mech, required_roles=pnl.NodeRole.INPUT) comp.add_node(ctl_mech) + # Seeds are chosen to show difference in results below. seeds = [13, 13, 14] + # cycle over the seeds twice setting and resetting the random state benchmark(comp.run, inputs={ctl_mech:seeds, mech:5.0}, num_trials=len(seeds) * 2, execution_mode=comp_mode) @@ -1381,6 +2501,35 @@ def test_modulation_of_random_state_DDM(self, comp_mode, benchmark, prng): elif prng == 'Philox': assert np.allclose(np.squeeze(comp.results[:len(seeds) * 2]), [[100, 19], [100, 21], [100, 21]] * 2) + @pytest.mark.benchmark + @pytest.mark.control + @pytest.mark.composition + # 'LLVM' mode is not supported, because synchronization of compiler and + # python values during execution is not implemented. + @pytest.mark.usefixtures("comp_mode_no_llvm") + @pytest.mark.parametrize('prng', ['Default', 'Philox']) + def test_modulation_of_random_state_DDM_Analytical(self, comp_mode, benchmark, prng): + # set explicit seed to make sure modulation is different + mech = pnl.DDM(function=pnl.DriftDiffusionAnalytical()) + if prng == 'Philox': + mech.parameters.random_state.set(_SeededPhilox([0])) + ctl_mech = pnl.ControlMechanism(control_signals=pnl.ControlSignal(modulates=('seed', mech), + modulation=pnl.OVERRIDE)) + comp = pnl.Composition() + comp.add_node(mech, required_roles=pnl.NodeRole.INPUT) + comp.add_node(ctl_mech) + + # Seeds are chosen to show difference in results below. + seeds = [3, 3, 4] + + # cycle over the seeds twice setting and resetting the random state + benchmark(comp.run, inputs={ctl_mech:seeds, mech:0.1}, num_trials=len(seeds) * 2, execution_mode=comp_mode) + + if prng == 'Default': + assert np.allclose(np.squeeze(comp.results[:len(seeds) * 2]), [[-1, 3.99948962], [1, 3.99948962], [-1, 3.99948962]] * 2) + elif prng == 'Philox': + assert np.allclose(np.squeeze(comp.results[:len(seeds) * 2]), [[-1, 3.99948962], [-1, 3.99948962], [1, 3.99948962]] * 2) + @pytest.mark.control @pytest.mark.composition @pytest.mark.parametrize("num_generators", [5]) @@ -1436,6 +2585,7 @@ def test_modulation_of_random_state(self, comp_mode, num_generators): assert np.allclose(best_second, comp.results[1]) +@pytest.mark.control class TestModelBasedOptimizationControlMechanisms_Execution: def test_ocm_default_function(self): a = pnl.ProcessingMechanism() @@ -1533,8 +2683,8 @@ def test_evc(self): pnl.ControlProjection(function=pnl.Linear, control_signal_params={pnl.ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3)})), noise=0.5, - starting_point=0, - t0=0.45), + starting_value=0, + non_decision_time=0.45), output_ports=[pnl.DECISION_VARIABLE, pnl.RESPONSE_TIME, pnl.PROBABILITY_UPPER_THRESHOLD], @@ -1548,17 +2698,17 @@ def test_evc(self): comp.add_controller(controller=pnl.OptimizationControlMechanism( agent_rep=comp, - state_features=[Input.input_port, reward.input_port], - state_feature_functions=pnl.AdaptiveIntegrator(rate=0.5), + state_features=[reward.input_port, Input.input_port], + state_feature_function=pnl.AdaptiveIntegrator(rate=0.5), objective_mechanism=pnl.ObjectiveMechanism( function=pnl.LinearCombination(operation=pnl.PRODUCT), monitor=[reward, Decision.output_ports[pnl.PROBABILITY_UPPER_THRESHOLD], (Decision.output_ports[pnl.RESPONSE_TIME], -1, 1)]), function=pnl.GridSearch(), - control_signals=[{PROJECTIONS: ("drift_rate", Decision), + control_signals=[{CONTROL: ("drift_rate", Decision), ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3)}, - {PROJECTIONS: ("threshold", Decision), + {CONTROL: ("threshold", Decision), ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3)}]) ) @@ -1641,8 +2791,8 @@ def test_evc_gratton(self): function=pnl.DriftDiffusionAnalytical(drift_rate=(1.0), threshold=(0.2645), noise=(0.5), - starting_point=(0), - t0=0.15), + starting_value=(0), + non_decision_time=0.15), output_ports=[pnl.DECISION_VARIABLE, pnl.RESPONSE_TIME, pnl.PROBABILITY_UPPER_THRESHOLD] @@ -1688,7 +2838,7 @@ def test_evc_gratton(self): state_features=[target_stim.input_port, flanker_stim.input_port, reward.input_port], - state_feature_functions=pnl.AdaptiveIntegrator( + state_feature_function=pnl.AdaptiveIntegrator( rate=1.0), objective_mechanism=objective_mech, function=pnl.GridSearch(), @@ -1812,8 +2962,8 @@ def test_laming_validation_specify_control_signals(self): drift_rate=1.0, threshold=1.0, noise=0.5, - starting_point=0, - t0=0.45 + starting_value=0, + non_decision_time=0.45 ), output_ports=[ pnl.DECISION_VARIABLE, @@ -1832,8 +2982,8 @@ def test_laming_validation_specify_control_signals(self): comp.add_controller( controller=pnl.OptimizationControlMechanism( agent_rep=comp, - state_features=[Input.input_port, reward.input_port], - state_feature_functions=pnl.AdaptiveIntegrator(rate=0.5), + state_features=[reward.input_port, Input.input_port], + state_feature_function=pnl.AdaptiveIntegrator(rate=0.5), objective_mechanism=pnl.ObjectiveMechanism( function=pnl.LinearCombination(operation=pnl.PRODUCT), monitor=[ @@ -1845,11 +2995,11 @@ def test_laming_validation_specify_control_signals(self): function=pnl.GridSearch(), control_signals=[ { - PROJECTIONS: (pnl.DRIFT_RATE, Decision), + CONTROL: (pnl.DRIFT_RATE, Decision), ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3) }, { - PROJECTIONS: (pnl.THRESHOLD, Decision), + CONTROL: (pnl.THRESHOLD, Decision), ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3) } ], @@ -1950,8 +3100,8 @@ def test_stateful_mechanism_in_simulation(self): ), ), noise=(0.5), - starting_point=(0), - t0=0.45 + starting_value=(0), + non_decision_time=0.45 ), output_ports=[ pnl.DECISION_VARIABLE, @@ -1970,8 +3120,8 @@ def test_stateful_mechanism_in_simulation(self): comp.add_controller( controller=pnl.OptimizationControlMechanism( agent_rep=comp, - state_features=[Input.input_port, reward.input_port], - state_feature_functions=pnl.AdaptiveIntegrator(rate=0.5), + state_features=[reward.input_port, Input.input_port], + state_feature_function=pnl.AdaptiveIntegrator(rate=0.5), objective_mechanism=pnl.ObjectiveMechanism( function=pnl.LinearCombination(operation=pnl.PRODUCT), monitor=[ @@ -1983,11 +3133,11 @@ def test_stateful_mechanism_in_simulation(self): function=pnl.GridSearch(), control_signals=[ { - PROJECTIONS: (pnl.DRIFT_RATE, Decision), + CONTROL: (pnl.DRIFT_RATE, Decision), ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3) }, { - PROJECTIONS: (pnl.THRESHOLD, Decision), + CONTROL: (pnl.THRESHOLD, Decision), ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3) } ], @@ -2091,7 +3241,7 @@ def test_model_based_ocm_after(self, benchmark, mode): ocm = pnl.OptimizationControlMechanism(agent_rep=comp, state_features=[A.input_port], objective_mechanism=objective_mech, - function=pnl.GridSearch(), + function=pnl.GridSearch(save_values=True), control_signals=[control_signal], comp_execution_mode=ocm_mode) # objective_mech.log.set_log_conditions(pnl.OUTCOME) @@ -2142,7 +3292,7 @@ def test_model_based_ocm_before(self, benchmark, mode): ocm = pnl.OptimizationControlMechanism(agent_rep=comp, state_features=[A.input_port], objective_mechanism=objective_mech, - function=pnl.GridSearch(), + function=pnl.GridSearch(save_values=True), control_signals=[control_signal], comp_execution_mode=ocm_mode) # objective_mech.log.set_log_conditions(pnl.OUTCOME) @@ -2181,7 +3331,7 @@ def test_model_based_ocm_with_buffer(self): objective_mech = pnl.ObjectiveMechanism(monitor=[B]) ocm = pnl.OptimizationControlMechanism(agent_rep=comp, state_features=[A.input_port], - state_feature_functions=pnl.Buffer(history=2), + state_feature_function=pnl.Buffer(history=2), objective_mechanism=objective_mech, function=pnl.GridSearch(), control_signals=[control_signal]) @@ -2271,7 +3421,7 @@ def computeAccuracy(trialInformation): # Constants as defined in Musslick et al. 2018 tau = 0.9 # Time Constant DRIFT = 1 # Drift Rate - STARTING_POINT = 0.0 # Starting Point + STARTING_VALUE = 0.0 # Starting Point THRESHOLD = 0.0475 # Threshold NOISE = 0.04 # Noise T0 = 0.2 # T0 @@ -2321,10 +3471,10 @@ def computeAccuracy(trialInformation): name="Drift = (S1 + S2) + (S1*Activity1 + S2*Activity2)") decisionMaker = pnl.DDM(function=pnl.DriftDiffusionAnalytical(drift_rate=DRIFT, - starting_point=STARTING_POINT, + starting_value=STARTING_VALUE, threshold=THRESHOLD, noise=NOISE, - t0=T0), + non_decision_time=T0), output_ports=[pnl.DECISION_VARIABLE, pnl.RESPONSE_TIME, pnl.PROBABILITY_UPPER_THRESHOLD, pnl.PROBABILITY_LOWER_THRESHOLD], @@ -2381,7 +3531,7 @@ def computeAccuracy(trialInformation): # Sets trial history for simulations over specified signal search parameters metaController = pnl.OptimizationControlMechanism(agent_rep=stabilityFlexibility, state_features=[taskLayer.input_port, stimulusInfo.input_port], - state_feature_functions=pnl.Buffer(history=10), + state_feature_function=pnl.Buffer(history=10), name="Controller", objective_mechanism=objectiveMechanism, function=pnl.GridSearch(), @@ -2399,13 +3549,23 @@ def computeAccuracy(trialInformation): inputs = {taskLayer: taskTrain, stimulusInfo: stimulusTrain} stabilityFlexibility.run(inputs) + assert np.allclose(stabilityFlexibility.results, + [[[0.0475], [0.33695222], [1.], [1.13867062e-09]], + [[0.0475], [1.13635091], [0.93038951], [0.06961049]], + [[0.0475], [0.35801411], [0.99999998], [1.77215519e-08]], + [[0.0475], [0.89706881], [0.97981972], [0.02018028]]]) - @pytest.mark.parametrize('num_estimates',[None, 1] ) - def test_model_based_num_estimates(self, num_estimates): + @pytest.mark.parametrize('num_estimates',[None, 1, 2] ) + @pytest.mark.parametrize('rand_var',[False, True] ) + def test_model_based_num_estimates(self, num_estimates, rand_var): A = pnl.ProcessingMechanism(name='A') - B = pnl.ProcessingMechanism(name='B', - function=pnl.SimpleIntegrator(rate=1)) + if rand_var: + B = pnl.DDM(name='B', + function=pnl.DriftDiffusionAnalytical) + else: + B = pnl.ProcessingMechanism(name='B', + function=pnl.SimpleIntegrator(rate=1)) comp = pnl.Composition(name='comp') comp.add_linear_processing_pathway([A, B]) @@ -2417,28 +3577,44 @@ def test_model_based_num_estimates(self, num_estimates): intensity_cost_function=pnl.Linear(slope=0.)) objective_mech = pnl.ObjectiveMechanism(monitor=[B]) - ocm = pnl.OptimizationControlMechanism(agent_rep=comp, - state_features=[A.input_port], - objective_mechanism=objective_mech, - function=pnl.GridSearch(), - num_estimates=num_estimates, - control_signals=[control_signal]) + warning_type = None + if num_estimates and not rand_var: + warning_type = UserWarning + warning_msg = f'"\'OptimizationControlMechanism-0\' has \'num_estimates = {num_estimates}\' specified, ' \ + f'but its \'agent_rep\' (\'comp\') has no random variables: ' \ + f'\'RANDOMIZATION_CONTROL_SIGNAL\' will not be created, and num_estimates set to None."' + with pytest.warns(warning_type) as warning: + ocm = pnl.OptimizationControlMechanism(agent_rep=comp, + state_features=[A.input_port], + objective_mechanism=objective_mech, + function=pnl.GridSearch(), + num_estimates=num_estimates, + control_signals=[control_signal]) + if warning_type: + assert repr(warning[5].message.args[0]) == warning_msg comp.add_controller(ocm) - inputs = {A: [[[1.0]]]} comp.run(inputs=inputs, num_trials=2) - if num_estimates is None: + if not num_estimates or not rand_var: assert pnl.RANDOMIZATION_CONTROL_SIGNAL not in comp.controller.control_signals # Confirm no estimates - elif num_estimates==1: - assert comp.controller.control_signals[pnl.RANDOMIZATION_CONTROL_SIGNAL].efferents == []# Confirm no noise - assert np.allclose(comp.simulation_results, - [[np.array([2.25])], [np.array([3.5])], [np.array([4.75])], [np.array([3.])], [np.array([4.25])], [np.array([5.5])]]) - assert np.allclose(comp.results, - [[np.array([1.])], [np.array([1.75])]]) + elif num_estimates: + assert len(comp.controller.control_signals[pnl.RANDOMIZATION_CONTROL_SIGNAL].efferents) == 1 + # noise + + if rand_var: # results for DDM (which has random variables) + assert np.allclose(comp.simulation_results, + [[np.array([2.25])], [np.array([3.5])], [np.array([4.75])], [np.array([3.])], [np.array([4.25])], [np.array([5.5])]]) + assert np.allclose(comp.results, + [[np.array([1.]), np.array([1.1993293])], [np.array([1.]), np.array([3.24637662])]]) + else: # results for ProcessingMechanism (which does not have any random variables) + assert np.allclose(comp.simulation_results, + [[np.array([2.25])], [np.array([3.5])], [np.array([4.75])], [np.array([3.])], [np.array([4.25])], [np.array([5.5])]]) + assert np.allclose(comp.results, + [[np.array([1.])], [np.array([1.75])]]) def test_model_based_ocm_no_simulations(self): A = pnl.ProcessingMechanism(name='A') @@ -2536,7 +3712,7 @@ def test_input_CIM_assignment(self, comp_mode): comp.add_controller( pnl.OptimizationControlMechanism( agent_rep=comp, - state_features=[input_b.input_port, input_a.input_port], + state_features=[input_a.input_port, input_b.input_port], name="Controller", objective_mechanism=pnl.ObjectiveMechanism( monitor=output.output_port, @@ -2571,6 +3747,7 @@ def test_input_CIM_assignment(self, comp_mode): assert np.allclose(results, [[7]]) +@pytest.mark.control class TestSampleIterator: def test_int_step(self): @@ -2684,6 +3861,7 @@ def test_list(self): assert sample_iterator.num == len(sample_list) +@pytest.mark.control class TestControlTimeScales: def test_time_step_before(self): diff --git a/tests/composition/test_gating.py b/tests/composition/test_gating.py index 21f787a6f89..486f1c04fbb 100644 --- a/tests/composition/test_gating.py +++ b/tests/composition/test_gating.py @@ -1,5 +1,6 @@ import numpy as np import pytest + import psyneulink as pnl @@ -19,7 +20,7 @@ def test_gating(benchmark, comp_mode): function=pnl.Linear(), output_ports={ pnl.NAME: 'RESULTS USING UDF', - pnl.FUNCTION: pnl.Linear(slope=pnl.GATING) + pnl.FUNCTION: pnl.Linear(slope=pnl.GATE) } ) diff --git a/tests/composition/test_learning.py b/tests/composition/test_learning.py index de7dae19478..cdf3c289165 100644 --- a/tests/composition/test_learning.py +++ b/tests/composition/test_learning.py @@ -274,13 +274,13 @@ def test_target_spec_over_nesting_of_items_in_target_value_error(self): comp.run(inputs={A: [1.0, 2.0, 3.0], p.target: [[[3.0], [4.0]], [[5.0], [6.0]], [[7.0], [8.0]]]}) assert ("Input stimulus" in str(error_text.value) and - "for Target is incompatible with its external_input_values" in str(error_text.value)) + "for Target is incompatible with the shape of its external input" in str(error_text.value)) # Elicit error with learn with pytest.raises(RunError) as error_text: comp.learn(inputs={A: [1.0, 2.0, 3.0], p.target: [[[3.0], [4.0]], [[5.0], [6.0]], [[7.0], [8.0]]]}) assert ("Input stimulus" in str(error_text.value) and - "for Target is incompatible with its external_input_values" in str(error_text.value)) + "for Target is incompatible with the shape of its external input" in str(error_text.value)) # The input sizes were picked because the lengths conflict in set: # >>> print({10, 2}, {2, 10}) @@ -303,7 +303,7 @@ def test_different_number_of_stimuli_for_targets_and_other_input_mech_error(self assert 'The input dictionary' in error_text assert 'contains input specifications of different lengths ({10, 2})' in error_text or \ 'contains input specifications of different lengths ({2, 10})' in error_text - assert 'The same number of inputs must be provided for each node in a Composition' in error_text + assert 'The same number of inputs must be provided for each receiver in a Composition' in error_text class TestLearningPathwayMethods: diff --git a/tests/composition/test_models.py b/tests/composition/test_models.py index 3db9c9c2092..5d9aa3e4087 100644 --- a/tests/composition/test_models.py +++ b/tests/composition/test_models.py @@ -13,7 +13,7 @@ def test_DDM(self): function=psyneulink.core.components.functions.nonstateful.distributionfunctions.DriftDiffusionAnalytical( drift_rate=(1.0), threshold=(10.0), - starting_point=0.0, + starting_value=0.0, ), name='My_DDM', ) @@ -231,21 +231,6 @@ def trial_dict(red_color, green_color, red_word, green_word, CN, WR): } return trialdict - # CREATE THRESHOLD FUNCTION - # first value of DDM's value is DECISION_VARIABLE - # context is always passed to Condition functions and is the context - # in which the function gets called - below, during system execution - def pass_threshold(mech1, mech2, thresh, context=None): - results1 = mech1.output_ports[0].parameters.value.get(context) - results2 = mech2.output_ports[0].parameters.value.get(context) - for val in results1: - if val >= thresh: - return True - for val in results2: - if val >= thresh: - return True - return False - accumulator_threshold = 1.0 mechanisms_to_update = [colors_hidden_layer, words_hidden_layer, response_layer] @@ -272,12 +257,11 @@ def switch_to_processing_trial(mechanisms): # Turn on noise switch_noise(mechanisms, psyneulink.core.components.functions.nonstateful.distributionfunctions.NormalDist(mean=0, standard_deviation=unit_noise).function) # Execute until one of the accumulators crosses the threshold + # first value of DDM's value is DECISION_VARIABLE my_Stroop.termination_processing = { - pnl.TimeScale.TRIAL: pnl.While( - pass_threshold, - respond_red_accumulator, - respond_green_accumulator, - accumulator_threshold + pnl.TimeScale.TRIAL: pnl.Or( + pnl.Threshold(respond_red_accumulator, 'value', accumulator_threshold, '>=', (0, 0)), + pnl.Threshold(respond_green_accumulator, 'value', accumulator_threshold, '>=', (0, 0)) ) } diff --git a/tests/composition/test_parameterestimationcomposition.py b/tests/composition/test_parameterestimationcomposition.py index 43eec9cf638..c5bffb15fd5 100644 --- a/tests/composition/test_parameterestimationcomposition.py +++ b/tests/composition/test_parameterestimationcomposition.py @@ -56,8 +56,8 @@ def test_parameter_estimation_composition(objective_function_arg, expected_input pnl.ALLOCATION_SAMPLES: samples, })), noise=0.5, - starting_point=0, - t0=0.45), + starting_value=0, + non_decision_time=0.45), output_ports=[DECISION_VARIABLE, RESPONSE_TIME, PROBABILITY_UPPER_THRESHOLD], @@ -65,8 +65,8 @@ def test_parameter_estimation_composition(objective_function_arg, expected_input Decision2 = DDM(function=DriftDiffusionAnalytical(drift_rate=1.0, threshold=1.0, noise=0.5, - starting_point=0, - t0=0.45), + starting_value=0, + non_decision_time=0.45), output_ports=[DECISION_VARIABLE, RESPONSE_TIME, PROBABILITY_UPPER_THRESHOLD], @@ -97,7 +97,7 @@ def test_parameter_estimation_composition(objective_function_arg, expected_input # enable_controller=False # For testing error ) ctlr = pec.controller - # pec.show_graph(show_node_structure=pnl.ALL) + assert ctlr.num_outcome_input_ports == 1 if objective_function_arg: # pec.show_graph(show_cim=True) diff --git a/tests/composition/test_report.py b/tests/composition/test_report.py index 82e79dbf443..9b23a372c27 100644 --- a/tests/composition/test_report.py +++ b/tests/composition/test_report.py @@ -174,6 +174,8 @@ def test_nested_comps_and_sims_basic(self): """Test output and progress reports for execution of simulations by controller in both an outer and nested composition, using input dictionary, generator instance and generator function. """ + # pnl.clear_registry() + pnl.clear_registry(pnl.FunctionRegistry) # instantiate mechanisms and inner comp ia = pnl.TransferMechanism(name='ia') @@ -397,7 +399,7 @@ def inputs_generator_function(): report_to_devices=ReportDevices.DIVERT ) actual_output = ocomp.rich_diverted_reports - expected_output = '\n ╔════════════════════════════ EXECUTION OF ocomp ════════════════════════════╗\n ║ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 0 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[-2]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━ iController SIMULATION OF icomp BEFORE its Trial 18 ━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [54.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 18 ━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰─────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └─────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 34.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[-20.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ║\n ║ ┃ │ │ input: -20.0 │ │ ┃ ║\n ║ ┃ │ │ output: 34.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[-20.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ oController SIMULATION OF ocomp AFTER its Trial 0 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[-2.0]] ┃ ║\n ║ ┃ outcome: [34.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[1.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 1 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━ iController SIMULATION OF icomp BEFORE its Trial 19 ━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [34.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[10.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 19 ━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 1.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰─────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └─────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: 10. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: 10.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 44.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[10.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ║\n ║ ┃ │ │ input: 10.0 │ │ ┃ ║\n ║ ┃ │ │ output: 44.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[10.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ oController SIMULATION OF ocomp AFTER its Trial 1 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[1.0]] ┃ ║\n ║ ┃ outcome: [44.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[10.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════════════════════════════════════════╝\n\nocomp: Executed 2 of 2 trials\n icomp: Executed 1 of 1 trial (depth: 1)\n icomp: Executed 1 of 1 trial (depth: 1)\n' + expected_output = '\n ╔════════════════════════════ EXECUTION OF ocomp ════════════════════════════╗\n ║ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 0 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[-2.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━ iController SIMULATION OF icomp BEFORE its Trial 18 ━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [54.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 18 ━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰─────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └─────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 34.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[-20.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ║\n ║ ┃ │ │ input: -20.0 │ │ ┃ ║\n ║ ┃ │ │ output: 34.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[-20.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ oController SIMULATION OF ocomp AFTER its Trial 0 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[-2.0]] ┃ ║\n ║ ┃ outcome: [34.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[1.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 1 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━ iController SIMULATION OF icomp BEFORE its Trial 19 ━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [34.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[10.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 19 ━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 1.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰─────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └─────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: 10. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: 10.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 44.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[10.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ║\n ║ ┃ │ │ input: 10.0 │ │ ┃ ║\n ║ ┃ │ │ output: 44.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[10.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ oController SIMULATION OF ocomp AFTER its Trial 1 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[1.0]] ┃ ║\n ║ ┃ outcome: [44.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[10.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════════════════════════════════════════╝\n\nocomp: Executed 2 of 2 trials\n icomp: Executed 1 of 1 trial (depth: 1)\n icomp: Executed 1 of 1 trial (depth: 1)\n' assert actual_output == expected_output ocomp.run(inputs=inputs_dict, @@ -407,7 +409,7 @@ def inputs_generator_function(): report_to_devices=ReportDevices.DIVERT ) actual_output = ocomp.rich_diverted_reports - expected_output = '\n ╔════════════════════════════ EXECUTION OF ocomp ════════════════════════════╗\n ║ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 0 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[-2]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━ iController SIMULATION OF icomp BEFORE its Trial 20 ━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [44.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 42.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -11. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 33.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[-11.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 24.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[-20.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 20 ━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰─────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └─────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 24.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[-20.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ║\n ║ ┃ │ │ input: -20.0 │ │ ┃ ║\n ║ ┃ │ │ output: 24.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[-20.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━ oController SIMULATION OF ocomp AFTER its Trial 0 ━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[-2.0]] ┃ ║\n ║ ┃ outcome: [24.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 0: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp BEFORE its Trial━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [24.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 22.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -11. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 13.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-11.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: 22.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: 22.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 1: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp BEFORE its Trial━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [24.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 22.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -11. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 13.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-11.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-20.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-20.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[1.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 1 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━ iController SIMULATION OF icomp BEFORE its Trial 21 ━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [24.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[1.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: 1. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: 1.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 25.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[1.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[1.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 5.5 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 5.5 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: 5.5 (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: 5.5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 5.5 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 5.5 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 29.5 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[5.5]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[1.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 10.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 10.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: 10. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: 10.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 10.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 10.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 34.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[10.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[10.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 21 ━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 1.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰─────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └─────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: 10. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: 10.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 34.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[10.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ║\n ║ ┃ │ │ input: 10.0 │ │ ┃ ║\n ║ ┃ │ │ output: 34.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[10.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━ oController SIMULATION OF ocomp AFTER its Trial 1 ━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[1.0]] ┃ ║\n ║ ┃ outcome: [34.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 0: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp BEFORE its Trial━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [24.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 22.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -11. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 13.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-11.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: 22.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: 22.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 1: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp BEFORE its Trial━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [24.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 22.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -11. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 13.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-11.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-20.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-20.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[10.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════════════════════════════════════════╝\n\nocomp: Executed 2 of 2 trials\n icomp: Executed 1 of 1 trial (depth: 1)\n icomp: Simulated 3 trials (depth: 2)\n ocomp: Simulated 2 trials (depth: 1)\n icomp: Executed 1 of 1 trial (depth: 2)\n icomp: Simulated 3 trials (depth: 3)\n icomp: Executed 1 of 1 trial (depth: 2)\n icomp: Simulated 3 trials (depth: 3)\n icomp: Executed 1 of 1 trial (depth: 1)\n icomp: Simulated 3 trials (depth: 2)\n ocomp: Simulated 2 trials (depth: 1)\n icomp: Executed 1 of 1 trial (depth: 2)\n icomp: Simulated 3 trials (depth: 3)\n icomp: Executed 1 of 1 trial (depth: 2)\n icomp: Simulated 3 trials (depth: 3)\n' + expected_output = '\n ╔════════════════════════════ EXECUTION OF ocomp ════════════════════════════╗\n ║ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 0 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[-2.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━ iController SIMULATION OF icomp BEFORE its Trial 20 ━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [44.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 42.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -11. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 33.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[-11.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 24.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[-20.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 20 ━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰─────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └─────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 24.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[-20.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ║\n ║ ┃ │ │ input: -20.0 │ │ ┃ ║\n ║ ┃ │ │ output: 24.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[-20.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━ oController SIMULATION OF ocomp AFTER its Trial 0 ━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[-2.0]] ┃ ║\n ║ ┃ outcome: [24.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 0: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp BEFORE its Trial━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [24.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 22.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -11. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 13.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-11.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: 22.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: 22.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 1: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp BEFORE its Trial━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [24.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 22.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -11. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 13.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-11.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-20.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-20.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[1.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 1 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━ iController SIMULATION OF icomp BEFORE its Trial 21 ━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [24.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[1.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: 1. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: 1.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 25.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[1.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[1.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 5.5 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 5.5 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: 5.5 (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: 5.5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 5.5 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 5.5 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 29.5 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[5.5]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[1.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 10.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 10.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: 10. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: 10.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 10.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 10.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 34.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[10.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[10.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 21 ━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 1.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰─────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └─────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: 10. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: 10.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 34.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[10.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ║\n ║ ┃ │ │ input: 10.0 │ │ ┃ ║\n ║ ┃ │ │ output: 34.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[10.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━ oController SIMULATION OF ocomp AFTER its Trial 1 ━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[1.0]] ┃ ║\n ║ ┃ outcome: [34.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 0: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp BEFORE its Trial━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [24.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 22.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -11. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 13.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-11.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: 22.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: 22.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 1: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp BEFORE its Trial━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [24.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 22.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -11. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 13.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-11.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-20.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-20.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[10.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════════════════════════════════════════╝\n\nocomp: Executed 2 of 2 trials\n icomp: Executed 1 of 1 trial (depth: 1)\n icomp: Simulated 3 trials (depth: 2)\n ocomp: Simulated 2 trials (depth: 1)\n icomp: Executed 1 of 1 trial (depth: 2)\n icomp: Simulated 3 trials (depth: 3)\n icomp: Executed 1 of 1 trial (depth: 2)\n icomp: Simulated 3 trials (depth: 3)\n icomp: Executed 1 of 1 trial (depth: 1)\n icomp: Simulated 3 trials (depth: 2)\n ocomp: Simulated 2 trials (depth: 1)\n icomp: Executed 1 of 1 trial (depth: 2)\n icomp: Simulated 3 trials (depth: 3)\n icomp: Executed 1 of 1 trial (depth: 2)\n icomp: Simulated 3 trials (depth: 3)\n' assert actual_output == expected_output icomp.controller_mode = pnl.AFTER @@ -420,7 +422,7 @@ def inputs_generator_function(): report_to_devices=ReportDevices.DIVERT ) actual_output = ocomp.rich_diverted_reports - expected_output = '\n ╔════════════════════════════ EXECUTION OF ocomp ════════════════════════════╗\n ║ ║\n ║ ║\n ║ ┏━ oController SIMULATION OF ocomp BEFORE its Trial 0 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[-2.0]] ┃ ║\n ║ ┃ outcome: [34.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[1.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 0 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[-2]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 22 ━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰─────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └─────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 14.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[-20.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━ iController SIMULATION OF icomp AFTER its Trial 22 ━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [14.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ║\n ║ ┃ │ │ input: -20.0 │ │ ┃ ║\n ║ ┃ │ │ output: 14.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[-20.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ oController SIMULATION OF ocomp BEFORE its Trial 1 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[1.0]] ┃ ║\n ║ ┃ outcome: [14.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[10.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 1 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 23 ━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 1.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰─────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └─────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: 10. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: 10.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 24.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[10.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━ iController SIMULATION OF icomp AFTER its Trial 23 ━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [24.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[10.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ║\n ║ ┃ │ │ input: 10.0 │ │ ┃ ║\n ║ ┃ │ │ output: 24.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[10.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════════════════════════════════════════╝\n\nocomp: Executed 2 of 2 trials\n icomp: Executed 1 of 1 trial (depth: 1)\n icomp: Executed 1 of 1 trial (depth: 1)\n' + expected_output = '\n ╔════════════════════════════ EXECUTION OF ocomp ════════════════════════════╗\n ║ ║\n ║ ║\n ║ ┏━ oController SIMULATION OF ocomp BEFORE its Trial 0 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[-2.0]] ┃ ║\n ║ ┃ outcome: [34.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[1.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 0 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[-2.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 22 ━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰─────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └─────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 14.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[-20.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━ iController SIMULATION OF icomp AFTER its Trial 22 ━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [14.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ║\n ║ ┃ │ │ input: -20.0 │ │ ┃ ║\n ║ ┃ │ │ output: 14.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[-20.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ oController SIMULATION OF ocomp BEFORE its Trial 1 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[1.0]] ┃ ║\n ║ ┃ outcome: [14.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[10.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 1 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 23 ━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 1.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰─────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └─────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: 10. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: 10.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 24.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[10.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━ iController SIMULATION OF icomp AFTER its Trial 23 ━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [24.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[10.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ║\n ║ ┃ │ │ input: 10.0 │ │ ┃ ║\n ║ ┃ │ │ output: 24.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[10.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════════════════════════════════════════╝\n\nocomp: Executed 2 of 2 trials\n icomp: Executed 1 of 1 trial (depth: 1)\n icomp: Executed 1 of 1 trial (depth: 1)\n' assert actual_output == expected_output ocomp.run(inputs=inputs_dict, @@ -430,11 +432,13 @@ def inputs_generator_function(): report_to_devices=ReportDevices.DIVERT ) actual_output = ocomp.rich_diverted_reports - expected_output = '\n ╔════════════════════════════ EXECUTION OF ocomp ════════════════════════════╗\n ║ ║\n ║ ║\n ║ ┏━━━━━━━━━ oController SIMULATION OF ocomp BEFORE its Trial 0 ━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[-2.0]] ┃ ║\n ║ ┃ outcome: [24.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 0: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-20.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp AFTER its Trial ━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [4.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -11. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -7.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-11.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -16.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-20.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 1: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -200.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -200.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -200. (monitored by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController Objective Mechanism and │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ oController Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -200.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -200.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -200.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -176.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-200.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp AFTER its Trial ━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [-176.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -178.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -11. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -187.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-11.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -196.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -200.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: -176.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-200.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[1.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 0 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[-2]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 24 ━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰─────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └─────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 4.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[-20.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━ iController SIMULATION OF icomp AFTER its Trial 24 ━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [4.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -11. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -7.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[-11.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -16.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[-20.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ║\n ║ ┃ │ │ input: -20.0 │ │ ┃ ║\n ║ ┃ │ │ output: 4.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[-20.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━ oController SIMULATION OF ocomp BEFORE its Trial 1 ━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[1.0]] ┃ ║\n ║ ┃ outcome: [4.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 0: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-20.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp AFTER its Trial ━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [4.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -11. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -7.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-11.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -16.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-20.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 1: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -200.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -200.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -200. (monitored by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController Objective Mechanism and │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ oController Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -200.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -200.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -200.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -176.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-200.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp AFTER its Trial ━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [-176.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -178.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -11. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -187.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-11.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -196.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -200.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: -176.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-200.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[10.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 1 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 25 ━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 1.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰─────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └─────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: 10. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: 10.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 14.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[10.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━ iController SIMULATION OF icomp AFTER its Trial 25 ━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [14.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[1.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: 1. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: 1.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 15.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[1.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[1.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 5.5 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 5.5 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: 5.5 (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: 5.5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 5.5 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 5.5 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 19.5 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[5.5]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[1.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 10.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 10.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: 10. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: 10.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 10.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 10.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 24.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[10.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[10.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ║\n ║ ┃ │ │ input: 10.0 │ │ ┃ ║\n ║ ┃ │ │ output: 14.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[10.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════════════════════════════════════════╝\n\nocomp: Executed 2 of 2 trials\n ocomp: Simulated 2 trials (depth: 1)\n icomp: Executed 1 of 1 trial (depth: 2)\n icomp: Simulated 3 trials (depth: 3)\n icomp: Executed 1 of 1 trial (depth: 2)\n icomp: Simulated 3 trials (depth: 3)\n icomp: Executed 1 of 1 trial (depth: 1)\n icomp: Simulated 3 trials (depth: 2)\n ocomp: Simulated 2 trials (depth: 1)\n icomp: Executed 1 of 1 trial (depth: 2)\n icomp: Simulated 3 trials (depth: 3)\n icomp: Executed 1 of 1 trial (depth: 2)\n icomp: Simulated 3 trials (depth: 3)\n icomp: Executed 1 of 1 trial (depth: 1)\n icomp: Simulated 3 trials (depth: 2)\n' + expected_output = '\n ╔════════════════════════════ EXECUTION OF ocomp ════════════════════════════╗\n ║ ║\n ║ ║\n ║ ┏━━━━━━━━━ oController SIMULATION OF ocomp BEFORE its Trial 0 ━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[-2.0]] ┃ ║\n ║ ┃ outcome: [24.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 0: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-20.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp AFTER its Trial ━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [4.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -11. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -7.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-11.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -16.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-20.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 1: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -200.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -200.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -200. (monitored by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController Objective Mechanism and │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ oController Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -200.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -200.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -200.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -176.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-200.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp AFTER its Trial ━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [-176.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -178.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -11. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -187.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-11.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -196.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -200.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: -176.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-200.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[1.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 0 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[-2.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 24 ━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰─────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └─────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -20.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 4.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[-20.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━ iController SIMULATION OF icomp AFTER its Trial 24 ━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [4.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -11. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -7.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[-11.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -16.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[-20.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ║\n ║ ┃ │ │ input: -20.0 │ │ ┃ ║\n ║ ┃ │ │ output: 4.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[-20.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━ oController SIMULATION OF ocomp BEFORE its Trial 1 ━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[1.0]] ┃ ║\n ║ ┃ outcome: [4.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 0: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-20.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp AFTER its Trial ━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [4.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: 2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -11. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -7.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-11.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -16.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: 4.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-20.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 1: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -200.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -200.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -200. (monitored by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController Objective Mechanism and │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ oController Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -200.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -200.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -200.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -176.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-200.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp AFTER its Trial ━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [-176.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -178.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -11. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -187.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-11.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -196.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -200.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: -176.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-200.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[10.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 1 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 25 ━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 1.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰─────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └─────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: 10. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: 10.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: 10.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: 14.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[10.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━ iController SIMULATION OF icomp AFTER its Trial 25 ━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [14.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[1.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: 1. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: 1.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 15.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[1.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[1.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 5.5 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 5.5 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: 5.5 (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: 5.5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 5.5 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 5.5 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 19.5 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[5.5]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 2: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[1.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 1.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 10.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰─────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └─────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 10.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: 10. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: 10.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 10.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: 10.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: 24.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[10.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[10.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ║\n ║ ┃ │ │ input: 10.0 │ │ ┃ ║\n ║ ┃ │ │ output: 14.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[10.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════════════════════════════════════════╝\n\nocomp: Executed 2 of 2 trials\n ocomp: Simulated 2 trials (depth: 1)\n icomp: Executed 1 of 1 trial (depth: 2)\n icomp: Simulated 3 trials (depth: 3)\n icomp: Executed 1 of 1 trial (depth: 2)\n icomp: Simulated 3 trials (depth: 3)\n icomp: Executed 1 of 1 trial (depth: 1)\n icomp: Simulated 3 trials (depth: 2)\n ocomp: Simulated 2 trials (depth: 1)\n icomp: Executed 1 of 1 trial (depth: 2)\n icomp: Simulated 3 trials (depth: 3)\n icomp: Executed 1 of 1 trial (depth: 2)\n icomp: Simulated 3 trials (depth: 3)\n icomp: Executed 1 of 1 trial (depth: 1)\n icomp: Simulated 3 trials (depth: 2)\n' assert actual_output == expected_output def test_nested_comps_and_sims_with_modulated_and_monitored_params_and_use_prefs(self): + pnl.clear_registry() + # instantiate mechanisms and inner comp ia = pnl.TransferMechanism(name='ia') ib = pnl.TransferMechanism(name='ib') @@ -473,8 +477,6 @@ def test_nested_comps_and_sims_with_modulated_and_monitored_params_and_use_prefs # setup structure of outer comp ocomp.add_node(icomp) - # ocomp._analyze_graph() - # add controller to outer comp ocomp.add_controller( pnl.OptimizationControlMechanism( @@ -496,8 +498,6 @@ def test_nested_comps_and_sims_with_modulated_and_monitored_params_and_use_prefs num=3))]) ) - # inputs_dict = {icomp:{ia: [[-2], [1]]}} - ocomp.run(inputs={icomp:-2}, report_output=ReportOutput.FULL, report_params=[pnl.ReportParams.MODULATED, pnl.ReportParams.MONITORED], @@ -507,7 +507,7 @@ def test_nested_comps_and_sims_with_modulated_and_monitored_params_and_use_prefs # report_to_devices=ReportDevices.RECORD ) actual_output = ocomp.rich_diverted_reports - expected_output = '\n ╔════════════════════════════ EXECUTION OF ocomp ════════════════════════════╗\n ║ ║\n ║ ║\n ║ ┏━━━━━━━━━ oController SIMULATION OF ocomp BEFORE its Trial 0 ━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[-2.0]] ┃ ║\n ║ ┃ outcome: [0.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 0: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 0 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ia ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -2. (monitored by iController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp AFTER its Trial ━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [-2.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -4. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -4.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -22. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -22.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭───── oController Objective Mechanism ─────╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ value: -2. (monitored by oController) │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 1: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 0 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ia ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -11. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -11. (monitored by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-11.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp AFTER its Trial ━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [-11.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -13. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -13.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -31. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -31.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌───────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭───── oController Objective Mechanism ──────╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╭──────────────── params ────────────────╮ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ value: -11. (monitored by oController) │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╰────────────────────────────────────────╯ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰────────────────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-11.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 2: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 0 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ia ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-20.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp AFTER its Trial ━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [-20.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -22. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -22.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -40. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -40.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌───────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭───── oController Objective Mechanism ──────╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╭──────────────── params ────────────────╮ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ value: -20. (monitored by oController) │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╰────────────────────────────────────────╯ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰────────────────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-20.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[1.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 0 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[-2]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 0 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ia ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ slope: 1.0 (modulated by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ and oController) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: -2. (monitored by iController) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━ iController SIMULATION OF icomp AFTER its Trial 0 ━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [-2.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 0 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ia ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -4. (monitored by iController) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -4.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 0 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ia ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -22. (monitored by │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -22.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[-20.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭───── oController Objective Mechanism ─────╮ │ ┃ ║\n ║ ┃ │ │ input: -2.0 │ │ ┃ ║\n ║ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ║\n ║ ┃ │ │ │ value: -2. (monitored by oController) │ │ │ ┃ ║\n ║ ┃ │ │ │ │ │ │ ┃ ║\n ║ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ║\n ║ ┃ │ │ output: -2.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[-2.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════════════════════════════════════════╝\n\n' + expected_output = '\n ╔════════════════════════════ EXECUTION OF ocomp ════════════════════════════╗\n ║ ║\n ║ ║\n ║ ┏━━━━━━━━━ oController SIMULATION OF ocomp BEFORE its Trial 0 ━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[-2.0]] ┃ ║\n ║ ┃ outcome: [0.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 0: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 0 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ia ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -2. (monitored by iController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp AFTER its Trial ━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [-2.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -4. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -4.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -22. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -22.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭───── oController Objective Mechanism ─────╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ value: -2. (monitored by oController) │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 1: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 0 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ia ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -11. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -11. (monitored by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-11.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp AFTER its Trial ━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [-11.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -13. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -13.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -31. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -31.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌───────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭───── oController Objective Mechanism ──────╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╭──────────────── params ────────────────╮ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ value: -11. (monitored by oController) │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╰────────────────────────────────────────╯ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰────────────────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-11.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 2: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 0 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ia ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-20.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp AFTER its Trial ━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [-20.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -22. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -22.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -40. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -40.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌───────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭───── oController Objective Mechanism ──────╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╭──────────────── params ────────────────╮ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ value: -20. (monitored by oController) │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╰────────────────────────────────────────╯ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰────────────────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-20.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[1.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 0 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[-2.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 0 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ia ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ slope: 1.0 (modulated by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ and oController) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: -2. (monitored by iController) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━ iController SIMULATION OF icomp AFTER its Trial 0 ━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [-2.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 0 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ia ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -4. (monitored by iController) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -4.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 0 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ia ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -22. (monitored by │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -22.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[-20.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭───── oController Objective Mechanism ─────╮ │ ┃ ║\n ║ ┃ │ │ input: -2.0 │ │ ┃ ║\n ║ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ║\n ║ ┃ │ │ │ value: -2. (monitored by oController) │ │ │ ┃ ║\n ║ ┃ │ │ │ │ │ │ ┃ ║\n ║ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ║\n ║ ┃ │ │ output: -2.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[-2.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════════════════════════════════════════╝\n\n' assert actual_output == expected_output ocomp.run(inputs={icomp:-2}, @@ -519,7 +519,7 @@ def test_nested_comps_and_sims_with_modulated_and_monitored_params_and_use_prefs # report_to_devices=ReportDevices.RECORD ) actual_output = ocomp.rich_diverted_reports - expected_output = '\n ╔════════════════════════════ EXECUTION OF ocomp ════════════════════════════╗\n ║ ║\n ║ ║\n ║ ┏━ oController SIMULATION OF ocomp BEFORE its Trial 0 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[-2.0]] ┃ ║\n ║ ┃ outcome: [-2.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[1.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 0 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[-2]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 1 ━━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰─────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └─────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -4.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━ iController SIMULATION OF icomp AFTER its Trial 1 ━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [-4.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ║\n ║ ┃ │ │ input: -2.0 │ │ ┃ ║\n ║ ┃ │ │ output: -4.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[-2.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════════════════════════════════════════╝\n\n' + expected_output = '\n ╔════════════════════════════ EXECUTION OF ocomp ════════════════════════════╗\n ║ ║\n ║ ║\n ║ ┏━ oController SIMULATION OF ocomp BEFORE its Trial 0 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[-2.0]] ┃ ║\n ║ ┃ outcome: [-2.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[1.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 0 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[-2.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 1 ━━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────── Time Step 0 ────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────── ia ───────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────── params ───────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰─────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰─────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └─────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────── Time Step 2 ─────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭─ iController Objective Mechanism ─╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -4.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━ iController SIMULATION OF icomp AFTER its Trial 1 ━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [-4.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────── Time Step 1 ─────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─ oController Objective Mechanism ─╮ │ ┃ ║\n ║ ┃ │ │ input: -2.0 │ │ ┃ ║\n ║ ┃ │ │ output: -4.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[-2.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════════════════════════════════════════╝\n\n' assert actual_output == expected_output ocomp.run(inputs={icomp:-2}, @@ -546,7 +546,7 @@ def test_nested_comps_and_sims_with_modulated_and_monitored_params_and_use_prefs # report_to_devices=ReportDevices.RECORD ) actual_output = ocomp.rich_diverted_reports - expected_output = '\n ╔════════════════════════════ EXECUTION OF ocomp ════════════════════════════╗\n ║ ║\n ║ ║\n ║ ┏━━━━━━━━━ oController SIMULATION OF ocomp BEFORE its Trial 0 ━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[-2.0]] ┃ ║\n ║ ┃ outcome: [-6.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 0: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 0 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ia ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -8. (monitored by iController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -8.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp AFTER its Trial ━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [-8.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -10. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -10.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -28. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -28.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭───── oController Objective Mechanism ─────╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ value: -8. (monitored by oController) │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: -8.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 1: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 0 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ia ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -11. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -17. (monitored by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -17.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-11.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp AFTER its Trial ━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [-17.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -19. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -19.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -37. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -37.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌───────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭───── oController Objective Mechanism ──────╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╭──────────────── params ────────────────╮ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ value: -17. (monitored by oController) │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╰────────────────────────────────────────╯ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: -17.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰────────────────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-11.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 2: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 0 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ia ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -26. (monitored by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -26.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-20.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp AFTER its Trial ━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [-26.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -28. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -28.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -46. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -46.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌───────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭───── oController Objective Mechanism ──────╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╭──────────────── params ────────────────╮ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ value: -26. (monitored by oController) │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╰────────────────────────────────────────╯ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: -26.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰────────────────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-20.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[1.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 0 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[-2]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 3 ━━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 0 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ia ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ slope: 1.0 (modulated by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ and oController) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: -8. (monitored by iController) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -8.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━ iController SIMULATION OF icomp AFTER its Trial 3 ━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [-8.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 0 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ia ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -10. (monitored by │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -10.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 0 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ia ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -28. (monitored by │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -28.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[-20.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭───── oController Objective Mechanism ─────╮ │ ┃ ║\n ║ ┃ │ │ input: -2.0 │ │ ┃ ║\n ║ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ║\n ║ ┃ │ │ │ value: -8. (monitored by oController) │ │ │ ┃ ║\n ║ ┃ │ │ │ │ │ │ ┃ ║\n ║ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ║\n ║ ┃ │ │ output: -8.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[-2.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════════════════════════════════════════╝\n\n' + expected_output = '\n ╔════════════════════════════ EXECUTION OF ocomp ════════════════════════════╗\n ║ ║\n ║ ║\n ║ ┏━━━━━━━━━ oController SIMULATION OF ocomp BEFORE its Trial 0 ━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ state: [[-2.0]] ┃ ║\n ║ ┃ outcome: [-6.0] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 0: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 0 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ia ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -8. (monitored by iController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -8.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp AFTER its Trial ━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [-8.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -10. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -10.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -28. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -28.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭───── oController Objective Mechanism ─────╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ value: -8. (monitored by oController) │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: -8.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 1: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 0 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ia ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -11. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -11.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -11.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -17. (monitored by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -17.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-11.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp AFTER its Trial ━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [-17.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -19. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -19.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -37. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -37.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌───────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭───── oController Objective Mechanism ──────╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -11.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╭──────────────── params ────────────────╮ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ value: -17. (monitored by oController) │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╰────────────────────────────────────────╯ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: -17.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰────────────────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-11.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┏━━━━━━━━━━━━━━━━━━ ocomp SIMULATION 2: Trial 0 ━━━━━━━━━━━━━━━━━━┓ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌──────────────────────── Time Step 0 ────────────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┏━━━━━━━━━━━━ EXECUTION OF icomp within ocomp ━━━━━━━━━━━━┓ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━━━━━━━━━━━━━━━━━ icomp: Trial 0 ━━━━━━━━━━━━━━━━━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ input: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 0 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ia ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ value: -26. (monitored by │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ │ │ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ output: -26.0 │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ result: [[-20.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┏━ iController SIMULATION OF icomp AFTER its Trial ━┓ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ state: [[-2.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ outcome: [-26.0] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -2. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -28. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -28.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┏━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━┓ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ input: [[-2.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 0 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ia ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 1 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭───────────────── ib ─────────────────╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -20. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController Objective Mechanism │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ and oController Objective │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ Mechanism) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┌────────────── Time Step 2 ──────────────┐ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╭── iController Objective Mechanism ───╮ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╭───────────── params ─────────────╮ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ value: -46. (monitored by │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ╰──────────────────────────────────╯ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ output: -46.0 │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ ╰──────────────────────────────────────╯ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ │ │ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ └──────────────────────────────────────────┘ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ result: [[-20.0]] ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ control allocation: [[1.0]] ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┃ ┃ │ ┃ ┃ ║\n ║ ┃ ┃ │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └──────────────────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ ┌───────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╭───── oController Objective Mechanism ──────╮ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╭──────────────── params ────────────────╮ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ value: -26. (monitored by oController) │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ╰────────────────────────────────────────╯ │ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ output: -26.0 │ │ ┃ ┃ ║\n ║ ┃ ┃ │ ╰────────────────────────────────────────────╯ │ ┃ ┃ ║\n ║ ┃ ┃ │ │ ┃ ┃ ║\n ║ ┃ ┃ └────────────────────────────────────────────────┘ ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┃ result: [[-20.0]] ┃ ┃ ║\n ║ ┃ ┃ ┃ ┃ ║\n ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ control allocation: [[1.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━ ocomp: Trial 0 ━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[-2.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 0 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╔══════════════ EXECUTION OF icomp within ocomp ═══════════════╗ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━━━━━━━━━━━━━━━━━━ icomp: Trial 3 ━━━━━━━━━━━━━━━━━━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ input: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 0 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ia ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ slope: 1.0 (modulated by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ and oController) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌─────────────────── Time Step 1 ───────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭────────────────────── ib ──────────────────────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭────────────────── params ──────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰────────────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰────────────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └────────────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ input: -2.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ value: -8. (monitored by iController) │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ │ │ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ output: -8.0 │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ │ │ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ └───────────────────────────────────────────────┘ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ result: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ║ ┏━━ iController SIMULATION OF icomp AFTER its Trial 3 ━━━┓ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ state: [[-2.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ outcome: [-8.0] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 0: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 0 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ia ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -2. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: -2.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -10. (monitored by │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -10.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┏━━━━━━━━━━ icomp SIMULATION 1: Trial 0 ━━━━━━━━━━━┓ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ input: [[-2.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 0 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ia ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -2.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-5 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ intercept: 0.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ slope: 1.0 (modulated by │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ iController and oController) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭─────────────────── ib ────────────────────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -20. (monitored by iController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism and oController │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ Objective Mechanism) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ function: Linear Function-14 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ variable: -20.0 │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┌──────────────── Time Step 2 ─────────────────┐ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╭───── iController Objective Mechanism ─────╮ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ input: -20.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ value: -28. (monitored by │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ iController) │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ │ │ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ output: -28.0 │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ │ │ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ └───────────────────────────────────────────────┘ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ result: [[-20.0]] ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ control allocation: [[1.0]] ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┃ ┃ ║ │ ┃ ║\n ║ ┃ │ ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║ │ ┃ ║\n ║ ┃ │ ║ ║ │ ┃ ║\n ║ ┃ │ ╚══════════════════════════════════════════════════════════════╝ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──────────────── Time Step 1 ─────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭───── oController Objective Mechanism ─────╮ │ ┃ ║\n ║ ┃ │ │ input: -2.0 │ │ ┃ ║\n ║ ┃ │ │ ╭─────────────── params ────────────────╮ │ │ ┃ ║\n ║ ┃ │ │ │ value: -8. (monitored by oController) │ │ │ ┃ ║\n ║ ┃ │ │ │ │ │ │ ┃ ║\n ║ ┃ │ │ ╰───────────────────────────────────────╯ │ │ ┃ ║\n ║ ┃ │ │ output: -8.0 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[-2.0]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════════════════════════════════════════╝\n\n' assert actual_output == expected_output icomp.controller.reportOutputPref = ReportOutput.ON @@ -555,6 +555,7 @@ def test_nested_comps_and_sims_with_modulated_and_monitored_params_and_use_prefs @pytest.mark.pytorch def test_autodiff_report(self): + xor_in = pnl.TransferMechanism(name='xor_in', default_variable=np.zeros(2)) @@ -626,7 +627,7 @@ def test_autodiff_report(self): report_progress=ReportProgress.ON, report_to_devices=ReportDevices.DIVERT) actual_report = xor.rich_diverted_reports - expected_report = '\n ╔══ EXECUTION OF autodiff_composition ═══╗\n ║ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 0 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9933057795354014]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 1 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.999331787548446]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 2 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993317875516309]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 3 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9998504229552773]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 4 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9933055512239266]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 5 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993317539824547]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 6 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993317539856401]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 7 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9998504138991838]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 8 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9933053228968025]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 9 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993317204136144]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 10 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993317204168003]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 11 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.999850404842228]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════╝\n\nautodiff_composition: Trained 12 trials\n' + expected_report = '\n ╔══ EXECUTION OF autodiff_composition ═══╗\n ║ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 0 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9933057795354014]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 1 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.999331787548446]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 2 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993317875516309]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 3 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9998504229552773]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 4 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9933055512239266]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 5 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993317539824547]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 6 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993317539856401]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 7 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9998504138991838]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 8 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9933053228968025]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 9 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993317204136144]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 10 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993317204168003]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 11 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.999850404842228]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════╝\n\nautodiff_composition: Trained 12 trials\n' assert actual_report == expected_report xor.run(inputs={xor_in:xor_inputs}, @@ -635,7 +636,7 @@ def test_autodiff_report(self): report_to_devices=ReportDevices.DIVERT ) actual_report = xor.rich_diverted_reports - expected_report = '\n ╔════════════════════ EXECUTION OF autodiff_composition ═════════════════════╗\n ║ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━ autodiff_composition: Trial 0 ━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[0, 0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──── Time Step 0 ────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭───── xor_in ─────╮ │ ┃ ║\n ║ ┃ │ │ input: [[0. 0.]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.0 0.0 │ │ ┃ ║\n ║ ┃ │ ╰──────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └──────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌─────────────────── Time Step 1 ────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭──────────────────── xor_hid ────────────────────╮ │ ┃ ║\n ║ ┃ │ │ input: [[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 │ │ ┃ ║\n ║ ┃ │ ╰─────────────────────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └─────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌── Time Step 2 ───┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─── xor_out ───╮ │ ┃ ║\n ║ ┃ │ │ input: 5.0 │ │ ┃ ║\n ║ ┃ │ │ output: 0.993 │ │ ┃ ║\n ║ ┃ │ ╰───────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9933050945540283]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━ autodiff_composition: Trial 1 ━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[0, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──── Time Step 0 ────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭───── xor_in ─────╮ │ ┃ ║\n ║ ┃ │ │ input: [[0. 1.]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.0 1.0 │ │ ┃ ║\n ║ ┃ │ ╰──────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └──────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 1 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─────────────────────────── xor_hid ───────────────────────────╮ │ ┃ ║\n ║ ┃ │ │ input: [[0.99999972 0.99999972 0.99999972 0.99999972 │ │ ┃ ║\n ║ ┃ │ │ 0.99999972 0.99999972 │ │ ┃ ║\n ║ ┃ │ │ 0.99999972 0.99999972 0.99999972 0.99999972]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.731 0.731 0.731 0.731 0.731 0.731 0.731 0.731 0.731 │ │ ┃ ║\n ║ ┃ │ │ 0.731 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌── Time Step 2 ───┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─── xor_out ───╮ │ ┃ ║\n ║ ┃ │ │ input: 7.31 │ │ ┃ ║\n ║ ┃ │ │ output: 0.999 │ │ ┃ ║\n ║ ┃ │ ╰───────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993317190927715]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━ autodiff_composition: Trial 2 ━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──── Time Step 0 ────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭───── xor_in ─────╮ │ ┃ ║\n ║ ┃ │ │ input: [[1. 0.]] │ │ ┃ ║\n ║ ┃ │ │ output: 1.0 0.0 │ │ ┃ ║\n ║ ┃ │ ╰──────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └──────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 1 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─────────────────────────── xor_hid ───────────────────────────╮ │ ┃ ║\n ║ ┃ │ │ input: [[0.99999972 0.99999972 0.99999972 0.99999972 │ │ ┃ ║\n ║ ┃ │ │ 0.99999972 0.99999972 │ │ ┃ ║\n ║ ┃ │ │ 0.99999972 0.99999972 0.99999972 0.99999972]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.731 0.731 0.731 0.731 0.731 0.731 0.731 0.731 0.731 │ │ ┃ ║\n ║ ┃ │ │ 0.731 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌── Time Step 2 ───┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─── xor_out ───╮ │ ┃ ║\n ║ ┃ │ │ input: 7.31 │ │ ┃ ║\n ║ ┃ │ │ output: 0.999 │ │ ┃ ║\n ║ ┃ │ ╰───────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993317190927715]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━ autodiff_composition: Trial 3 ━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──── Time Step 0 ────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭───── xor_in ─────╮ │ ┃ ║\n ║ ┃ │ │ input: [[1. 1.]] │ │ ┃ ║\n ║ ┃ │ │ output: 1.0 1.0 │ │ ┃ ║\n ║ ┃ │ ╰──────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └──────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 1 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─────────────────────────── xor_hid ───────────────────────────╮ │ ┃ ║\n ║ ┃ │ │ input: [[1.99999944 1.99999944 1.99999944 1.99999944 │ │ ┃ ║\n ║ ┃ │ │ 1.99999944 1.99999944 │ │ ┃ ║\n ║ ┃ │ │ 1.99999944 1.99999944 1.99999944 1.99999944]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.881 0.881 0.881 0.881 0.881 0.881 0.881 0.881 0.881 │ │ ┃ ║\n ║ ┃ │ │ 0.881 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌─ Time Step 2 ──┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭── xor_out ──╮ │ ┃ ║\n ║ ┃ │ │ input: 8.81 │ │ ┃ ║\n ║ ┃ │ │ output: 1.0 │ │ ┃ ║\n ║ ┃ │ ╰─────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └─────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9998504044852918]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════════════════════════════════════════╝\n\nautodiff_composition: Executed 4 of 4 trials\n' + expected_report = '\n ╔════════════════════ EXECUTION OF autodiff_composition ═════════════════════╗\n ║ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━ autodiff_composition: Trial 0 ━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[0.0, 0.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──── Time Step 0 ────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭───── xor_in ─────╮ │ ┃ ║\n ║ ┃ │ │ input: [[0. 0.]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.0 0.0 │ │ ┃ ║\n ║ ┃ │ ╰──────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └──────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌─────────────────── Time Step 1 ────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭──────────────────── xor_hid ────────────────────╮ │ ┃ ║\n ║ ┃ │ │ input: [[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 │ │ ┃ ║\n ║ ┃ │ ╰─────────────────────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └─────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌── Time Step 2 ───┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─── xor_out ───╮ │ ┃ ║\n ║ ┃ │ │ input: 5.0 │ │ ┃ ║\n ║ ┃ │ │ output: 0.993 │ │ ┃ ║\n ║ ┃ │ ╰───────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9933050945540283]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━ autodiff_composition: Trial 1 ━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[0.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──── Time Step 0 ────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭───── xor_in ─────╮ │ ┃ ║\n ║ ┃ │ │ input: [[0. 1.]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.0 1.0 │ │ ┃ ║\n ║ ┃ │ ╰──────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └──────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 1 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─────────────────────────── xor_hid ───────────────────────────╮ │ ┃ ║\n ║ ┃ │ │ input: [[0.99999972 0.99999972 0.99999972 0.99999972 │ │ ┃ ║\n ║ ┃ │ │ 0.99999972 0.99999972 │ │ ┃ ║\n ║ ┃ │ │ 0.99999972 0.99999972 0.99999972 0.99999972]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.731 0.731 0.731 0.731 0.731 0.731 0.731 0.731 0.731 │ │ ┃ ║\n ║ ┃ │ │ 0.731 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌── Time Step 2 ───┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─── xor_out ───╮ │ ┃ ║\n ║ ┃ │ │ input: 7.31 │ │ ┃ ║\n ║ ┃ │ │ output: 0.999 │ │ ┃ ║\n ║ ┃ │ ╰───────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993317190927715]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━ autodiff_composition: Trial 2 ━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 0.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──── Time Step 0 ────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭───── xor_in ─────╮ │ ┃ ║\n ║ ┃ │ │ input: [[1. 0.]] │ │ ┃ ║\n ║ ┃ │ │ output: 1.0 0.0 │ │ ┃ ║\n ║ ┃ │ ╰──────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └──────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 1 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─────────────────────────── xor_hid ───────────────────────────╮ │ ┃ ║\n ║ ┃ │ │ input: [[0.99999972 0.99999972 0.99999972 0.99999972 │ │ ┃ ║\n ║ ┃ │ │ 0.99999972 0.99999972 │ │ ┃ ║\n ║ ┃ │ │ 0.99999972 0.99999972 0.99999972 0.99999972]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.731 0.731 0.731 0.731 0.731 0.731 0.731 0.731 0.731 │ │ ┃ ║\n ║ ┃ │ │ 0.731 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌── Time Step 2 ───┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─── xor_out ───╮ │ ┃ ║\n ║ ┃ │ │ input: 7.31 │ │ ┃ ║\n ║ ┃ │ │ output: 0.999 │ │ ┃ ║\n ║ ┃ │ ╰───────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993317190927715]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━ autodiff_composition: Trial 3 ━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──── Time Step 0 ────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭───── xor_in ─────╮ │ ┃ ║\n ║ ┃ │ │ input: [[1. 1.]] │ │ ┃ ║\n ║ ┃ │ │ output: 1.0 1.0 │ │ ┃ ║\n ║ ┃ │ ╰──────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └──────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 1 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─────────────────────────── xor_hid ───────────────────────────╮ │ ┃ ║\n ║ ┃ │ │ input: [[1.99999944 1.99999944 1.99999944 1.99999944 │ │ ┃ ║\n ║ ┃ │ │ 1.99999944 1.99999944 │ │ ┃ ║\n ║ ┃ │ │ 1.99999944 1.99999944 1.99999944 1.99999944]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.881 0.881 0.881 0.881 0.881 0.881 0.881 0.881 0.881 │ │ ┃ ║\n ║ ┃ │ │ 0.881 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌─ Time Step 2 ──┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭── xor_out ──╮ │ ┃ ║\n ║ ┃ │ │ input: 8.81 │ │ ┃ ║\n ║ ┃ │ │ output: 1.0 │ │ ┃ ║\n ║ ┃ │ ╰─────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └─────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9998504044852918]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════════════════════════════════════════╝\n\nautodiff_composition: Executed 4 of 4 trials\n' assert actual_report == expected_report xor.learn(inputs= training_inputs, @@ -660,7 +661,7 @@ def test_autodiff_report(self): report_progress=ReportProgress.OFF, report_to_devices=ReportDevices.DIVERT) actual_report = xor.rich_diverted_reports - expected_report = '\n ╔══ EXECUTION OF autodiff_composition ═══╗\n ║ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 0 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9933044094317858]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 1 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993315861097587]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 2 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993315861129465]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 3 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9998503686057807]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 4 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9933041810263933]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 5 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.999331552526669]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 6 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993315525298574]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 7 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9998503595445122]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 8 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9933039526053421]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 9 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993315189407287]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 10 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993315189439175]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 11 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9998503504823807]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════╝\n\n' + expected_report = '\n ╔══ EXECUTION OF autodiff_composition ═══╗\n ║ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 0 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9933044094317858]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 1 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993315861097587]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 2 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993315861129465]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 3 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9998503686057807]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 4 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9933041810263933]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 5 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.999331552526669]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 6 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993315525298574]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 7 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9998503595445122]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 8 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9933039526053421]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 9 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993315189407287]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 10 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9993315189439175]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━ autodiff_composition: Trial 11 ━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9998503504823807]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════╝\n\n' assert actual_report == expected_report xor.run(inputs={xor_in:xor_inputs}, @@ -669,5 +670,5 @@ def test_autodiff_report(self): report_to_devices=ReportDevices.DIVERT ) actual_report = xor.rich_diverted_reports - expected_report = '\n ╔════════════════════ EXECUTION OF autodiff_composition ═════════════════════╗\n ║ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━ autodiff_composition: Trial 0 ━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[0, 0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──── Time Step 0 ────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭───── xor_in ─────╮ │ ┃ ║\n ║ ┃ │ │ input: [[0. 0.]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.0 0.0 │ │ ┃ ║\n ║ ┃ │ ╰──────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └──────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌─────────────────── Time Step 1 ────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭──────────────────── xor_hid ────────────────────╮ │ ┃ ║\n ║ ┃ │ │ input: [[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 │ │ ┃ ║\n ║ ┃ │ ╰─────────────────────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └─────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌── Time Step 2 ───┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─── xor_out ───╮ │ ┃ ║\n ║ ┃ │ │ input: 5.0 │ │ ┃ ║\n ║ ┃ │ │ output: 0.993 │ │ ┃ ║\n ║ ┃ │ ╰───────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9933037241686309]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━ autodiff_composition: Trial 1 ━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[0, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──── Time Step 0 ────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭───── xor_in ─────╮ │ ┃ ║\n ║ ┃ │ │ input: [[0. 1.]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.0 1.0 │ │ ┃ ║\n ║ ┃ │ ╰──────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └──────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 1 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─────────────────────────── xor_hid ───────────────────────────╮ │ ┃ ║\n ║ ┃ │ │ input: [[0.99999953 0.99999953 0.99999953 0.99999953 │ │ ┃ ║\n ║ ┃ │ │ 0.99999953 0.99999953 │ │ ┃ ║\n ║ ┃ │ │ 0.99999953 0.99999953 0.99999953 0.99999953]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.731 0.731 0.731 0.731 0.731 0.731 0.731 0.731 0.731 │ │ ┃ ║\n ║ ┃ │ │ 0.731 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌── Time Step 2 ───┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─── xor_out ───╮ │ ┃ ║\n ║ ┃ │ │ input: 7.31 │ │ ┃ ║\n ║ ┃ │ │ output: 0.999 │ │ ┃ ║\n ║ ┃ │ ╰───────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.999331517619013]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━ autodiff_composition: Trial 2 ━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──── Time Step 0 ────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭───── xor_in ─────╮ │ ┃ ║\n ║ ┃ │ │ input: [[1. 0.]] │ │ ┃ ║\n ║ ┃ │ │ output: 1.0 0.0 │ │ ┃ ║\n ║ ┃ │ ╰──────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └──────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 1 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─────────────────────────── xor_hid ───────────────────────────╮ │ ┃ ║\n ║ ┃ │ │ input: [[0.99999953 0.99999953 0.99999953 0.99999953 │ │ ┃ ║\n ║ ┃ │ │ 0.99999953 0.99999953 │ │ ┃ ║\n ║ ┃ │ │ 0.99999953 0.99999953 0.99999953 0.99999953]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.731 0.731 0.731 0.731 0.731 0.731 0.731 0.731 0.731 │ │ ┃ ║\n ║ ┃ │ │ 0.731 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌── Time Step 2 ───┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─── xor_out ───╮ │ ┃ ║\n ║ ┃ │ │ input: 7.31 │ │ ┃ ║\n ║ ┃ │ │ output: 0.999 │ │ ┃ ║\n ║ ┃ │ ╰───────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.999331517619013]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━ autodiff_composition: Trial 3 ━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1, 1], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──── Time Step 0 ────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭───── xor_in ─────╮ │ ┃ ║\n ║ ┃ │ │ input: [[1. 1.]] │ │ ┃ ║\n ║ ┃ │ │ output: 1.0 1.0 │ │ ┃ ║\n ║ ┃ │ ╰──────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └──────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 1 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─────────────────────────── xor_hid ───────────────────────────╮ │ ┃ ║\n ║ ┃ │ │ input: [[1.99999906 1.99999906 1.99999906 1.99999906 │ │ ┃ ║\n ║ ┃ │ │ 1.99999906 1.99999906 │ │ ┃ ║\n ║ ┃ │ │ 1.99999906 1.99999906 1.99999906 1.99999906]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.881 0.881 0.881 0.881 0.881 0.881 0.881 0.881 0.881 │ │ ┃ ║\n ║ ┃ │ │ 0.881 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌─ Time Step 2 ──┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭── xor_out ──╮ │ ┃ ║\n ║ ┃ │ │ input: 8.81 │ │ ┃ ║\n ║ ┃ │ │ output: 1.0 │ │ ┃ ║\n ║ ┃ │ ╰─────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └─────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9998503501251857]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════════════════════════════════════════╝\n\n' + expected_report = '\n ╔════════════════════ EXECUTION OF autodiff_composition ═════════════════════╗\n ║ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━ autodiff_composition: Trial 0 ━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[0.0, 0.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──── Time Step 0 ────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭───── xor_in ─────╮ │ ┃ ║\n ║ ┃ │ │ input: [[0. 0.]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.0 0.0 │ │ ┃ ║\n ║ ┃ │ ╰──────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └──────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌─────────────────── Time Step 1 ────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭──────────────────── xor_hid ────────────────────╮ │ ┃ ║\n ║ ┃ │ │ input: [[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 │ │ ┃ ║\n ║ ┃ │ ╰─────────────────────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └─────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌── Time Step 2 ───┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─── xor_out ───╮ │ ┃ ║\n ║ ┃ │ │ input: 5.0 │ │ ┃ ║\n ║ ┃ │ │ output: 0.993 │ │ ┃ ║\n ║ ┃ │ ╰───────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9933037241686309]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━ autodiff_composition: Trial 1 ━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[0.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──── Time Step 0 ────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭───── xor_in ─────╮ │ ┃ ║\n ║ ┃ │ │ input: [[0. 1.]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.0 1.0 │ │ ┃ ║\n ║ ┃ │ ╰──────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └──────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 1 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─────────────────────────── xor_hid ───────────────────────────╮ │ ┃ ║\n ║ ┃ │ │ input: [[0.99999953 0.99999953 0.99999953 0.99999953 │ │ ┃ ║\n ║ ┃ │ │ 0.99999953 0.99999953 │ │ ┃ ║\n ║ ┃ │ │ 0.99999953 0.99999953 0.99999953 0.99999953]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.731 0.731 0.731 0.731 0.731 0.731 0.731 0.731 0.731 │ │ ┃ ║\n ║ ┃ │ │ 0.731 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌── Time Step 2 ───┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─── xor_out ───╮ │ ┃ ║\n ║ ┃ │ │ input: 7.31 │ │ ┃ ║\n ║ ┃ │ │ output: 0.999 │ │ ┃ ║\n ║ ┃ │ ╰───────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.999331517619013]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━ autodiff_composition: Trial 2 ━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 0.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──── Time Step 0 ────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭───── xor_in ─────╮ │ ┃ ║\n ║ ┃ │ │ input: [[1. 0.]] │ │ ┃ ║\n ║ ┃ │ │ output: 1.0 0.0 │ │ ┃ ║\n ║ ┃ │ ╰──────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └──────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 1 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─────────────────────────── xor_hid ───────────────────────────╮ │ ┃ ║\n ║ ┃ │ │ input: [[0.99999953 0.99999953 0.99999953 0.99999953 │ │ ┃ ║\n ║ ┃ │ │ 0.99999953 0.99999953 │ │ ┃ ║\n ║ ┃ │ │ 0.99999953 0.99999953 0.99999953 0.99999953]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.731 0.731 0.731 0.731 0.731 0.731 0.731 0.731 0.731 │ │ ┃ ║\n ║ ┃ │ │ 0.731 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌── Time Step 2 ───┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─── xor_out ───╮ │ ┃ ║\n ║ ┃ │ │ input: 7.31 │ │ ┃ ║\n ║ ┃ │ │ output: 0.999 │ │ ┃ ║\n ║ ┃ │ ╰───────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.999331517619013]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ║ ┏━━━━━━━━━━━━━━━━━━━ autodiff_composition: Trial 3 ━━━━━━━━━━━━━━━━━━━━┓ ║\n ║ ┃ ┃ ║\n ║ ┃ input: [[1.0, 1.0], [0.5]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌──── Time Step 0 ────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭───── xor_in ─────╮ │ ┃ ║\n ║ ┃ │ │ input: [[1. 1.]] │ │ ┃ ║\n ║ ┃ │ │ output: 1.0 1.0 │ │ ┃ ║\n ║ ┃ │ ╰──────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └──────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌────────────────────────── Time Step 1 ───────────────────────────┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭─────────────────────────── xor_hid ───────────────────────────╮ │ ┃ ║\n ║ ┃ │ │ input: [[1.99999906 1.99999906 1.99999906 1.99999906 │ │ ┃ ║\n ║ ┃ │ │ 1.99999906 1.99999906 │ │ ┃ ║\n ║ ┃ │ │ 1.99999906 1.99999906 1.99999906 1.99999906]] │ │ ┃ ║\n ║ ┃ │ │ output: 0.881 0.881 0.881 0.881 0.881 0.881 0.881 0.881 0.881 │ │ ┃ ║\n ║ ┃ │ │ 0.881 │ │ ┃ ║\n ║ ┃ │ ╰───────────────────────────────────────────────────────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └───────────────────────────────────────────────────────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ ┌─ Time Step 2 ──┐ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ │ ╭── xor_out ──╮ │ ┃ ║\n ║ ┃ │ │ input: 8.81 │ │ ┃ ║\n ║ ┃ │ │ output: 1.0 │ │ ┃ ║\n ║ ┃ │ ╰─────────────╯ │ ┃ ║\n ║ ┃ │ │ ┃ ║\n ║ ┃ └─────────────────┘ ┃ ║\n ║ ┃ ┃ ║\n ║ ┃ result: [[0.9998503501251857]] ┃ ║\n ║ ┃ ┃ ║\n ║ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ║\n ║ ║\n ╚═════════════════════════════════════════════════════════════════════════════╝\n\n' assert actual_report == expected_report diff --git a/tests/composition/test_show_graph.py b/tests/composition/test_show_graph.py index 40a235a97cd..65836803fcb 100644 --- a/tests/composition/test_show_graph.py +++ b/tests/composition/test_show_graph.py @@ -3,6 +3,7 @@ from psyneulink.core.components.functions.nonstateful.learningfunctions import BackPropagation from psyneulink.core.components.functions.nonstateful.transferfunctions import Linear +from psyneulink.core.components.functions.nonstateful.optimizationfunctions import GridSearch from psyneulink.core.components.functions.stateful.memoryfunctions import DictionaryMemory from psyneulink.core.components.functions.stateful.memoryfunctions import STORAGE_PROB from psyneulink.core.components.mechanisms.modulatory.control.controlmechanism import ControlMechanism @@ -241,11 +242,11 @@ def test_converging_pathways(self): ), ( {'show_controller': True}, - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\tia [color=green penwidth=3 rank=source shape=oval]\n\tia -> ib [label="" arrowhead=normal color=black penwidth=1]\n\t"my ocm" -> ia [label="" arrowhead=box color=purple penwidth=1]\n\t"my ocm" -> ia [label="" arrowhead=box color=purple penwidth=1]\n\t"my ocm" -> ib [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> "my ocm" [label="" arrowhead=normal color=purple penwidth=1]\n\tib [color=red penwidth=3 rank=max shape=oval]\n\t"my ocm" [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}' + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\tia [color=green penwidth=3 rank=source shape=oval]\n\tia -> ib [label="" arrowhead=normal color=black penwidth=1]\n\t"my ocm" -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"my ocm" -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"my ocm" -> ib [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> "my ocm" [label="" arrowhead=normal color=purple penwidth=1]\n\tib [color=red penwidth=3 rank=max shape=oval]\n\t"my ocm" [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}' ), ( {'show_controller': True, 'show_node_structure': True}, - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tia:"OutputPort-RESULT" -> ib:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"my ocm":"OutputPort-ia[noise] ControlSignal" -> ia:"ParameterPort-noise" [label="" arrowhead=box color=purple penwidth=1]\n\t"my ocm":"OutputPort-ia[intercept] ControlSignal" -> ia:"ParameterPort-intercept" [label="" arrowhead=box color=purple penwidth=1]\n\t"my ocm":"OutputPort-ib[slope] ControlSignal" -> ib:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ia_InputPort-0" -> "my ocm":"InputPort-Shadowed input of of ia[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\tib [label=<
RESULT
OutputPorts
Mechanism:
ib
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\t"my ocm" [label=<
ia[noise] ControlSignalia[intercept] ControlSignalib[slope] ControlSignal
OutputPorts
Mechanism:
my ocm
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of ia[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}' + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tia:"OutputPort-RESULT" -> ib:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"my ocm":"OutputPort-ia[noise] ControlSignal" -> ia:"ParameterPort-noise" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"my ocm":"OutputPort-ia[intercept] ControlSignal" -> ia:"ParameterPort-intercept" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"my ocm":"OutputPort-ib[slope] ControlSignal" -> ib:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ia_InputPort-0" -> "my ocm":"InputPort-SHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\tib [label=<
RESULT
OutputPorts
Mechanism:
ib
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\t"my ocm" [label=<
ia[noise] ControlSignalia[intercept] ControlSignalib[slope] ControlSignal
OutputPorts
Mechanism:
my ocm
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}' ) ] @@ -295,7 +296,7 @@ def test_no_nested_and_controler_name_with_space_in_it( ), ( {'show_nested': 2, 'show_cim': True, 'show_node_structure': True}, - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\toa:"OutputPort-RESULT" -> "mcomp INPUT_CIM":"InputPort-INPUT_CIM_ma_InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tctl_mech:"OutputPort-ma[slope] ControlSignal" -> "mcomp PARAMETER_CIM":"InputPort-PARAMETER_CIM_ma_slope" [label="" arrowhead=normal color=blue penwidth=1]\n\t"mcomp OUTPUT_CIM":"OutputPort-OUTPUT_CIM_mb_RESULT" -> ob:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tob:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [label=<
INPUT_CIM_oa_InputPort-0
OutputPorts
Mechanism:
ocomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> oa:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp OUTPUT_CIM" [label=<
Mechanism:
ocomp Output_CIM
InputPorts
OUTPUT_CIM_ob_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\tob:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ob_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ma[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tsubgraph cluster_mcomp {\n\t\tgraph [label=mcomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tma [label=<
RESULT
OutputPorts
Mechanism:
ma
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\tma:"OutputPort-RESULT" -> "icomp INPUT_CIM":"InputPort-INPUT_CIM_ia_InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"icomp OUTPUT_CIM":"OutputPort-OUTPUT_CIM_ib_RESULT" -> mb:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"mcomp INPUT_CIM" [label=<
INPUT_CIM_ma_InputPort-0
OutputPorts
Mechanism:
mcomp Input_CIM
InputPorts
INPUT_CIM_ma_InputPort-0
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"mcomp INPUT_CIM":"OutputPort-INPUT_CIM_ma_InputPort-0" -> ma:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"mcomp PARAMETER_CIM" [label=<
PARAMETER_CIM_ma_slope
OutputPorts
Mechanism:
mcomp Parameter_CIM
InputPorts
PARAMETER_CIM_ma_slope
> color=blue penwidth=1 rank=same shape=plaintext]\n\t\t"mcomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ma_slope" -> ma:"ParameterPort-slope" [label="" arrowhead=box color=blue penwidth=1]\n\t\t"mcomp OUTPUT_CIM" [label=<
OUTPUT_CIM_mb_RESULT
OutputPorts
Mechanism:
mcomp Output_CIM
InputPorts
OUTPUT_CIM_mb_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\t\tmb:"OutputPort-RESULT" -> "mcomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_mb_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\t\tmb [label=<
RESULT
OutputPorts
Mechanism:
mb
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\t\tsubgraph cluster_icomp {\n\t\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\t\tedge [fontname=arial fontsize=10]\n\t\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\t\tia:"OutputPort-RESULT" -> ib:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t\t"icomp INPUT_CIM" [label=<
INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
icomp Input_CIM
InputPorts
INPUT_CIM_ia_InputPort-0
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t\t"icomp INPUT_CIM":"OutputPort-INPUT_CIM_ia_InputPort-0" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t\t"icomp OUTPUT_CIM" [label=<
OUTPUT_CIM_ib_RESULT
OutputPorts
Mechanism:
icomp Output_CIM
InputPorts
OUTPUT_CIM_ib_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\t\t\tib:"OutputPort-RESULT" -> "icomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ib_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\t\t\tib [label=<
RESULT
OutputPorts
Mechanism:
ib
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\t\t\tlabel=icomp\n\t\t}\n\t\tlabel=mcomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\toa:"OutputPort-RESULT" -> "mcomp INPUT_CIM":"InputPort-INPUT_CIM_ma_InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tctl_mech:"OutputPort-ma[slope] ControlSignal" -> "mcomp PARAMETER_CIM":"InputPort-PARAMETER_CIM_ma_slope" [label="" arrowhead=normal color=blue penwidth=1 style=solid]\n\t"mcomp OUTPUT_CIM":"OutputPort-OUTPUT_CIM_mb_RESULT" -> ob:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tob:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [label=<
INPUT_CIM_oa_InputPort-0
OutputPorts
Mechanism:
ocomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> oa:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp OUTPUT_CIM" [label=<
Mechanism:
ocomp Output_CIM
InputPorts
OUTPUT_CIM_ob_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\tob:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ob_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ma[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tsubgraph cluster_mcomp {\n\t\tgraph [label=mcomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tma [label=<
RESULT
OutputPorts
Mechanism:
ma
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\tma:"OutputPort-RESULT" -> "icomp INPUT_CIM":"InputPort-INPUT_CIM_ia_InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"icomp OUTPUT_CIM":"OutputPort-OUTPUT_CIM_ib_RESULT" -> mb:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"mcomp INPUT_CIM" [label=<
INPUT_CIM_ma_InputPort-0
OutputPorts
Mechanism:
mcomp Input_CIM
InputPorts
INPUT_CIM_ma_InputPort-0
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"mcomp INPUT_CIM":"OutputPort-INPUT_CIM_ma_InputPort-0" -> ma:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"mcomp PARAMETER_CIM" [label=<
PARAMETER_CIM_ma_slope
OutputPorts
Mechanism:
mcomp Parameter_CIM
InputPorts
PARAMETER_CIM_ma_slope
> color=blue penwidth=1 rank=same shape=plaintext]\n\t\t"mcomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ma_slope" -> ma:"ParameterPort-slope" [label="" arrowhead=box color=blue penwidth=1 style=solid]\n\t\t"mcomp OUTPUT_CIM" [label=<
OUTPUT_CIM_mb_RESULT
OutputPorts
Mechanism:
mcomp Output_CIM
InputPorts
OUTPUT_CIM_mb_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\t\tmb:"OutputPort-RESULT" -> "mcomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_mb_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tmb [label=<
RESULT
OutputPorts
Mechanism:
mb
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\t\tsubgraph cluster_icomp {\n\t\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\t\tedge [fontname=arial fontsize=10]\n\t\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\t\tia:"OutputPort-RESULT" -> ib:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t\t"icomp INPUT_CIM" [label=<
INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
icomp Input_CIM
InputPorts
INPUT_CIM_ia_InputPort-0
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t\t"icomp INPUT_CIM":"OutputPort-INPUT_CIM_ia_InputPort-0" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t\t"icomp OUTPUT_CIM" [label=<
OUTPUT_CIM_ib_RESULT
OutputPorts
Mechanism:
icomp Output_CIM
InputPorts
OUTPUT_CIM_ib_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\t\t\tib:"OutputPort-RESULT" -> "icomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ib_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t\tib [label=<
RESULT
OutputPorts
Mechanism:
ib
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\t\t\tlabel=icomp\n\t\t}\n\t\tlabel=mcomp\n\t}\n}', ), ] @@ -338,11 +339,11 @@ def test_multiple_nesting_levels_with_control_mech_projection_one_level_deep( ), ( {'show_nested': False, 'show_cim': True, 'show_learning': True}, - 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"OUTER INPUT" [color=green penwidth=3 rank=source shape=oval]\n\tINTERNAL [color=black penwidth=1 rank=same shape=oval]\n\t"OUTER INPUT" -> INTERNAL [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" [color=pink penwidth=3 rank=same shape=rectangle]\n\tINTERNAL -> "NESTED COMPOSITION" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" -> "OUTER OUTPUT" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"COMPOSITION INPUT_CIM" -> "OUTER INPUT" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t"OUTER OUTPUT" -> "COMPOSITION OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\t"OUTER OUTPUT" [color=red penwidth=3 rank=max shape=oval]\n}', + 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"OUTER INPUT" [color=green penwidth=3 rank=source shape=oval]\n\tINTERNAL [color=black penwidth=1 rank=same shape=oval]\n\t"OUTER INPUT" -> INTERNAL [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" [color=pink penwidth=3 rank=same shape=rectangle]\n\tINTERNAL -> "NESTED COMPOSITION" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" -> "OUTER OUTPUT" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"COMPOSITION INPUT_CIM" -> "OUTER INPUT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"COMPOSITION OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t"OUTER OUTPUT" -> "COMPOSITION OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OUTER OUTPUT" [color=red penwidth=3 rank=max shape=oval]\n}', ), ( {'show_nested': NESTED, 'show_cim': True, 'show_learning': True}, - 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"OUTER INPUT" [color=green penwidth=3 rank=source shape=oval]\n\tINTERNAL [color=black penwidth=1 rank=same shape=oval]\n\t"OUTER INPUT" -> INTERNAL [label="" arrowhead=normal color=black penwidth=1]\n\tINTERNAL -> "NESTED COMPOSITION INPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION OUTPUT_CIM" -> "OUTER OUTPUT" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"COMPOSITION INPUT_CIM" -> "OUTER INPUT" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t"OUTER OUTPUT" -> "COMPOSITION OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\t"OUTER OUTPUT" [color=red penwidth=3 rank=max shape=oval]\n\tsubgraph "cluster_NESTED COMPOSITION" {\n\t\tgraph [label="NESTED COMPOSITION" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tTarget [color=orange penwidth=3 rank=min shape=oval]\n\t\t"INNER INPUT" [color=green penwidth=3 rank=source shape=oval]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [color=black penwidth=1 shape=diamond]\n\t\t"INNER INPUT" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [arrowhead=none color=black penwidth=1]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" -> "INNER OUTPUT" [color=black penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" color=orange penwidth=1]\n\t\t"NESTED COMPOSITION INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t"NESTED COMPOSITION INPUT_CIM" -> "INNER INPUT" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"NESTED COMPOSITION INPUT_CIM" -> Target [label="" arrowhead=normal color=black penwidth=1]\n\t\t"NESTED COMPOSITION OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\t"INNER OUTPUT" -> "NESTED COMPOSITION OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\t\tComparator [color=orange penwidth=1 rank=min shape=oval]\n\t\t"INNER OUTPUT" -> Comparator [label="" arrowhead=normal color=orange penwidth=1]\n\t\tTarget -> Comparator [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [color=orange penwidth=1 rank=min shape=oval]\n\t\tComparator -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER INPUT" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT" [color=red penwidth=3 rank=max shape=oval]\n\t\tlabel="NESTED COMPOSITION"\n\t}\n}', + 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"OUTER INPUT" [color=green penwidth=3 rank=source shape=oval]\n\tINTERNAL [color=black penwidth=1 rank=same shape=oval]\n\t"OUTER INPUT" -> INTERNAL [label="" arrowhead=normal color=black penwidth=1]\n\tINTERNAL -> "NESTED COMPOSITION INPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"NESTED COMPOSITION OUTPUT_CIM" -> "OUTER OUTPUT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"COMPOSITION INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"COMPOSITION INPUT_CIM" -> "OUTER INPUT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"COMPOSITION OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t"OUTER OUTPUT" -> "COMPOSITION OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OUTER OUTPUT" [color=red penwidth=3 rank=max shape=oval]\n\tsubgraph "cluster_NESTED COMPOSITION" {\n\t\tgraph [label="NESTED COMPOSITION" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tTarget [color=orange penwidth=3 rank=min shape=oval]\n\t\t"INNER INPUT" [color=green penwidth=3 rank=source shape=oval]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [color=black penwidth=1 shape=diamond]\n\t\t"INNER INPUT" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [arrowhead=none color=black penwidth=1]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" -> "INNER OUTPUT" [color=black penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" color=orange penwidth=1]\n\t\t"NESTED COMPOSITION INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t"NESTED COMPOSITION INPUT_CIM" -> "INNER INPUT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"NESTED COMPOSITION INPUT_CIM" -> Target [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"NESTED COMPOSITION OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\t"INNER OUTPUT" -> "NESTED COMPOSITION OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tComparator [color=orange penwidth=1 rank=min shape=oval]\n\t\t"INNER OUTPUT" -> Comparator [label="" arrowhead=normal color=orange penwidth=1]\n\t\tTarget -> Comparator [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [color=orange penwidth=1 rank=min shape=oval]\n\t\tComparator -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER INPUT" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT" [color=red penwidth=3 rank=max shape=oval]\n\t\tlabel="NESTED COMPOSITION"\n\t}\n}', ), ( {'show_nested': False, 'show_cim': False, 'show_node_structure': True, 'show_learning': True}, @@ -354,11 +355,11 @@ def test_multiple_nesting_levels_with_control_mech_projection_one_level_deep( ), ( {'show_nested': False, 'show_cim': True, 'show_node_structure': True, 'show_learning': True}, - 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"OUTER INPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER INPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tINTERNAL [label=<
OutputPort-0
OutputPorts
Mechanism:
INTERNAL
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=black penwidth=1 rank=same shape=plaintext]\n\t"OUTER INPUT":"OutputPort-OutputPort-0" -> INTERNAL:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" [color=pink penwidth=3 rank=same shape=rectangle]\n\tINTERNAL:"OutputPort-OutputPort-0" -> "NESTED COMPOSITION" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" -> "OUTER OUTPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION INPUT_CIM" [label=<
INPUT_CIM_OUTER INPUT_InputPort-0
OutputPorts
Mechanism:
COMPOSITION Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_OUTER INPUT_InputPort-0" -> "OUTER INPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION OUTPUT_CIM" [label=<
Mechanism:
COMPOSITION Output_CIM
InputPorts
OUTPUT_CIM_OUTER OUTPUT_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t"OUTER OUTPUT":"OutputPort-OutputPort-0" -> "COMPOSITION OUTPUT_CIM":"InputPort-OUTPUT_CIM_OUTER OUTPUT_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"OUTER OUTPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER OUTPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n}', + 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"OUTER INPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER INPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tINTERNAL [label=<
OutputPort-0
OutputPorts
Mechanism:
INTERNAL
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=black penwidth=1 rank=same shape=plaintext]\n\t"OUTER INPUT":"OutputPort-OutputPort-0" -> INTERNAL:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" [color=pink penwidth=3 rank=same shape=rectangle]\n\tINTERNAL:"OutputPort-OutputPort-0" -> "NESTED COMPOSITION" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" -> "OUTER OUTPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION INPUT_CIM" [label=<
INPUT_CIM_OUTER INPUT_InputPort-0
OutputPorts
Mechanism:
COMPOSITION Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_OUTER INPUT_InputPort-0" -> "OUTER INPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"COMPOSITION OUTPUT_CIM" [label=<
Mechanism:
COMPOSITION Output_CIM
InputPorts
OUTPUT_CIM_OUTER OUTPUT_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t"OUTER OUTPUT":"OutputPort-OutputPort-0" -> "COMPOSITION OUTPUT_CIM":"InputPort-OUTPUT_CIM_OUTER OUTPUT_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OUTER OUTPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER OUTPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n}', ), ( {'show_nested': NESTED, 'show_cim': True, 'show_node_structure': True, 'show_learning': True}, - 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"OUTER INPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER INPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tINTERNAL [label=<
OutputPort-0
OutputPorts
Mechanism:
INTERNAL
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=black penwidth=1 rank=same shape=plaintext]\n\t"OUTER INPUT":"OutputPort-OutputPort-0" -> INTERNAL:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tINTERNAL:"OutputPort-OutputPort-0" -> "NESTED COMPOSITION INPUT_CIM":"InputPort-INPUT_CIM_INNER INPUT_InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION OUTPUT_CIM":"OutputPort-OUTPUT_CIM_INNER OUTPUT_OutputPort-0" -> "OUTER OUTPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION INPUT_CIM" [label=<
INPUT_CIM_OUTER INPUT_InputPort-0
OutputPorts
Mechanism:
COMPOSITION Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_OUTER INPUT_InputPort-0" -> "OUTER INPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION OUTPUT_CIM" [label=<
Mechanism:
COMPOSITION Output_CIM
InputPorts
OUTPUT_CIM_OUTER OUTPUT_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t"OUTER OUTPUT":"OutputPort-OutputPort-0" -> "COMPOSITION OUTPUT_CIM":"InputPort-OUTPUT_CIM_OUTER OUTPUT_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"OUTER OUTPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER OUTPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tsubgraph "cluster_NESTED COMPOSITION" {\n\t\tgraph [label="NESTED COMPOSITION" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tTarget [label=<
OutputPort-0
OutputPorts
Mechanism:
Target
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=orange penwidth=3 rank=min shape=plaintext]\n\t\t"INNER INPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
INNER INPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [color=black penwidth=1 shape=diamond]\n\t\t"INNER INPUT":"OutputPort-OutputPort-0" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [arrowhead=none color=black penwidth=1]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" -> "INNER OUTPUT":"InputPort-InputPort-0" [color=black penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"OutputPort-LearningSignal" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" color=orange penwidth=1]\n\t\t"NESTED COMPOSITION INPUT_CIM" [label=<
INPUT_CIM_INNER INPUT_InputPort-0INPUT_CIM_Target_InputPort-0
OutputPorts
Mechanism:
NESTED COMPOSITION Input_CIM
InputPorts
INPUT_CIM_INNER INPUT_InputPort-0INPUT_CIM_Target_InputPort-0
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"NESTED COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_INNER INPUT_InputPort-0" -> "INNER INPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"NESTED COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_Target_InputPort-0" -> Target:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"NESTED COMPOSITION OUTPUT_CIM" [label=<
OUTPUT_CIM_INNER OUTPUT_OutputPort-0
OutputPorts
Mechanism:
NESTED COMPOSITION Output_CIM
InputPorts
OUTPUT_CIM_INNER OUTPUT_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t\t"INNER OUTPUT":"OutputPort-OutputPort-0" -> "NESTED COMPOSITION OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER OUTPUT_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tComparator [label=<
OUTCOMEMSE
OutputPorts
Mechanism:
Comparator
ParameterPorts
offset
scale
InputPorts
SAMPLETARGET
> color=orange penwidth=1 rank=min shape=plaintext]\n\t\t"INNER OUTPUT":"OutputPort-OutputPort-0" -> Comparator:"InputPort-SAMPLE" [label="" arrowhead=normal color=orange penwidth=1]\n\t\tTarget:"OutputPort-OutputPort-0" -> Comparator:"InputPort-TARGET" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label=<
error_signalLearningSignal
OutputPorts
Mechanism:
Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]
ParameterPorts
learning_rate
InputPorts
activation_inputactivation_outputerror_signal
> color=orange penwidth=1 rank=min shape=plaintext]\n\t\tComparator:"OutputPort-OUTCOME" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"InputPort-error_signal" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER INPUT":"OutputPort-OutputPort-0" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"InputPort-activation_input" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT":"OutputPort-OutputPort-0" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"InputPort-activation_output" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
INNER OUTPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\t\tlabel="NESTED COMPOSITION"\n\t}\n}', + 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"OUTER INPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER INPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tINTERNAL [label=<
OutputPort-0
OutputPorts
Mechanism:
INTERNAL
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=black penwidth=1 rank=same shape=plaintext]\n\t"OUTER INPUT":"OutputPort-OutputPort-0" -> INTERNAL:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tINTERNAL:"OutputPort-OutputPort-0" -> "NESTED COMPOSITION INPUT_CIM":"InputPort-INPUT_CIM_INNER INPUT_InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"NESTED COMPOSITION OUTPUT_CIM":"OutputPort-OUTPUT_CIM_INNER OUTPUT_OutputPort-0" -> "OUTER OUTPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"COMPOSITION INPUT_CIM" [label=<
INPUT_CIM_OUTER INPUT_InputPort-0
OutputPorts
Mechanism:
COMPOSITION Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_OUTER INPUT_InputPort-0" -> "OUTER INPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"COMPOSITION OUTPUT_CIM" [label=<
Mechanism:
COMPOSITION Output_CIM
InputPorts
OUTPUT_CIM_OUTER OUTPUT_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t"OUTER OUTPUT":"OutputPort-OutputPort-0" -> "COMPOSITION OUTPUT_CIM":"InputPort-OUTPUT_CIM_OUTER OUTPUT_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OUTER OUTPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER OUTPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tsubgraph "cluster_NESTED COMPOSITION" {\n\t\tgraph [label="NESTED COMPOSITION" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tTarget [label=<
OutputPort-0
OutputPorts
Mechanism:
Target
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=orange penwidth=3 rank=min shape=plaintext]\n\t\t"INNER INPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
INNER INPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [color=black penwidth=1 shape=diamond]\n\t\t"INNER INPUT":"OutputPort-OutputPort-0" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [arrowhead=none color=black penwidth=1]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" -> "INNER OUTPUT":"InputPort-InputPort-0" [color=black penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"OutputPort-LearningSignal" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" color=orange penwidth=1]\n\t\t"NESTED COMPOSITION INPUT_CIM" [label=<
INPUT_CIM_INNER INPUT_InputPort-0INPUT_CIM_Target_InputPort-0
OutputPorts
Mechanism:
NESTED COMPOSITION Input_CIM
InputPorts
INPUT_CIM_INNER INPUT_InputPort-0INPUT_CIM_Target_InputPort-0
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"NESTED COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_INNER INPUT_InputPort-0" -> "INNER INPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"NESTED COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_Target_InputPort-0" -> Target:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"NESTED COMPOSITION OUTPUT_CIM" [label=<
OUTPUT_CIM_INNER OUTPUT_OutputPort-0
OutputPorts
Mechanism:
NESTED COMPOSITION Output_CIM
InputPorts
OUTPUT_CIM_INNER OUTPUT_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t\t"INNER OUTPUT":"OutputPort-OutputPort-0" -> "NESTED COMPOSITION OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER OUTPUT_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tComparator [label=<
OUTCOMEMSE
OutputPorts
Mechanism:
Comparator
ParameterPorts
offset
scale
InputPorts
SAMPLETARGET
> color=orange penwidth=1 rank=min shape=plaintext]\n\t\t"INNER OUTPUT":"OutputPort-OutputPort-0" -> Comparator:"InputPort-SAMPLE" [label="" arrowhead=normal color=orange penwidth=1]\n\t\tTarget:"OutputPort-OutputPort-0" -> Comparator:"InputPort-TARGET" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label=<
error_signalLearningSignal
OutputPorts
Mechanism:
Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]
ParameterPorts
learning_rate
InputPorts
activation_inputactivation_outputerror_signal
> color=orange penwidth=1 rank=min shape=plaintext]\n\t\tComparator:"OutputPort-OUTCOME" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"InputPort-error_signal" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER INPUT":"OutputPort-OutputPort-0" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"InputPort-activation_input" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT":"OutputPort-OutputPort-0" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"InputPort-activation_output" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
INNER OUTPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\t\tlabel="NESTED COMPOSITION"\n\t}\n}', ), ] @@ -382,35 +383,35 @@ def test_nested_learning(self, show_graph_kwargs, expected_output): _nested_learning_test_with_user_specified_target_in_outer_composition_data = [ ( {'show_nested': False, 'show_cim': False, 'show_learning': True}, - 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\tTARGET [color=green penwidth=3 rank=source shape=oval]\n\t"OUTER INPUT" [color=green penwidth=3 rank=source shape=oval]\n\tINTERNAL [color=black penwidth=1 rank=same shape=oval]\n\t"OUTER INPUT" -> INTERNAL [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" [color=pink penwidth=3 rank=same shape=rectangle]\n\tINTERNAL -> "NESTED COMPOSITION" [label="" arrowhead=normal color=black penwidth=1]\n\tTARGET -> "NESTED COMPOSITION" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" -> "OUTER OUTPUT" [label="" arrowhead=normal color=black penwidth=1]\n\tCONTROLLER -> INTERNAL [label="" arrowhead=box color=purple penwidth=1]\n\t"OBJECTIVE MECHANISM" [color=purple penwidth=1 rank=min shape=oval]\n\t"OBJECTIVE MECHANISM" -> CONTROLLER [label="" color=purple penwidth=1]\n\t"OUTER INPUT" -> "OBJECTIVE MECHANISM" [label="" color=purple penwidth=1]\n\t"OUTER OUTPUT" -> "OBJECTIVE MECHANISM" [label="" color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM" -> CONTROLLER [label="" arrowhead=normal color=purple penwidth=1]\n\t"OUTER OUTPUT" [color=red penwidth=3 rank=max shape=oval]\n\tCONTROLLER [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}' + 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\tTARGET [color=green penwidth=3 rank=source shape=oval]\n\t"OUTER INPUT" [color=green penwidth=3 rank=source shape=oval]\n\tINTERNAL [color=black penwidth=1 rank=same shape=oval]\n\t"OUTER INPUT" -> INTERNAL [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" [color=pink penwidth=3 rank=same shape=rectangle]\n\tINTERNAL -> "NESTED COMPOSITION" [label="" arrowhead=normal color=black penwidth=1]\n\tTARGET -> "NESTED COMPOSITION" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" -> "OUTER OUTPUT" [label="" arrowhead=normal color=black penwidth=1]\n\tCONTROLLER -> INTERNAL [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"OBJECTIVE MECHANISM" [color=purple penwidth=1 rank=min shape=oval]\n\t"OBJECTIVE MECHANISM" -> CONTROLLER [label="" color=purple penwidth=1]\n\t"OUTER INPUT" -> "OBJECTIVE MECHANISM" [label="" color=purple penwidth=1]\n\t"OUTER OUTPUT" -> "OBJECTIVE MECHANISM" [label="" color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM" -> CONTROLLER [label="" arrowhead=normal color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM" -> CONTROLLER [label="" arrowhead=normal color=purple penwidth=1]\n\t"OUTER OUTPUT" [color=red penwidth=3 rank=max shape=oval]\n\tCONTROLLER [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}' ), ( {'show_nested': NESTED, 'show_cim': False, 'show_learning': True}, - 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\tTARGET [color=green penwidth=3 rank=source shape=oval]\n\t"OUTER INPUT" [color=green penwidth=3 rank=source shape=oval]\n\tINTERNAL [color=black penwidth=1 rank=same shape=oval]\n\t"OUTER INPUT" -> INTERNAL [label="" arrowhead=normal color=black penwidth=1]\n\tINTERNAL -> "INNER INPUT" [label="" arrowhead=normal color=black penwidth=1]\n\tTARGET -> Target [label="" arrowhead=normal color=orange penwidth=1]\n\t"INNER OUTPUT" -> "OUTER OUTPUT" [label="" arrowhead=normal color=black penwidth=1]\n\tCONTROLLER -> INTERNAL [label="" arrowhead=box color=purple penwidth=1]\n\t"OBJECTIVE MECHANISM" [color=purple penwidth=1 rank=min shape=oval]\n\t"OBJECTIVE MECHANISM" -> CONTROLLER [label="" color=purple penwidth=1]\n\t"OUTER INPUT" -> "OBJECTIVE MECHANISM" [label="" color=purple penwidth=1]\n\t"OUTER OUTPUT" -> "OBJECTIVE MECHANISM" [label="" color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM" -> CONTROLLER [label="" arrowhead=normal color=purple penwidth=1]\n\t"OUTER OUTPUT" [color=red penwidth=3 rank=max shape=oval]\n\tCONTROLLER [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph "cluster_NESTED COMPOSITION" {\n\t\tgraph [label="NESTED COMPOSITION" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tTarget [color=orange penwidth=3 rank=min shape=oval]\n\t\t"INNER INPUT" [color=green penwidth=3 rank=source shape=oval]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [color=black penwidth=1 shape=diamond]\n\t\t"INNER INPUT" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [arrowhead=none color=black penwidth=1]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" -> "INNER OUTPUT" [color=black penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" color=orange penwidth=1]\n\t\tComparator [color=orange penwidth=1 rank=min shape=oval]\n\t\t"INNER OUTPUT" -> Comparator [label="" arrowhead=normal color=orange penwidth=1]\n\t\tTarget -> Comparator [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [color=orange penwidth=1 rank=min shape=oval]\n\t\tComparator -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER INPUT" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT" [color=red penwidth=3 rank=max shape=oval]\n\t\tlabel="NESTED COMPOSITION"\n\t}\n}' + 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\tTARGET [color=green penwidth=3 rank=source shape=oval]\n\t"OUTER INPUT" [color=green penwidth=3 rank=source shape=oval]\n\tINTERNAL [color=black penwidth=1 rank=same shape=oval]\n\t"OUTER INPUT" -> INTERNAL [label="" arrowhead=normal color=black penwidth=1]\n\tINTERNAL -> "INNER INPUT" [label="" arrowhead=normal color=black penwidth=1]\n\tTARGET -> Target [label="" arrowhead=normal color=orange penwidth=1]\n\t"INNER OUTPUT" -> "OUTER OUTPUT" [label="" arrowhead=normal color=black penwidth=1]\n\tCONTROLLER -> INTERNAL [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"OBJECTIVE MECHANISM" [color=purple penwidth=1 rank=min shape=oval]\n\t"OBJECTIVE MECHANISM" -> CONTROLLER [label="" color=purple penwidth=1]\n\t"OUTER INPUT" -> "OBJECTIVE MECHANISM" [label="" color=purple penwidth=1]\n\t"OUTER OUTPUT" -> "OBJECTIVE MECHANISM" [label="" color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM" -> CONTROLLER [label="" arrowhead=normal color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM" -> CONTROLLER [label="" arrowhead=normal color=purple penwidth=1]\n\t"OUTER OUTPUT" [color=red penwidth=3 rank=max shape=oval]\n\tCONTROLLER [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph "cluster_NESTED COMPOSITION" {\n\t\tgraph [label="NESTED COMPOSITION" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tTarget [color=orange penwidth=3 rank=min shape=oval]\n\t\t"INNER INPUT" [color=green penwidth=3 rank=source shape=oval]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [color=black penwidth=1 shape=diamond]\n\t\t"INNER INPUT" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [arrowhead=none color=black penwidth=1]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" -> "INNER OUTPUT" [color=black penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" color=orange penwidth=1]\n\t\tComparator [color=orange penwidth=1 rank=min shape=oval]\n\t\t"INNER OUTPUT" -> Comparator [label="" arrowhead=normal color=orange penwidth=1]\n\t\tTarget -> Comparator [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [color=orange penwidth=1 rank=min shape=oval]\n\t\tComparator -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER INPUT" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT" [color=red penwidth=3 rank=max shape=oval]\n\t\tlabel="NESTED COMPOSITION"\n\t}\n}' ), ( {'show_nested': False, 'show_cim': True, 'show_learning': True}, - 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\tTARGET [color=green penwidth=3 rank=source shape=oval]\n\t"OUTER INPUT" [color=green penwidth=3 rank=source shape=oval]\n\tINTERNAL [color=black penwidth=1 rank=same shape=oval]\n\t"OUTER INPUT" -> INTERNAL [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" [color=pink penwidth=3 rank=same shape=rectangle]\n\tINTERNAL -> "NESTED COMPOSITION" [label="" arrowhead=normal color=black penwidth=1]\n\tTARGET -> "NESTED COMPOSITION" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" -> "OUTER OUTPUT" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"COMPOSITION INPUT_CIM" -> "OUTER INPUT" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION INPUT_CIM" -> TARGET [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t"OUTER OUTPUT" -> "COMPOSITION OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tCONTROLLER -> INTERNAL [label="" arrowhead=box color=purple penwidth=1]\n\t"OBJECTIVE MECHANISM" [color=purple penwidth=1 rank=min shape=oval]\n\t"OBJECTIVE MECHANISM" -> CONTROLLER [label="" color=purple penwidth=1]\n\t"OUTER INPUT" -> "OBJECTIVE MECHANISM" [label="" color=purple penwidth=1]\n\t"OUTER OUTPUT" -> "OBJECTIVE MECHANISM" [label="" color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM" -> CONTROLLER [label="" arrowhead=normal color=purple penwidth=1]\n\t"OUTER OUTPUT" [color=red penwidth=3 rank=max shape=oval]\n\tCONTROLLER [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}' + 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\tTARGET [color=green penwidth=3 rank=source shape=oval]\n\t"OUTER INPUT" [color=green penwidth=3 rank=source shape=oval]\n\tINTERNAL [color=black penwidth=1 rank=same shape=oval]\n\t"OUTER INPUT" -> INTERNAL [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" [color=pink penwidth=3 rank=same shape=rectangle]\n\tINTERNAL -> "NESTED COMPOSITION" [label="" arrowhead=normal color=black penwidth=1]\n\tTARGET -> "NESTED COMPOSITION" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" -> "OUTER OUTPUT" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"COMPOSITION INPUT_CIM" -> "OUTER INPUT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"COMPOSITION INPUT_CIM" -> TARGET [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"COMPOSITION OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t"OUTER OUTPUT" -> "COMPOSITION OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tCONTROLLER -> INTERNAL [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"OBJECTIVE MECHANISM" [color=purple penwidth=1 rank=min shape=oval]\n\t"OBJECTIVE MECHANISM" -> CONTROLLER [label="" color=purple penwidth=1]\n\t"OUTER INPUT" -> "OBJECTIVE MECHANISM" [label="" color=purple penwidth=1]\n\t"OUTER OUTPUT" -> "OBJECTIVE MECHANISM" [label="" color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM" -> CONTROLLER [label="" arrowhead=normal color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM" -> CONTROLLER [label="" arrowhead=normal color=purple penwidth=1]\n\t"OUTER OUTPUT" [color=red penwidth=3 rank=max shape=oval]\n\tCONTROLLER [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}' ), ( {'show_nested': NESTED, 'show_cim': True, 'show_learning': True}, - 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\tTARGET [color=green penwidth=3 rank=source shape=oval]\n\t"OUTER INPUT" [color=green penwidth=3 rank=source shape=oval]\n\tINTERNAL [color=black penwidth=1 rank=same shape=oval]\n\t"OUTER INPUT" -> INTERNAL [label="" arrowhead=normal color=black penwidth=1]\n\tINTERNAL -> "NESTED COMPOSITION INPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tTARGET -> "NESTED COMPOSITION INPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION OUTPUT_CIM" -> "OUTER OUTPUT" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"COMPOSITION INPUT_CIM" -> "OUTER INPUT" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION INPUT_CIM" -> TARGET [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t"OUTER OUTPUT" -> "COMPOSITION OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tCONTROLLER -> INTERNAL [label="" arrowhead=box color=purple penwidth=1]\n\t"OBJECTIVE MECHANISM" [color=purple penwidth=1 rank=min shape=oval]\n\t"OBJECTIVE MECHANISM" -> CONTROLLER [label="" color=purple penwidth=1]\n\t"OUTER INPUT" -> "OBJECTIVE MECHANISM" [label="" color=purple penwidth=1]\n\t"OUTER OUTPUT" -> "OBJECTIVE MECHANISM" [label="" color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM" -> CONTROLLER [label="" arrowhead=normal color=purple penwidth=1]\n\t"OUTER OUTPUT" [color=red penwidth=3 rank=max shape=oval]\n\tCONTROLLER [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph "cluster_NESTED COMPOSITION" {\n\t\tgraph [label="NESTED COMPOSITION" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tTarget [color=orange penwidth=3 rank=min shape=oval]\n\t\t"INNER INPUT" [color=green penwidth=3 rank=source shape=oval]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [color=black penwidth=1 shape=diamond]\n\t\t"INNER INPUT" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [arrowhead=none color=black penwidth=1]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" -> "INNER OUTPUT" [color=black penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" color=orange penwidth=1]\n\t\t"NESTED COMPOSITION INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t"NESTED COMPOSITION INPUT_CIM" -> "INNER INPUT" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"NESTED COMPOSITION INPUT_CIM" -> Target [label="" arrowhead=normal color=black penwidth=1]\n\t\t"NESTED COMPOSITION OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\t"INNER OUTPUT" -> "NESTED COMPOSITION OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\t\tComparator [color=orange penwidth=1 rank=min shape=oval]\n\t\t"INNER OUTPUT" -> Comparator [label="" arrowhead=normal color=orange penwidth=1]\n\t\tTarget -> Comparator [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [color=orange penwidth=1 rank=min shape=oval]\n\t\tComparator -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER INPUT" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT" [color=red penwidth=3 rank=max shape=oval]\n\t\tlabel="NESTED COMPOSITION"\n\t}\n}' + 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\tTARGET [color=green penwidth=3 rank=source shape=oval]\n\t"OUTER INPUT" [color=green penwidth=3 rank=source shape=oval]\n\tINTERNAL [color=black penwidth=1 rank=same shape=oval]\n\t"OUTER INPUT" -> INTERNAL [label="" arrowhead=normal color=black penwidth=1]\n\tINTERNAL -> "NESTED COMPOSITION INPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tTARGET -> "NESTED COMPOSITION INPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"NESTED COMPOSITION OUTPUT_CIM" -> "OUTER OUTPUT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"COMPOSITION INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"COMPOSITION INPUT_CIM" -> "OUTER INPUT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"COMPOSITION INPUT_CIM" -> TARGET [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"COMPOSITION OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t"OUTER OUTPUT" -> "COMPOSITION OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tCONTROLLER -> INTERNAL [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"OBJECTIVE MECHANISM" [color=purple penwidth=1 rank=min shape=oval]\n\t"OBJECTIVE MECHANISM" -> CONTROLLER [label="" color=purple penwidth=1]\n\t"OUTER INPUT" -> "OBJECTIVE MECHANISM" [label="" color=purple penwidth=1]\n\t"OUTER OUTPUT" -> "OBJECTIVE MECHANISM" [label="" color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM" -> CONTROLLER [label="" arrowhead=normal color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM" -> CONTROLLER [label="" arrowhead=normal color=purple penwidth=1]\n\t"OUTER OUTPUT" [color=red penwidth=3 rank=max shape=oval]\n\tCONTROLLER [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph "cluster_NESTED COMPOSITION" {\n\t\tgraph [label="NESTED COMPOSITION" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tTarget [color=orange penwidth=3 rank=min shape=oval]\n\t\t"INNER INPUT" [color=green penwidth=3 rank=source shape=oval]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [color=black penwidth=1 shape=diamond]\n\t\t"INNER INPUT" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [arrowhead=none color=black penwidth=1]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" -> "INNER OUTPUT" [color=black penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" color=orange penwidth=1]\n\t\t"NESTED COMPOSITION INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t"NESTED COMPOSITION INPUT_CIM" -> "INNER INPUT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"NESTED COMPOSITION INPUT_CIM" -> Target [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"NESTED COMPOSITION OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\t"INNER OUTPUT" -> "NESTED COMPOSITION OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tComparator [color=orange penwidth=1 rank=min shape=oval]\n\t\t"INNER OUTPUT" -> Comparator [label="" arrowhead=normal color=orange penwidth=1]\n\t\tTarget -> Comparator [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [color=orange penwidth=1 rank=min shape=oval]\n\t\tComparator -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER INPUT" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT" [color=red penwidth=3 rank=max shape=oval]\n\t\tlabel="NESTED COMPOSITION"\n\t}\n}' ), ( {'show_nested': False, 'show_cim': False, 'show_node_structure': True, 'show_learning': True}, - 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\tTARGET [label=<
OutputPort-0
OutputPorts
Mechanism:
TARGET
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t"OUTER INPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER INPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tINTERNAL [label=<
OutputPort-0
OutputPorts
Mechanism:
INTERNAL
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=black penwidth=1 rank=same shape=plaintext]\n\t"OUTER INPUT":"OutputPort-OutputPort-0" -> INTERNAL:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" [color=pink penwidth=3 rank=same shape=rectangle]\n\tINTERNAL:"OutputPort-OutputPort-0" -> "NESTED COMPOSITION" [label="" arrowhead=normal color=black penwidth=1]\n\tTARGET:"OutputPort-OutputPort-0" -> "NESTED COMPOSITION" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" -> "OUTER OUTPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tCONTROLLER:"OutputPort-INTERNAL[slope] ControlSignal" -> INTERNAL:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"OBJECTIVE MECHANISM" [label=<
OUTCOME
OutputPorts
Mechanism:
OBJECTIVE MECHANISM
ParameterPorts
offset
scale
InputPorts
Value of OUTER INPUT [OutputPort-0]Value of OUTER OUTPUT [OutputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\t"OBJECTIVE MECHANISM":"OutputPort-OUTCOME" -> CONTROLLER:"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\t"OUTER INPUT":"OutputPort-OutputPort-0" -> "OBJECTIVE MECHANISM":"InputPort-Value of OUTER INPUT [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"OUTER OUTPUT":"OutputPort-OutputPort-0" -> "OBJECTIVE MECHANISM":"InputPort-Value of OUTER OUTPUT [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_OUTER INPUT_InputPort-0" -> CONTROLLER:"InputPort-Shadowed input of of OUTER INPUT[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OUTER OUTPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER OUTPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tCONTROLLER [label=<
INTERNAL[slope] ControlSignal
OutputPorts
Mechanism:
CONTROLLER
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of OUTER INPUT[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}' + 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\tTARGET [label=<
OutputPort-0
OutputPorts
Mechanism:
TARGET
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t"OUTER INPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER INPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tINTERNAL [label=<
OutputPort-0
OutputPorts
Mechanism:
INTERNAL
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=black penwidth=1 rank=same shape=plaintext]\n\t"OUTER INPUT":"OutputPort-OutputPort-0" -> INTERNAL:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" [color=pink penwidth=3 rank=same shape=rectangle]\n\tINTERNAL:"OutputPort-OutputPort-0" -> "NESTED COMPOSITION" [label="" arrowhead=normal color=black penwidth=1]\n\tTARGET:"OutputPort-OutputPort-0" -> "NESTED COMPOSITION" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" -> "OUTER OUTPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tCONTROLLER:"OutputPort-INTERNAL[slope] ControlSignal" -> INTERNAL:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"OBJECTIVE MECHANISM" [label=<
OUTCOME
OutputPorts
Mechanism:
OBJECTIVE MECHANISM
ParameterPorts
offset
scale
InputPorts
Value of OUTER INPUT [OutputPort-0]Value of OUTER OUTPUT [OutputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\t"OBJECTIVE MECHANISM":"OutputPort-OUTCOME" -> CONTROLLER:"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\t"OUTER INPUT":"OutputPort-OutputPort-0" -> "OBJECTIVE MECHANISM":"InputPort-Value of OUTER INPUT [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"OUTER OUTPUT":"OutputPort-OutputPort-0" -> "OBJECTIVE MECHANISM":"InputPort-Value of OUTER OUTPUT [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_OUTER INPUT_InputPort-0" -> CONTROLLER:"InputPort-SHADOWED INPUT OF OUTER INPUT[InputPort-0] FOR OUTER INPUT[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_OUTER INPUT_InputPort-0" -> CONTROLLER:"InputPort-SHADOWED INPUT OF TARGET[InputPort-0] FOR TARGET[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OUTER OUTPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER OUTPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tCONTROLLER [label=<
INTERNAL[slope] ControlSignal
OutputPorts
Mechanism:
CONTROLLER
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF OUTER INPUT[InputPort-0] FOR OUTER INPUT[InputPort-0]SHADOWED INPUT OF TARGET[InputPort-0] FOR TARGET[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}' ), ( {'show_nested': NESTED, 'show_cim': False, 'show_node_structure': True, 'show_learning': True}, - 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\tTARGET [label=<
OutputPort-0
OutputPorts
Mechanism:
TARGET
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t"OUTER INPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER INPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tINTERNAL [label=<
OutputPort-0
OutputPorts
Mechanism:
INTERNAL
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=black penwidth=1 rank=same shape=plaintext]\n\t"OUTER INPUT":"OutputPort-OutputPort-0" -> INTERNAL:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tINTERNAL:"OutputPort-OutputPort-0" -> "INNER INPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tTARGET:"OutputPort-OutputPort-0" -> Target:"InputPort-InputPort-0" [label="" arrowhead=normal color=orange penwidth=1]\n\t"INNER OUTPUT":"OutputPort-OutputPort-0" -> "OUTER OUTPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tCONTROLLER:"OutputPort-INTERNAL[slope] ControlSignal" -> INTERNAL:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"OBJECTIVE MECHANISM" [label=<
OUTCOME
OutputPorts
Mechanism:
OBJECTIVE MECHANISM
ParameterPorts
offset
scale
InputPorts
Value of OUTER INPUT [OutputPort-0]Value of OUTER OUTPUT [OutputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\t"OBJECTIVE MECHANISM":"OutputPort-OUTCOME" -> CONTROLLER:"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\t"OUTER INPUT":"OutputPort-OutputPort-0" -> "OBJECTIVE MECHANISM":"InputPort-Value of OUTER INPUT [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"OUTER OUTPUT":"OutputPort-OutputPort-0" -> "OBJECTIVE MECHANISM":"InputPort-Value of OUTER OUTPUT [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_OUTER INPUT_InputPort-0" -> CONTROLLER:"InputPort-Shadowed input of of OUTER INPUT[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OUTER OUTPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER OUTPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tCONTROLLER [label=<
INTERNAL[slope] ControlSignal
OutputPorts
Mechanism:
CONTROLLER
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of OUTER INPUT[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph "cluster_NESTED COMPOSITION" {\n\t\tgraph [label="NESTED COMPOSITION" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tTarget [label=<
OutputPort-0
OutputPorts
Mechanism:
Target
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=orange penwidth=3 rank=min shape=plaintext]\n\t\t"INNER INPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
INNER INPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [color=black penwidth=1 shape=diamond]\n\t\t"INNER INPUT":"OutputPort-OutputPort-0" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [arrowhead=none color=black penwidth=1]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" -> "INNER OUTPUT":"InputPort-InputPort-0" [color=black penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"OutputPort-LearningSignal" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" color=orange penwidth=1]\n\t\tComparator [label=<
OUTCOMEMSE
OutputPorts
Mechanism:
Comparator
ParameterPorts
offset
scale
InputPorts
SAMPLETARGET
> color=orange penwidth=1 rank=min shape=plaintext]\n\t\t"INNER OUTPUT":"OutputPort-OutputPort-0" -> Comparator:"InputPort-SAMPLE" [label="" arrowhead=normal color=orange penwidth=1]\n\t\tTarget:"OutputPort-OutputPort-0" -> Comparator:"InputPort-TARGET" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label=<
error_signalLearningSignal
OutputPorts
Mechanism:
Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]
ParameterPorts
learning_rate
InputPorts
activation_inputactivation_outputerror_signal
> color=orange penwidth=1 rank=min shape=plaintext]\n\t\tComparator:"OutputPort-OUTCOME" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"InputPort-error_signal" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER INPUT":"OutputPort-OutputPort-0" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"InputPort-activation_input" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT":"OutputPort-OutputPort-0" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"InputPort-activation_output" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
INNER OUTPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\t\tlabel="NESTED COMPOSITION"\n\t}\n}' + 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\tTARGET [label=<
OutputPort-0
OutputPorts
Mechanism:
TARGET
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t"OUTER INPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER INPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tINTERNAL [label=<
OutputPort-0
OutputPorts
Mechanism:
INTERNAL
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=black penwidth=1 rank=same shape=plaintext]\n\t"OUTER INPUT":"OutputPort-OutputPort-0" -> INTERNAL:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tINTERNAL:"OutputPort-OutputPort-0" -> "INNER INPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tTARGET:"OutputPort-OutputPort-0" -> Target:"InputPort-InputPort-0" [label="" arrowhead=normal color=orange penwidth=1]\n\t"INNER OUTPUT":"OutputPort-OutputPort-0" -> "OUTER OUTPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tCONTROLLER:"OutputPort-INTERNAL[slope] ControlSignal" -> INTERNAL:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"OBJECTIVE MECHANISM" [label=<
OUTCOME
OutputPorts
Mechanism:
OBJECTIVE MECHANISM
ParameterPorts
offset
scale
InputPorts
Value of OUTER INPUT [OutputPort-0]Value of OUTER OUTPUT [OutputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\t"OBJECTIVE MECHANISM":"OutputPort-OUTCOME" -> CONTROLLER:"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\t"OUTER INPUT":"OutputPort-OutputPort-0" -> "OBJECTIVE MECHANISM":"InputPort-Value of OUTER INPUT [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"OUTER OUTPUT":"OutputPort-OutputPort-0" -> "OBJECTIVE MECHANISM":"InputPort-Value of OUTER OUTPUT [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_OUTER INPUT_InputPort-0" -> CONTROLLER:"InputPort-SHADOWED INPUT OF OUTER INPUT[InputPort-0] FOR OUTER INPUT[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_OUTER INPUT_InputPort-0" -> CONTROLLER:"InputPort-SHADOWED INPUT OF TARGET[InputPort-0] FOR TARGET[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OUTER OUTPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER OUTPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tCONTROLLER [label=<
INTERNAL[slope] ControlSignal
OutputPorts
Mechanism:
CONTROLLER
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF OUTER INPUT[InputPort-0] FOR OUTER INPUT[InputPort-0]SHADOWED INPUT OF TARGET[InputPort-0] FOR TARGET[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph "cluster_NESTED COMPOSITION" {\n\t\tgraph [label="NESTED COMPOSITION" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tTarget [label=<
OutputPort-0
OutputPorts
Mechanism:
Target
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=orange penwidth=3 rank=min shape=plaintext]\n\t\t"INNER INPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
INNER INPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [color=black penwidth=1 shape=diamond]\n\t\t"INNER INPUT":"OutputPort-OutputPort-0" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [arrowhead=none color=black penwidth=1]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" -> "INNER OUTPUT":"InputPort-InputPort-0" [color=black penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"OutputPort-LearningSignal" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" color=orange penwidth=1]\n\t\tComparator [label=<
OUTCOMEMSE
OutputPorts
Mechanism:
Comparator
ParameterPorts
offset
scale
InputPorts
SAMPLETARGET
> color=orange penwidth=1 rank=min shape=plaintext]\n\t\t"INNER OUTPUT":"OutputPort-OutputPort-0" -> Comparator:"InputPort-SAMPLE" [label="" arrowhead=normal color=orange penwidth=1]\n\t\tTarget:"OutputPort-OutputPort-0" -> Comparator:"InputPort-TARGET" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label=<
error_signalLearningSignal
OutputPorts
Mechanism:
Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]
ParameterPorts
learning_rate
InputPorts
activation_inputactivation_outputerror_signal
> color=orange penwidth=1 rank=min shape=plaintext]\n\t\tComparator:"OutputPort-OUTCOME" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"InputPort-error_signal" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER INPUT":"OutputPort-OutputPort-0" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"InputPort-activation_input" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT":"OutputPort-OutputPort-0" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"InputPort-activation_output" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
INNER OUTPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\t\tlabel="NESTED COMPOSITION"\n\t}\n}' ), ( {'show_nested': False, 'show_cim': True, 'show_node_structure': True, 'show_learning': True}, - 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\tTARGET [label=<
OutputPort-0
OutputPorts
Mechanism:
TARGET
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t"OUTER INPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER INPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tINTERNAL [label=<
OutputPort-0
OutputPorts
Mechanism:
INTERNAL
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=black penwidth=1 rank=same shape=plaintext]\n\t"OUTER INPUT":"OutputPort-OutputPort-0" -> INTERNAL:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" [color=pink penwidth=3 rank=same shape=rectangle]\n\tINTERNAL:"OutputPort-OutputPort-0" -> "NESTED COMPOSITION" [label="" arrowhead=normal color=black penwidth=1]\n\tTARGET:"OutputPort-OutputPort-0" -> "NESTED COMPOSITION" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" -> "OUTER OUTPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION INPUT_CIM" [label=<
INPUT_CIM_OUTER INPUT_InputPort-0INPUT_CIM_TARGET_InputPort-0
OutputPorts
Mechanism:
COMPOSITION Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_OUTER INPUT_InputPort-0" -> "OUTER INPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_TARGET_InputPort-0" -> TARGET:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION OUTPUT_CIM" [label=<
Mechanism:
COMPOSITION Output_CIM
InputPorts
OUTPUT_CIM_OUTER OUTPUT_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t"OUTER OUTPUT":"OutputPort-OutputPort-0" -> "COMPOSITION OUTPUT_CIM":"InputPort-OUTPUT_CIM_OUTER OUTPUT_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tCONTROLLER:"OutputPort-INTERNAL[slope] ControlSignal" -> INTERNAL:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"OBJECTIVE MECHANISM" [label=<
OUTCOME
OutputPorts
Mechanism:
OBJECTIVE MECHANISM
ParameterPorts
offset
scale
InputPorts
Value of OUTER INPUT [OutputPort-0]Value of OUTER OUTPUT [OutputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\t"OBJECTIVE MECHANISM":"OutputPort-OUTCOME" -> CONTROLLER:"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\t"OUTER INPUT":"OutputPort-OutputPort-0" -> "OBJECTIVE MECHANISM":"InputPort-Value of OUTER INPUT [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"OUTER OUTPUT":"OutputPort-OutputPort-0" -> "OBJECTIVE MECHANISM":"InputPort-Value of OUTER OUTPUT [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_OUTER INPUT_InputPort-0" -> CONTROLLER:"InputPort-Shadowed input of of OUTER INPUT[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OUTER OUTPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER OUTPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tCONTROLLER [label=<
INTERNAL[slope] ControlSignal
OutputPorts
Mechanism:
CONTROLLER
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of OUTER INPUT[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}' + 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\tTARGET [label=<
OutputPort-0
OutputPorts
Mechanism:
TARGET
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t"OUTER INPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER INPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tINTERNAL [label=<
OutputPort-0
OutputPorts
Mechanism:
INTERNAL
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=black penwidth=1 rank=same shape=plaintext]\n\t"OUTER INPUT":"OutputPort-OutputPort-0" -> INTERNAL:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" [color=pink penwidth=3 rank=same shape=rectangle]\n\tINTERNAL:"OutputPort-OutputPort-0" -> "NESTED COMPOSITION" [label="" arrowhead=normal color=black penwidth=1]\n\tTARGET:"OutputPort-OutputPort-0" -> "NESTED COMPOSITION" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION" -> "OUTER OUTPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION INPUT_CIM" [label=<
INPUT_CIM_OUTER INPUT_InputPort-0INPUT_CIM_TARGET_InputPort-0
OutputPorts
Mechanism:
COMPOSITION Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_OUTER INPUT_InputPort-0" -> "OUTER INPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_TARGET_InputPort-0" -> TARGET:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"COMPOSITION OUTPUT_CIM" [label=<
Mechanism:
COMPOSITION Output_CIM
InputPorts
OUTPUT_CIM_OUTER OUTPUT_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t"OUTER OUTPUT":"OutputPort-OutputPort-0" -> "COMPOSITION OUTPUT_CIM":"InputPort-OUTPUT_CIM_OUTER OUTPUT_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tCONTROLLER:"OutputPort-INTERNAL[slope] ControlSignal" -> INTERNAL:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"OBJECTIVE MECHANISM" [label=<
OUTCOME
OutputPorts
Mechanism:
OBJECTIVE MECHANISM
ParameterPorts
offset
scale
InputPorts
Value of OUTER INPUT [OutputPort-0]Value of OUTER OUTPUT [OutputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\t"OBJECTIVE MECHANISM":"OutputPort-OUTCOME" -> CONTROLLER:"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\t"OUTER INPUT":"OutputPort-OutputPort-0" -> "OBJECTIVE MECHANISM":"InputPort-Value of OUTER INPUT [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"OUTER OUTPUT":"OutputPort-OutputPort-0" -> "OBJECTIVE MECHANISM":"InputPort-Value of OUTER OUTPUT [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_OUTER INPUT_InputPort-0" -> CONTROLLER:"InputPort-SHADOWED INPUT OF OUTER INPUT[InputPort-0] FOR OUTER INPUT[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_TARGET_InputPort-0" -> CONTROLLER:"InputPort-SHADOWED INPUT OF TARGET[InputPort-0] FOR TARGET[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OUTER OUTPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER OUTPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tCONTROLLER [label=<
INTERNAL[slope] ControlSignal
OutputPorts
Mechanism:
CONTROLLER
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF OUTER INPUT[InputPort-0] FOR OUTER INPUT[InputPort-0]SHADOWED INPUT OF TARGET[InputPort-0] FOR TARGET[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}' ), ( {'show_nested': NESTED, 'show_cim': True, 'show_node_structure': True, 'show_learning': True}, - 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\tTARGET [label=<
OutputPort-0
OutputPorts
Mechanism:
TARGET
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t"OUTER INPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER INPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tINTERNAL [label=<
OutputPort-0
OutputPorts
Mechanism:
INTERNAL
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=black penwidth=1 rank=same shape=plaintext]\n\t"OUTER INPUT":"OutputPort-OutputPort-0" -> INTERNAL:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tINTERNAL:"OutputPort-OutputPort-0" -> "NESTED COMPOSITION INPUT_CIM":"InputPort-INPUT_CIM_INNER INPUT_InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tTARGET:"OutputPort-OutputPort-0" -> "NESTED COMPOSITION INPUT_CIM":"InputPort-INPUT_CIM_Target_InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"NESTED COMPOSITION OUTPUT_CIM":"OutputPort-OUTPUT_CIM_INNER OUTPUT_OutputPort-0" -> "OUTER OUTPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION INPUT_CIM" [label=<
INPUT_CIM_OUTER INPUT_InputPort-0INPUT_CIM_TARGET_InputPort-0
OutputPorts
Mechanism:
COMPOSITION Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_OUTER INPUT_InputPort-0" -> "OUTER INPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_TARGET_InputPort-0" -> TARGET:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"COMPOSITION OUTPUT_CIM" [label=<
Mechanism:
COMPOSITION Output_CIM
InputPorts
OUTPUT_CIM_OUTER OUTPUT_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t"OUTER OUTPUT":"OutputPort-OutputPort-0" -> "COMPOSITION OUTPUT_CIM":"InputPort-OUTPUT_CIM_OUTER OUTPUT_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tCONTROLLER:"OutputPort-INTERNAL[slope] ControlSignal" -> INTERNAL:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"OBJECTIVE MECHANISM" [label=<
OUTCOME
OutputPorts
Mechanism:
OBJECTIVE MECHANISM
ParameterPorts
offset
scale
InputPorts
Value of OUTER INPUT [OutputPort-0]Value of OUTER OUTPUT [OutputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\t"OBJECTIVE MECHANISM":"OutputPort-OUTCOME" -> CONTROLLER:"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\t"OUTER INPUT":"OutputPort-OutputPort-0" -> "OBJECTIVE MECHANISM":"InputPort-Value of OUTER INPUT [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"OUTER OUTPUT":"OutputPort-OutputPort-0" -> "OBJECTIVE MECHANISM":"InputPort-Value of OUTER OUTPUT [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_OUTER INPUT_InputPort-0" -> CONTROLLER:"InputPort-Shadowed input of of OUTER INPUT[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OUTER OUTPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER OUTPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tCONTROLLER [label=<
INTERNAL[slope] ControlSignal
OutputPorts
Mechanism:
CONTROLLER
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of OUTER INPUT[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph "cluster_NESTED COMPOSITION" {\n\t\tgraph [label="NESTED COMPOSITION" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tTarget [label=<
OutputPort-0
OutputPorts
Mechanism:
Target
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=orange penwidth=3 rank=min shape=plaintext]\n\t\t"INNER INPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
INNER INPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [color=black penwidth=1 shape=diamond]\n\t\t"INNER INPUT":"OutputPort-OutputPort-0" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [arrowhead=none color=black penwidth=1]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" -> "INNER OUTPUT":"InputPort-InputPort-0" [color=black penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"OutputPort-LearningSignal" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" color=orange penwidth=1]\n\t\t"NESTED COMPOSITION INPUT_CIM" [label=<
INPUT_CIM_INNER INPUT_InputPort-0INPUT_CIM_Target_InputPort-0
OutputPorts
Mechanism:
NESTED COMPOSITION Input_CIM
InputPorts
INPUT_CIM_INNER INPUT_InputPort-0INPUT_CIM_Target_InputPort-0
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"NESTED COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_INNER INPUT_InputPort-0" -> "INNER INPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"NESTED COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_Target_InputPort-0" -> Target:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"NESTED COMPOSITION OUTPUT_CIM" [label=<
OUTPUT_CIM_INNER OUTPUT_OutputPort-0
OutputPorts
Mechanism:
NESTED COMPOSITION Output_CIM
InputPorts
OUTPUT_CIM_INNER OUTPUT_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t\t"INNER OUTPUT":"OutputPort-OutputPort-0" -> "NESTED COMPOSITION OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER OUTPUT_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tComparator [label=<
OUTCOMEMSE
OutputPorts
Mechanism:
Comparator
ParameterPorts
offset
scale
InputPorts
SAMPLETARGET
> color=orange penwidth=1 rank=min shape=plaintext]\n\t\t"INNER OUTPUT":"OutputPort-OutputPort-0" -> Comparator:"InputPort-SAMPLE" [label="" arrowhead=normal color=orange penwidth=1]\n\t\tTarget:"OutputPort-OutputPort-0" -> Comparator:"InputPort-TARGET" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label=<
error_signalLearningSignal
OutputPorts
Mechanism:
Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]
ParameterPorts
learning_rate
InputPorts
activation_inputactivation_outputerror_signal
> color=orange penwidth=1 rank=min shape=plaintext]\n\t\tComparator:"OutputPort-OUTCOME" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"InputPort-error_signal" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER INPUT":"OutputPort-OutputPort-0" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"InputPort-activation_input" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT":"OutputPort-OutputPort-0" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"InputPort-activation_output" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
INNER OUTPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\t\tlabel="NESTED COMPOSITION"\n\t}\n}' + 'digraph COMPOSITION {\n\tgraph [label=COMPOSITION overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\tTARGET [label=<
OutputPort-0
OutputPorts
Mechanism:
TARGET
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t"OUTER INPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER INPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tINTERNAL [label=<
OutputPort-0
OutputPorts
Mechanism:
INTERNAL
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=black penwidth=1 rank=same shape=plaintext]\n\t"OUTER INPUT":"OutputPort-OutputPort-0" -> INTERNAL:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tINTERNAL:"OutputPort-OutputPort-0" -> "NESTED COMPOSITION INPUT_CIM":"InputPort-INPUT_CIM_INNER INPUT_InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tTARGET:"OutputPort-OutputPort-0" -> "NESTED COMPOSITION INPUT_CIM":"InputPort-INPUT_CIM_Target_InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"NESTED COMPOSITION OUTPUT_CIM":"OutputPort-OUTPUT_CIM_INNER OUTPUT_OutputPort-0" -> "OUTER OUTPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"COMPOSITION INPUT_CIM" [label=<
INPUT_CIM_OUTER INPUT_InputPort-0INPUT_CIM_TARGET_InputPort-0
OutputPorts
Mechanism:
COMPOSITION Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_OUTER INPUT_InputPort-0" -> "OUTER INPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_TARGET_InputPort-0" -> TARGET:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"COMPOSITION OUTPUT_CIM" [label=<
Mechanism:
COMPOSITION Output_CIM
InputPorts
OUTPUT_CIM_OUTER OUTPUT_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t"OUTER OUTPUT":"OutputPort-OutputPort-0" -> "COMPOSITION OUTPUT_CIM":"InputPort-OUTPUT_CIM_OUTER OUTPUT_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tCONTROLLER:"OutputPort-INTERNAL[slope] ControlSignal" -> INTERNAL:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"OBJECTIVE MECHANISM" [label=<
OUTCOME
OutputPorts
Mechanism:
OBJECTIVE MECHANISM
ParameterPorts
offset
scale
InputPorts
Value of OUTER INPUT [OutputPort-0]Value of OUTER OUTPUT [OutputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\t"OBJECTIVE MECHANISM":"OutputPort-OUTCOME" -> CONTROLLER:"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\t"OUTER INPUT":"OutputPort-OutputPort-0" -> "OBJECTIVE MECHANISM":"InputPort-Value of OUTER INPUT [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"OUTER OUTPUT":"OutputPort-OutputPort-0" -> "OBJECTIVE MECHANISM":"InputPort-Value of OUTER OUTPUT [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_OUTER INPUT_InputPort-0" -> CONTROLLER:"InputPort-SHADOWED INPUT OF OUTER INPUT[InputPort-0] FOR OUTER INPUT[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_TARGET_InputPort-0" -> CONTROLLER:"InputPort-SHADOWED INPUT OF TARGET[InputPort-0] FOR TARGET[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OUTER OUTPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
OUTER OUTPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tCONTROLLER [label=<
INTERNAL[slope] ControlSignal
OutputPorts
Mechanism:
CONTROLLER
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF OUTER INPUT[InputPort-0] FOR OUTER INPUT[InputPort-0]SHADOWED INPUT OF TARGET[InputPort-0] FOR TARGET[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph "cluster_NESTED COMPOSITION" {\n\t\tgraph [label="NESTED COMPOSITION" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tTarget [label=<
OutputPort-0
OutputPorts
Mechanism:
Target
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=orange penwidth=3 rank=min shape=plaintext]\n\t\t"INNER INPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
INNER INPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [color=black penwidth=1 shape=diamond]\n\t\t"INNER INPUT":"OutputPort-OutputPort-0" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [arrowhead=none color=black penwidth=1]\n\t\t"MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" -> "INNER OUTPUT":"InputPort-InputPort-0" [color=black penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"OutputPort-LearningSignal" -> "MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label="" color=orange penwidth=1]\n\t\t"NESTED COMPOSITION INPUT_CIM" [label=<
INPUT_CIM_INNER INPUT_InputPort-0INPUT_CIM_Target_InputPort-0
OutputPorts
Mechanism:
NESTED COMPOSITION Input_CIM
InputPorts
INPUT_CIM_INNER INPUT_InputPort-0INPUT_CIM_Target_InputPort-0
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"NESTED COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_INNER INPUT_InputPort-0" -> "INNER INPUT":"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"NESTED COMPOSITION INPUT_CIM":"OutputPort-INPUT_CIM_Target_InputPort-0" -> Target:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"NESTED COMPOSITION OUTPUT_CIM" [label=<
OUTPUT_CIM_INNER OUTPUT_OutputPort-0
OutputPorts
Mechanism:
NESTED COMPOSITION Output_CIM
InputPorts
OUTPUT_CIM_INNER OUTPUT_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t\t"INNER OUTPUT":"OutputPort-OutputPort-0" -> "NESTED COMPOSITION OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER OUTPUT_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tComparator [label=<
OUTCOMEMSE
OutputPorts
Mechanism:
Comparator
ParameterPorts
offset
scale
InputPorts
SAMPLETARGET
> color=orange penwidth=1 rank=min shape=plaintext]\n\t\t"INNER OUTPUT":"OutputPort-OutputPort-0" -> Comparator:"InputPort-SAMPLE" [label="" arrowhead=normal color=orange penwidth=1]\n\t\tTarget:"OutputPort-OutputPort-0" -> Comparator:"InputPort-TARGET" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]" [label=<
error_signalLearningSignal
OutputPorts
Mechanism:
Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]
ParameterPorts
learning_rate
InputPorts
activation_inputactivation_outputerror_signal
> color=orange penwidth=1 rank=min shape=plaintext]\n\t\tComparator:"OutputPort-OUTCOME" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"InputPort-error_signal" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER INPUT":"OutputPort-OutputPort-0" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"InputPort-activation_input" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT":"OutputPort-OutputPort-0" -> "Learning Mechanism for MappingProjection from INNER INPUT[OutputPort-0] to INNER OUTPUT[InputPort-0]":"InputPort-activation_output" [label="" arrowhead=normal color=orange penwidth=1]\n\t\t"INNER OUTPUT" [label=<
OutputPort-0
OutputPorts
Mechanism:
INNER OUTPUT
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\t\tlabel="NESTED COMPOSITION"\n\t}\n}' ), ] @@ -447,6 +448,7 @@ def test_nested_learning_test_with_user_specified_target_in_outer_composition( assert len(target.efferents) == 1 assert target.efferents[0].receiver == icomp.input_CIM.input_ports['INPUT_CIM_Target_InputPort-0'] assert icomp.input_CIM.output_ports['INPUT_CIM_Target_InputPort-0'].efferents[0].receiver.owner == p.target + assert ocomp.controller.num_state_input_ports == 1 gv = ocomp.show_graph(output_fmt='source', **show_graph_kwargs) assert gv.strip() == expected_output @@ -502,18 +504,18 @@ def test_nested_learning_test_with_user_specified_target_in_outer_composition( # each item corresponds to the same item in _nested_show_graph_kwargs above _of_show_nested_show_cim_and_show_node_structure_expected_outputs = [ - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\tlabel=icomp\n\t}\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\toa -> ia [label="" arrowhead=normal color=black penwidth=1]\n\tctl_mech -> ia [label="" arrowhead=box color=blue penwidth=1]\n\tia -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> ia [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> ia [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\tlabel=icomp\n\t}\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"ocomp INPUT_CIM" -> ob [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" -> oa [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\tob -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\toc -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> icomp [label="" arrowhead=normal color=blue penwidth=1]\n\toa -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"ocomp INPUT_CIM" -> ob [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" -> oa [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\tob -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\toc -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> icomp [label="" arrowhead=normal color=purple penwidth=1]\n\tocm -> icomp [label="" arrowhead=normal color=purple penwidth=1]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\t"icomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t"icomp INPUT_CIM" -> ia [label="" arrowhead=normal color=black penwidth=1]\n\t\t"icomp PARAMETER_CIM" [color=purple penwidth=1 rank=same shape=rectangle]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=blue penwidth=1]\n\t\t"icomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\tia -> "icomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\tlabel=icomp\n\t}\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\toa -> "icomp INPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tctl_mech -> "icomp PARAMETER_CIM" [label="" arrowhead=normal color=blue penwidth=1]\n\t"icomp OUTPUT_CIM" -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"ocomp INPUT_CIM" -> ob [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" -> oa [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\tob -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\toc -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> "icomp PARAMETER_CIM" [label="" arrowhead=normal color=purple penwidth=1]\n\tocm -> "icomp PARAMETER_CIM" [label="" arrowhead=normal color=purple penwidth=1]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\t"icomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t"icomp INPUT_CIM" -> ia [label="" arrowhead=normal color=black penwidth=1]\n\t\t"icomp PARAMETER_CIM" [color=purple penwidth=1 rank=same shape=rectangle]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=blue penwidth=1]\n\t\t"icomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\tia -> "icomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\tlabel=icomp\n\t}\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-Shadowed input of of ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-Shadowed input of of oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of ob[InputPort-0]Shadowed input of of oa[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-Shadowed input of of ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-Shadowed input of of oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of ob[InputPort-0]Shadowed input of of oa[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\tlabel=icomp\n\t}\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\toa:"OutputPort-RESULT" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=blue penwidth=1]\n\tia:"OutputPort-RESULT" -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> ia:"ParameterPort-noise" [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> ia:"ParameterPort-intercept" [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-Shadowed input of of ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-Shadowed input of of oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of ob[InputPort-0]Shadowed input of of oa[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\tlabel=icomp\n\t}\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [label=<
INPUT_CIM_ob_InputPort-0INPUT_CIM_oa_InputPort-0
OutputPorts
Mechanism:
ocomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ob:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> oa:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp OUTPUT_CIM" [label=<
Mechanism:
ocomp Output_CIM
InputPorts
OUTPUT_CIM_ob_RESULTOUTPUT_CIM_oc_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\tob:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ob_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_oc_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-Shadowed input of of ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-Shadowed input of of oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of ob[InputPort-0]Shadowed input of of oa[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> icomp [label="" arrowhead=normal color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [label=<
INPUT_CIM_ob_InputPort-0INPUT_CIM_oa_InputPort-0
OutputPorts
Mechanism:
ocomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ob:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> oa:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp OUTPUT_CIM" [label=<
Mechanism:
ocomp Output_CIM
InputPorts
OUTPUT_CIM_ob_RESULTOUTPUT_CIM_oc_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\tob:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ob_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_oc_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> icomp [label="" arrowhead=normal color=purple penwidth=1]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> icomp [label="" arrowhead=normal color=purple penwidth=1]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-Shadowed input of of ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-Shadowed input of of oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of ob[InputPort-0]Shadowed input of of oa[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\t"icomp INPUT_CIM" [label=<
INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
icomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"icomp INPUT_CIM":"OutputPort-INPUT_CIM_ia_InputPort-0" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"icomp PARAMETER_CIM" [label=<
PARAMETER_CIM_ia_interceptPARAMETER_CIM_ia_noisePARAMETER_CIM_ia_slope
OutputPorts
Mechanism:
icomp Parameter_CIM
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_intercept" -> ia:"ParameterPort-intercept" [label="" arrowhead=box color=purple penwidth=1]\n\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_noise" -> ia:"ParameterPort-noise" [label="" arrowhead=box color=purple penwidth=1]\n\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_slope" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=blue penwidth=1]\n\t\t"icomp OUTPUT_CIM" [label=<
Mechanism:
icomp Output_CIM
InputPorts
OUTPUT_CIM_ia_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\t\tia:"OutputPort-RESULT" -> "icomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ia_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\tlabel=icomp\n\t}\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\toa:"OutputPort-RESULT" -> "icomp INPUT_CIM":"InputPort-INPUT_CIM_ia_InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> "icomp PARAMETER_CIM":"InputPort-PARAMETER_CIM_ia_slope" [label="" arrowhead=normal color=blue penwidth=1]\n\t"icomp OUTPUT_CIM":"OutputPort-OUTPUT_CIM_ia_RESULT" -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [label=<
INPUT_CIM_ob_InputPort-0INPUT_CIM_oa_InputPort-0
OutputPorts
Mechanism:
ocomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ob:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> oa:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp OUTPUT_CIM" [label=<
Mechanism:
ocomp Output_CIM
InputPorts
OUTPUT_CIM_ob_RESULTOUTPUT_CIM_oc_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\tob:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ob_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_oc_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> "icomp PARAMETER_CIM":"InputPort-PARAMETER_CIM_ia_noise" [label="" arrowhead=normal color=purple penwidth=1]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> "icomp PARAMETER_CIM":"InputPort-PARAMETER_CIM_ia_intercept" [label="" arrowhead=normal color=purple penwidth=1]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-Shadowed input of of ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-Shadowed input of of oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of ob[InputPort-0]Shadowed input of of oa[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\t"icomp INPUT_CIM" [label=<
INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
icomp Input_CIM
InputPorts
INPUT_CIM_ia_InputPort-0
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"icomp INPUT_CIM":"OutputPort-INPUT_CIM_ia_InputPort-0" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"icomp PARAMETER_CIM" [label=<
PARAMETER_CIM_ia_interceptPARAMETER_CIM_ia_noisePARAMETER_CIM_ia_slope
OutputPorts
Mechanism:
icomp Parameter_CIM
InputPorts
PARAMETER_CIM_ia_interceptPARAMETER_CIM_ia_noisePARAMETER_CIM_ia_slope
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_intercept" -> ia:"ParameterPort-intercept" [label="" arrowhead=box color=purple penwidth=1]\n\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_noise" -> ia:"ParameterPort-noise" [label="" arrowhead=box color=purple penwidth=1]\n\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_slope" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=blue penwidth=1]\n\t\t"icomp OUTPUT_CIM" [label=<
OUTPUT_CIM_ia_RESULT
OutputPorts
Mechanism:
icomp Output_CIM
InputPorts
OUTPUT_CIM_ia_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\t\tia:"OutputPort-RESULT" -> "icomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ia_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\tlabel=icomp\n\t}\n}' + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\tlabel=icomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\toa -> ia [label="" arrowhead=normal color=black penwidth=1]\n\tctl_mech -> ia [label="" arrowhead=box color=blue penwidth=1]\n\tia -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\tlabel=icomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"ocomp INPUT_CIM" -> ob [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> oa [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\tob -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\toc -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> icomp [label="" arrowhead=normal color=blue penwidth=1]\n\toa -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"ocomp INPUT_CIM" -> ob [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> oa [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\tob -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\toc -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tocm -> icomp [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm -> icomp [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\t"icomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t"icomp INPUT_CIM" -> ia [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM" [color=purple penwidth=1 rank=same shape=rectangle]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=blue penwidth=1 style=solid]\n\t\t"icomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\tia -> "icomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\tlabel=icomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\toa -> "icomp INPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tctl_mech -> "icomp PARAMETER_CIM" [label="" arrowhead=normal color=blue penwidth=1 style=solid]\n\t"icomp OUTPUT_CIM" -> oc [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"ocomp INPUT_CIM" -> ob [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> oa [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\tob -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\toc -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tocm -> "icomp PARAMETER_CIM" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm -> "icomp PARAMETER_CIM" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\t"icomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t"icomp INPUT_CIM" -> ia [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM" [color=purple penwidth=1 rank=same shape=rectangle]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=blue penwidth=1 style=solid]\n\t\t"icomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\tia -> "icomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\tlabel=icomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\tlabel=icomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\toa:"OutputPort-RESULT" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=blue penwidth=1]\n\tia:"OutputPort-RESULT" -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> ia:"ParameterPort-noise" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> ia:"ParameterPort-intercept" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\tlabel=icomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [label=<
INPUT_CIM_ob_InputPort-0INPUT_CIM_oa_InputPort-0
OutputPorts
Mechanism:
ocomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ob:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> oa:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp OUTPUT_CIM" [label=<
Mechanism:
ocomp Output_CIM
InputPorts
OUTPUT_CIM_ob_RESULTOUTPUT_CIM_oc_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\tob:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ob_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\toc:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_oc_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> icomp [label="" arrowhead=normal color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [label=<
INPUT_CIM_ob_InputPort-0INPUT_CIM_oa_InputPort-0
OutputPorts
Mechanism:
ocomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ob:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> oa:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp OUTPUT_CIM" [label=<
Mechanism:
ocomp Output_CIM
InputPorts
OUTPUT_CIM_ob_RESULTOUTPUT_CIM_oc_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\tob:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ob_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\toc:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_oc_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> icomp [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> icomp [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\t"icomp INPUT_CIM" [label=<
INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
icomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"icomp INPUT_CIM":"OutputPort-INPUT_CIM_ia_InputPort-0" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM" [label=<
PARAMETER_CIM_ia_interceptPARAMETER_CIM_ia_noisePARAMETER_CIM_ia_slope
OutputPorts
Mechanism:
icomp Parameter_CIM
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_intercept" -> ia:"ParameterPort-intercept" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_noise" -> ia:"ParameterPort-noise" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_slope" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=blue penwidth=1 style=solid]\n\t\t"icomp OUTPUT_CIM" [label=<
Mechanism:
icomp Output_CIM
InputPorts
OUTPUT_CIM_ia_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\t\tia:"OutputPort-RESULT" -> "icomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ia_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\tlabel=icomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\toa:"OutputPort-RESULT" -> "icomp INPUT_CIM":"InputPort-INPUT_CIM_ia_InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> "icomp PARAMETER_CIM":"InputPort-PARAMETER_CIM_ia_slope" [label="" arrowhead=normal color=blue penwidth=1 style=solid]\n\t"icomp OUTPUT_CIM":"OutputPort-OUTPUT_CIM_ia_RESULT" -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [label=<
INPUT_CIM_ob_InputPort-0INPUT_CIM_oa_InputPort-0
OutputPorts
Mechanism:
ocomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ob:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> oa:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp OUTPUT_CIM" [label=<
Mechanism:
ocomp Output_CIM
InputPorts
OUTPUT_CIM_ob_RESULTOUTPUT_CIM_oc_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\tob:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ob_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\toc:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_oc_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> "icomp PARAMETER_CIM":"InputPort-PARAMETER_CIM_ia_noise" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> "icomp PARAMETER_CIM":"InputPort-PARAMETER_CIM_ia_intercept" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\t"icomp INPUT_CIM" [label=<
INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
icomp Input_CIM
InputPorts
INPUT_CIM_ia_InputPort-0
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"icomp INPUT_CIM":"OutputPort-INPUT_CIM_ia_InputPort-0" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM" [label=<
PARAMETER_CIM_ia_interceptPARAMETER_CIM_ia_noisePARAMETER_CIM_ia_slope
OutputPorts
Mechanism:
icomp Parameter_CIM
InputPorts
PARAMETER_CIM_ia_interceptPARAMETER_CIM_ia_noisePARAMETER_CIM_ia_slope
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_intercept" -> ia:"ParameterPort-intercept" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_noise" -> ia:"ParameterPort-noise" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_slope" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=blue penwidth=1 style=solid]\n\t\t"icomp OUTPUT_CIM" [label=<
OUTPUT_CIM_ia_RESULT
OutputPorts
Mechanism:
icomp Output_CIM
InputPorts
OUTPUT_CIM_ia_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\t\tia:"OutputPort-RESULT" -> "icomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ia_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\tlabel=icomp\n\t}\n}' ] @pytest.mark.parametrize( @@ -556,18 +558,18 @@ def test_of_show_nested_show_cim_and_show_node_structure( # each item corresponds to the same item in _nested_show_graph_kwargs above _of_show_3_level_nested_show_cim_and_show_node_structure_outputs = [ - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\tmidcomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> midcomp [label="" arrowhead=box color=blue penwidth=1]\n\toa -> midcomp [label="" arrowhead=normal color=black penwidth=1]\n\tmidcomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> midcomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> midcomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\tmidcomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> midcomp [label="" arrowhead=box color=blue penwidth=1]\n\toa -> midcomp [label="" arrowhead=normal color=black penwidth=1]\n\tmidcomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> midcomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> midcomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_midcomp {\n\t\tgraph [label=midcomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tma [color=green penwidth=3 rank=source shape=oval]\n\t\ticomp [color=red penwidth=3 rank=max shape=rectangle]\n\t\tma -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\t\tsubgraph cluster_icomp {\n\t\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\t\tedge [fontname=arial fontsize=10]\n\t\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\t\tcolor=red\n\t\t\tlabel=icomp\n\t\t}\n\t\tlabel=midcomp\n\t}\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\toa -> ma [label="" arrowhead=normal color=black penwidth=1]\n\tctl_mech -> ia [label="" arrowhead=box color=blue penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> ia [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> ia [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_midcomp {\n\t\tgraph [label=midcomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tma [color=green penwidth=3 rank=source shape=oval]\n\t\tma -> ia [label="" arrowhead=normal color=black penwidth=1]\n\t\tsubgraph cluster_icomp {\n\t\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\t\tedge [fontname=arial fontsize=10]\n\t\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\t\tcolor=red\n\t\t\tlabel=icomp\n\t\t}\n\t\tlabel=midcomp\n\t}\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\tmidcomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> midcomp [label="" arrowhead=box color=blue penwidth=1]\n\toa -> midcomp [label="" arrowhead=normal color=black penwidth=1]\n\tmidcomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"ocomp INPUT_CIM" -> oa [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" -> ob [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\toc -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tob -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> midcomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> midcomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\tmidcomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> midcomp [label="" arrowhead=normal color=blue penwidth=1]\n\toa -> midcomp [label="" arrowhead=normal color=black penwidth=1]\n\tmidcomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"ocomp INPUT_CIM" -> oa [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" -> ob [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\toc -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tob -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> midcomp [label="" arrowhead=normal color=purple penwidth=1]\n\tocm -> midcomp [label="" arrowhead=normal color=purple penwidth=1]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_midcomp {\n\t\tgraph [label=midcomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tma [color=green penwidth=3 rank=source shape=oval]\n\t\ticomp [color=red penwidth=3 rank=max shape=rectangle]\n\t\tma -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\t\t"midcomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t"midcomp INPUT_CIM" -> ma [label="" arrowhead=normal color=black penwidth=1]\n\t\t"midcomp PARAMETER_CIM" [color=purple penwidth=1 rank=same shape=rectangle]\n\t\t"midcomp PARAMETER_CIM" -> icomp [label="" arrowhead=normal color=blue penwidth=1]\n\t\t"midcomp PARAMETER_CIM" -> icomp [label="" arrowhead=normal color=purple penwidth=1]\n\t\t"midcomp PARAMETER_CIM" -> icomp [label="" arrowhead=normal color=purple penwidth=1]\n\t\t"midcomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\ticomp -> "midcomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\t\tsubgraph cluster_icomp {\n\t\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\t\tedge [fontname=arial fontsize=10]\n\t\t\t"icomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t\t"icomp INPUT_CIM" -> ia [label="" arrowhead=normal color=black penwidth=1]\n\t\t\t"icomp PARAMETER_CIM" [color=purple penwidth=1 rank=same shape=rectangle]\n\t\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1]\n\t\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1]\n\t\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=blue penwidth=1]\n\t\t\t"icomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\t\tia -> "icomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\t\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\t\tcolor=red\n\t\t\tlabel=icomp\n\t\t}\n\t\tlabel=midcomp\n\t}\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\toa -> "midcomp INPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tctl_mech -> "midcomp PARAMETER_CIM" [label="" arrowhead=normal color=blue penwidth=1]\n\t"midcomp OUTPUT_CIM" -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"ocomp INPUT_CIM" -> oa [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" -> ob [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\toc -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tob -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> "midcomp PARAMETER_CIM" [label="" arrowhead=normal color=purple penwidth=1]\n\tocm -> "midcomp PARAMETER_CIM" [label="" arrowhead=normal color=purple penwidth=1]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_midcomp {\n\t\tgraph [label=midcomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tma [color=green penwidth=3 rank=source shape=oval]\n\t\tma -> "icomp INPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"midcomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t"midcomp INPUT_CIM" -> ma [label="" arrowhead=normal color=black penwidth=1]\n\t\t"midcomp PARAMETER_CIM" [color=purple penwidth=1 rank=same shape=rectangle]\n\t\t"midcomp PARAMETER_CIM" -> "icomp PARAMETER_CIM" [label="" arrowhead=normal color=blue penwidth=1]\n\t\t"midcomp PARAMETER_CIM" -> "icomp PARAMETER_CIM" [label="" arrowhead=normal color=purple penwidth=1]\n\t\t"midcomp PARAMETER_CIM" -> "icomp PARAMETER_CIM" [label="" arrowhead=normal color=purple penwidth=1]\n\t\t"midcomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\t"icomp OUTPUT_CIM" -> "midcomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\t\tsubgraph cluster_icomp {\n\t\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\t\tedge [fontname=arial fontsize=10]\n\t\t\t"icomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t\t"icomp INPUT_CIM" -> ia [label="" arrowhead=normal color=black penwidth=1]\n\t\t\t"icomp PARAMETER_CIM" [color=purple penwidth=1 rank=same shape=rectangle]\n\t\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1]\n\t\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1]\n\t\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=blue penwidth=1]\n\t\t\t"icomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\t\tia -> "icomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\t\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\t\tcolor=red\n\t\t\tlabel=icomp\n\t\t}\n\t\tlabel=midcomp\n\t}\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tmidcomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> midcomp [label="" arrowhead=box color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> midcomp [label="" arrowhead=normal color=black penwidth=1]\n\tmidcomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> midcomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> midcomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-Shadowed input of of oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-Shadowed input of of ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of oa[InputPort-0]Shadowed input of of ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tmidcomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> midcomp [label="" arrowhead=box color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> midcomp [label="" arrowhead=normal color=black penwidth=1]\n\tmidcomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> midcomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> midcomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-Shadowed input of of oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-Shadowed input of of ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of oa[InputPort-0]Shadowed input of of ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_midcomp {\n\t\tgraph [label=midcomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tma [label=<
RESULT
OutputPorts
Mechanism:
ma
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\ticomp [color=red penwidth=3 rank=max shape=rectangle]\n\t\tma:"OutputPort-RESULT" -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\t\tsubgraph cluster_icomp {\n\t\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\t\tedge [fontname=arial fontsize=10]\n\t\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\t\tcolor=red\n\t\t\tlabel=icomp\n\t\t}\n\t\tlabel=midcomp\n\t}\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\toa:"OutputPort-RESULT" -> ma:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=blue penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> ia:"ParameterPort-noise" [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> ia:"ParameterPort-intercept" [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-Shadowed input of of oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-Shadowed input of of ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of oa[InputPort-0]Shadowed input of of ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_midcomp {\n\t\tgraph [label=midcomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tma [label=<
RESULT
OutputPorts
Mechanism:
ma
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\tma:"OutputPort-RESULT" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tsubgraph cluster_icomp {\n\t\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\t\tedge [fontname=arial fontsize=10]\n\t\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\t\tcolor=red\n\t\t\tlabel=icomp\n\t\t}\n\t\tlabel=midcomp\n\t}\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tmidcomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> midcomp [label="" arrowhead=box color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> midcomp [label="" arrowhead=normal color=black penwidth=1]\n\tmidcomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [label=<
INPUT_CIM_oa_InputPort-0INPUT_CIM_ob_InputPort-0
OutputPorts
Mechanism:
ocomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> oa:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ob:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp OUTPUT_CIM" [label=<
Mechanism:
ocomp Output_CIM
InputPorts
OUTPUT_CIM_oc_RESULTOUTPUT_CIM_ob_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\toc:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_oc_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\tob:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ob_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> midcomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> midcomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-Shadowed input of of oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-Shadowed input of of ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of oa[InputPort-0]Shadowed input of of ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tmidcomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> midcomp [label="" arrowhead=normal color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> midcomp [label="" arrowhead=normal color=black penwidth=1]\n\tmidcomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [label=<
INPUT_CIM_oa_InputPort-0INPUT_CIM_ob_InputPort-0
OutputPorts
Mechanism:
ocomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> oa:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ob:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp OUTPUT_CIM" [label=<
Mechanism:
ocomp Output_CIM
InputPorts
OUTPUT_CIM_oc_RESULTOUTPUT_CIM_ob_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\toc:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_oc_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\tob:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ob_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> midcomp [label="" arrowhead=normal color=purple penwidth=1]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> midcomp [label="" arrowhead=normal color=purple penwidth=1]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-Shadowed input of of oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-Shadowed input of of ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of oa[InputPort-0]Shadowed input of of ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_midcomp {\n\t\tgraph [label=midcomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tma [label=<
RESULT
OutputPorts
Mechanism:
ma
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\ticomp [color=red penwidth=3 rank=max shape=rectangle]\n\t\tma:"OutputPort-RESULT" -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\t\t"midcomp INPUT_CIM" [label=<
INPUT_CIM_ma_InputPort-0
OutputPorts
Mechanism:
midcomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"midcomp INPUT_CIM":"OutputPort-INPUT_CIM_ma_InputPort-0" -> ma:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"midcomp PARAMETER_CIM" [label=<
PARAMETER_CIM_ia_slopePARAMETER_CIM_ia_noisePARAMETER_CIM_ia_intercept
OutputPorts
Mechanism:
midcomp Parameter_CIM
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t"midcomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_slope" -> icomp [label="" arrowhead=normal color=blue penwidth=1]\n\t\t"midcomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_noise" -> icomp [label="" arrowhead=normal color=purple penwidth=1]\n\t\t"midcomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_intercept" -> icomp [label="" arrowhead=normal color=purple penwidth=1]\n\t\t"midcomp OUTPUT_CIM" [label=<
Mechanism:
midcomp Output_CIM
InputPorts
OUTPUT_CIM_icomp_OUTPUT_CIM_ia_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\t\ticomp -> "midcomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_icomp_OUTPUT_CIM_ia_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\t\tsubgraph cluster_icomp {\n\t\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\t\tedge [fontname=arial fontsize=10]\n\t\t\t"icomp INPUT_CIM" [label=<
INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
icomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t\t"icomp INPUT_CIM":"OutputPort-INPUT_CIM_ia_InputPort-0" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t\t"icomp PARAMETER_CIM" [label=<
PARAMETER_CIM_ia_interceptPARAMETER_CIM_ia_noisePARAMETER_CIM_ia_slope
OutputPorts
Mechanism:
icomp Parameter_CIM
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_intercept" -> ia:"ParameterPort-intercept" [label="" arrowhead=box color=purple penwidth=1]\n\t\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_noise" -> ia:"ParameterPort-noise" [label="" arrowhead=box color=purple penwidth=1]\n\t\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_slope" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=blue penwidth=1]\n\t\t\t"icomp OUTPUT_CIM" [label=<
Mechanism:
icomp Output_CIM
InputPorts
OUTPUT_CIM_ia_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\t\t\tia:"OutputPort-RESULT" -> "icomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ia_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\t\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\t\tcolor=red\n\t\t\tlabel=icomp\n\t\t}\n\t\tlabel=midcomp\n\t}\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\toa:"OutputPort-RESULT" -> "midcomp INPUT_CIM":"InputPort-INPUT_CIM_ma_InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> "midcomp PARAMETER_CIM":"InputPort-PARAMETER_CIM_ia_slope" [label="" arrowhead=normal color=blue penwidth=1]\n\t"midcomp OUTPUT_CIM":"OutputPort-OUTPUT_CIM_icomp_OUTPUT_CIM_ia_RESULT" -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [label=<
INPUT_CIM_oa_InputPort-0INPUT_CIM_ob_InputPort-0
OutputPorts
Mechanism:
ocomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> oa:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ob:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp OUTPUT_CIM" [label=<
Mechanism:
ocomp Output_CIM
InputPorts
OUTPUT_CIM_oc_RESULTOUTPUT_CIM_ob_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\toc:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_oc_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\tob:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ob_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> "midcomp PARAMETER_CIM":"InputPort-PARAMETER_CIM_ia_noise" [label="" arrowhead=normal color=purple penwidth=1]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> "midcomp PARAMETER_CIM":"InputPort-PARAMETER_CIM_ia_intercept" [label="" arrowhead=normal color=purple penwidth=1]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-Shadowed input of of oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-Shadowed input of of ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of oa[InputPort-0]Shadowed input of of ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_midcomp {\n\t\tgraph [label=midcomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tma [label=<
RESULT
OutputPorts
Mechanism:
ma
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\tma:"OutputPort-RESULT" -> "icomp INPUT_CIM":"InputPort-INPUT_CIM_ia_InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"midcomp INPUT_CIM" [label=<
INPUT_CIM_ma_InputPort-0
OutputPorts
Mechanism:
midcomp Input_CIM
InputPorts
INPUT_CIM_ma_InputPort-0
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"midcomp INPUT_CIM":"OutputPort-INPUT_CIM_ma_InputPort-0" -> ma:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"midcomp PARAMETER_CIM" [label=<
PARAMETER_CIM_ia_slopePARAMETER_CIM_ia_noisePARAMETER_CIM_ia_intercept
OutputPorts
Mechanism:
midcomp Parameter_CIM
InputPorts
PARAMETER_CIM_ia_slopePARAMETER_CIM_ia_noisePARAMETER_CIM_ia_intercept
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t"midcomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_slope" -> "icomp PARAMETER_CIM":"InputPort-PARAMETER_CIM_ia_slope" [label="" arrowhead=normal color=blue penwidth=1]\n\t\t"midcomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_noise" -> "icomp PARAMETER_CIM":"InputPort-PARAMETER_CIM_ia_noise" [label="" arrowhead=normal color=purple penwidth=1]\n\t\t"midcomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_intercept" -> "icomp PARAMETER_CIM":"InputPort-PARAMETER_CIM_ia_intercept" [label="" arrowhead=normal color=purple penwidth=1]\n\t\t"midcomp OUTPUT_CIM" [label=<
OUTPUT_CIM_icomp_OUTPUT_CIM_ia_RESULT
OutputPorts
Mechanism:
midcomp Output_CIM
InputPorts
OUTPUT_CIM_icomp_OUTPUT_CIM_ia_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\t\t"icomp OUTPUT_CIM":"OutputPort-OUTPUT_CIM_ia_RESULT" -> "midcomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_icomp_OUTPUT_CIM_ia_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\t\tsubgraph cluster_icomp {\n\t\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\t\tedge [fontname=arial fontsize=10]\n\t\t\t"icomp INPUT_CIM" [label=<
INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
icomp Input_CIM
InputPorts
INPUT_CIM_ia_InputPort-0
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t\t"icomp INPUT_CIM":"OutputPort-INPUT_CIM_ia_InputPort-0" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t\t"icomp PARAMETER_CIM" [label=<
PARAMETER_CIM_ia_interceptPARAMETER_CIM_ia_noisePARAMETER_CIM_ia_slope
OutputPorts
Mechanism:
icomp Parameter_CIM
InputPorts
PARAMETER_CIM_ia_interceptPARAMETER_CIM_ia_noisePARAMETER_CIM_ia_slope
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_intercept" -> ia:"ParameterPort-intercept" [label="" arrowhead=box color=purple penwidth=1]\n\t\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_noise" -> ia:"ParameterPort-noise" [label="" arrowhead=box color=purple penwidth=1]\n\t\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_slope" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=blue penwidth=1]\n\t\t\t"icomp OUTPUT_CIM" [label=<
OUTPUT_CIM_ia_RESULT
OutputPorts
Mechanism:
icomp Output_CIM
InputPorts
OUTPUT_CIM_ia_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\t\t\tia:"OutputPort-RESULT" -> "icomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ia_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\t\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\t\tcolor=red\n\t\t\tlabel=icomp\n\t\t}\n\t\tlabel=midcomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\tmidcomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> midcomp [label="" arrowhead=box color=blue penwidth=1]\n\toa -> midcomp [label="" arrowhead=normal color=black penwidth=1]\n\tmidcomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> midcomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> midcomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\tmidcomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> midcomp [label="" arrowhead=box color=blue penwidth=1]\n\toa -> midcomp [label="" arrowhead=normal color=black penwidth=1]\n\tmidcomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> midcomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> midcomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_midcomp {\n\t\tgraph [label=midcomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tma [color=green penwidth=3 rank=source shape=oval]\n\t\ticomp [color=red penwidth=3 rank=max shape=rectangle]\n\t\tma -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\t\tsubgraph cluster_icomp {\n\t\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\t\tedge [fontname=arial fontsize=10]\n\t\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\t\tcolor=red\n\t\t\tlabel=icomp\n\t\t}\n\t\tlabel=midcomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\toa -> ma [label="" arrowhead=normal color=black penwidth=1]\n\tctl_mech -> ia [label="" arrowhead=box color=blue penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_midcomp {\n\t\tgraph [label=midcomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tma [color=green penwidth=3 rank=source shape=oval]\n\t\tma -> ia [label="" arrowhead=normal color=black penwidth=1]\n\t\tsubgraph cluster_icomp {\n\t\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\t\tedge [fontname=arial fontsize=10]\n\t\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\t\tcolor=red\n\t\t\tlabel=icomp\n\t\t}\n\t\tlabel=midcomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\tmidcomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> midcomp [label="" arrowhead=box color=blue penwidth=1]\n\toa -> midcomp [label="" arrowhead=normal color=black penwidth=1]\n\tmidcomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"ocomp INPUT_CIM" -> oa [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ob [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\toc -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tob -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tocm -> midcomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> midcomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\tmidcomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> midcomp [label="" arrowhead=normal color=blue penwidth=1]\n\toa -> midcomp [label="" arrowhead=normal color=black penwidth=1]\n\tmidcomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"ocomp INPUT_CIM" -> oa [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ob [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\toc -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tob -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tocm -> midcomp [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm -> midcomp [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_midcomp {\n\t\tgraph [label=midcomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tma [color=green penwidth=3 rank=source shape=oval]\n\t\ticomp [color=red penwidth=3 rank=max shape=rectangle]\n\t\tma -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\t\t"midcomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t"midcomp INPUT_CIM" -> ma [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"midcomp PARAMETER_CIM" [color=purple penwidth=1 rank=same shape=rectangle]\n\t\t"midcomp PARAMETER_CIM" -> icomp [label="" arrowhead=normal color=blue penwidth=1 style=solid]\n\t\t"midcomp PARAMETER_CIM" -> icomp [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\t\t"midcomp PARAMETER_CIM" -> icomp [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\t\t"midcomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\ticomp -> "midcomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tsubgraph cluster_icomp {\n\t\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\t\tedge [fontname=arial fontsize=10]\n\t\t\t"icomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t\t"icomp INPUT_CIM" -> ia [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t\t"icomp PARAMETER_CIM" [color=purple penwidth=1 rank=same shape=rectangle]\n\t\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=blue penwidth=1 style=solid]\n\t\t\t"icomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\t\tia -> "icomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\t\tcolor=red\n\t\t\tlabel=icomp\n\t\t}\n\t\tlabel=midcomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\toa -> "midcomp INPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tctl_mech -> "midcomp PARAMETER_CIM" [label="" arrowhead=normal color=blue penwidth=1 style=solid]\n\t"midcomp OUTPUT_CIM" -> oc [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"ocomp INPUT_CIM" -> oa [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ob [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\toc -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tob -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tocm -> "midcomp PARAMETER_CIM" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm -> "midcomp PARAMETER_CIM" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_midcomp {\n\t\tgraph [label=midcomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tma [color=green penwidth=3 rank=source shape=oval]\n\t\tma -> "icomp INPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"midcomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t"midcomp INPUT_CIM" -> ma [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"midcomp PARAMETER_CIM" [color=purple penwidth=1 rank=same shape=rectangle]\n\t\t"midcomp PARAMETER_CIM" -> "icomp PARAMETER_CIM" [label="" arrowhead=normal color=blue penwidth=1 style=solid]\n\t\t"midcomp PARAMETER_CIM" -> "icomp PARAMETER_CIM" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\t\t"midcomp PARAMETER_CIM" -> "icomp PARAMETER_CIM" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\t\t"midcomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\t"icomp OUTPUT_CIM" -> "midcomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tsubgraph cluster_icomp {\n\t\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\t\tedge [fontname=arial fontsize=10]\n\t\t\t"icomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t\t"icomp INPUT_CIM" -> ia [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t\t"icomp PARAMETER_CIM" [color=purple penwidth=1 rank=same shape=rectangle]\n\t\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=blue penwidth=1 style=solid]\n\t\t\t"icomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\t\tia -> "icomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\t\tcolor=red\n\t\t\tlabel=icomp\n\t\t}\n\t\tlabel=midcomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tmidcomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> midcomp [label="" arrowhead=box color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> midcomp [label="" arrowhead=normal color=black penwidth=1]\n\tmidcomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> midcomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> midcomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tmidcomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> midcomp [label="" arrowhead=box color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> midcomp [label="" arrowhead=normal color=black penwidth=1]\n\tmidcomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> midcomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> midcomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_midcomp {\n\t\tgraph [label=midcomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tma [label=<
RESULT
OutputPorts
Mechanism:
ma
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\ticomp [color=red penwidth=3 rank=max shape=rectangle]\n\t\tma:"OutputPort-RESULT" -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\t\tsubgraph cluster_icomp {\n\t\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\t\tedge [fontname=arial fontsize=10]\n\t\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\t\tcolor=red\n\t\t\tlabel=icomp\n\t\t}\n\t\tlabel=midcomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\toa:"OutputPort-RESULT" -> ma:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=blue penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> ia:"ParameterPort-noise" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> ia:"ParameterPort-intercept" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_midcomp {\n\t\tgraph [label=midcomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tma [label=<
RESULT
OutputPorts
Mechanism:
ma
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\tma:"OutputPort-RESULT" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tsubgraph cluster_icomp {\n\t\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\t\tedge [fontname=arial fontsize=10]\n\t\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\t\tcolor=red\n\t\t\tlabel=icomp\n\t\t}\n\t\tlabel=midcomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tmidcomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> midcomp [label="" arrowhead=box color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> midcomp [label="" arrowhead=normal color=black penwidth=1]\n\tmidcomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [label=<
INPUT_CIM_oa_InputPort-0INPUT_CIM_ob_InputPort-0
OutputPorts
Mechanism:
ocomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> oa:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ob:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp OUTPUT_CIM" [label=<
Mechanism:
ocomp Output_CIM
InputPorts
OUTPUT_CIM_oc_RESULTOUTPUT_CIM_ob_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\toc:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_oc_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tob:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ob_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> midcomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> midcomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\tmidcomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> midcomp [label="" arrowhead=normal color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> midcomp [label="" arrowhead=normal color=black penwidth=1]\n\tmidcomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [label=<
INPUT_CIM_oa_InputPort-0INPUT_CIM_ob_InputPort-0
OutputPorts
Mechanism:
ocomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> oa:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ob:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp OUTPUT_CIM" [label=<
Mechanism:
ocomp Output_CIM
InputPorts
OUTPUT_CIM_oc_RESULTOUTPUT_CIM_ob_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\toc:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_oc_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tob:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ob_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> midcomp [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> midcomp [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_midcomp {\n\t\tgraph [label=midcomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tma [label=<
RESULT
OutputPorts
Mechanism:
ma
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\ticomp [color=red penwidth=3 rank=max shape=rectangle]\n\t\tma:"OutputPort-RESULT" -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\t\t"midcomp INPUT_CIM" [label=<
INPUT_CIM_ma_InputPort-0
OutputPorts
Mechanism:
midcomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"midcomp INPUT_CIM":"OutputPort-INPUT_CIM_ma_InputPort-0" -> ma:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"midcomp PARAMETER_CIM" [label=<
PARAMETER_CIM_ia_slopePARAMETER_CIM_ia_noisePARAMETER_CIM_ia_intercept
OutputPorts
Mechanism:
midcomp Parameter_CIM
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t"midcomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_slope" -> icomp [label="" arrowhead=normal color=blue penwidth=1 style=solid]\n\t\t"midcomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_noise" -> icomp [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\t\t"midcomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_intercept" -> icomp [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\t\t"midcomp OUTPUT_CIM" [label=<
Mechanism:
midcomp Output_CIM
InputPorts
OUTPUT_CIM_icomp_OUTPUT_CIM_ia_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\t\ticomp -> "midcomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_icomp_OUTPUT_CIM_ia_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tsubgraph cluster_icomp {\n\t\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\t\tedge [fontname=arial fontsize=10]\n\t\t\t"icomp INPUT_CIM" [label=<
INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
icomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t\t"icomp INPUT_CIM":"OutputPort-INPUT_CIM_ia_InputPort-0" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t\t"icomp PARAMETER_CIM" [label=<
PARAMETER_CIM_ia_interceptPARAMETER_CIM_ia_noisePARAMETER_CIM_ia_slope
OutputPorts
Mechanism:
icomp Parameter_CIM
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_intercept" -> ia:"ParameterPort-intercept" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_noise" -> ia:"ParameterPort-noise" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_slope" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=blue penwidth=1 style=solid]\n\t\t\t"icomp OUTPUT_CIM" [label=<
Mechanism:
icomp Output_CIM
InputPorts
OUTPUT_CIM_ia_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\t\t\tia:"OutputPort-RESULT" -> "icomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ia_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\t\tcolor=red\n\t\t\tlabel=icomp\n\t\t}\n\t\tlabel=midcomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\toa:"OutputPort-RESULT" -> "midcomp INPUT_CIM":"InputPort-INPUT_CIM_ma_InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> "midcomp PARAMETER_CIM":"InputPort-PARAMETER_CIM_ia_slope" [label="" arrowhead=normal color=blue penwidth=1 style=solid]\n\t"midcomp OUTPUT_CIM":"OutputPort-OUTPUT_CIM_icomp_OUTPUT_CIM_ia_RESULT" -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [label=<
INPUT_CIM_oa_InputPort-0INPUT_CIM_ob_InputPort-0
OutputPorts
Mechanism:
ocomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> oa:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ob:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp OUTPUT_CIM" [label=<
Mechanism:
ocomp Output_CIM
InputPorts
OUTPUT_CIM_oc_RESULTOUTPUT_CIM_ob_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\toc:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_oc_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tob:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ob_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> "midcomp PARAMETER_CIM":"InputPort-PARAMETER_CIM_ia_noise" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> "midcomp PARAMETER_CIM":"InputPort-PARAMETER_CIM_ia_intercept" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_midcomp {\n\t\tgraph [label=midcomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tma [label=<
RESULT
OutputPorts
Mechanism:
ma
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\tma:"OutputPort-RESULT" -> "icomp INPUT_CIM":"InputPort-INPUT_CIM_ia_InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"midcomp INPUT_CIM" [label=<
INPUT_CIM_ma_InputPort-0
OutputPorts
Mechanism:
midcomp Input_CIM
InputPorts
INPUT_CIM_ma_InputPort-0
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"midcomp INPUT_CIM":"OutputPort-INPUT_CIM_ma_InputPort-0" -> ma:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"midcomp PARAMETER_CIM" [label=<
PARAMETER_CIM_ia_slopePARAMETER_CIM_ia_noisePARAMETER_CIM_ia_intercept
OutputPorts
Mechanism:
midcomp Parameter_CIM
InputPorts
PARAMETER_CIM_ia_slopePARAMETER_CIM_ia_noisePARAMETER_CIM_ia_intercept
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t"midcomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_slope" -> "icomp PARAMETER_CIM":"InputPort-PARAMETER_CIM_ia_slope" [label="" arrowhead=normal color=blue penwidth=1 style=solid]\n\t\t"midcomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_noise" -> "icomp PARAMETER_CIM":"InputPort-PARAMETER_CIM_ia_noise" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\t\t"midcomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_intercept" -> "icomp PARAMETER_CIM":"InputPort-PARAMETER_CIM_ia_intercept" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\t\t"midcomp OUTPUT_CIM" [label=<
OUTPUT_CIM_icomp_OUTPUT_CIM_ia_RESULT
OutputPorts
Mechanism:
midcomp Output_CIM
InputPorts
OUTPUT_CIM_icomp_OUTPUT_CIM_ia_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\t\t"icomp OUTPUT_CIM":"OutputPort-OUTPUT_CIM_ia_RESULT" -> "midcomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_icomp_OUTPUT_CIM_ia_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tsubgraph cluster_icomp {\n\t\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\t\tedge [fontname=arial fontsize=10]\n\t\t\t"icomp INPUT_CIM" [label=<
INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
icomp Input_CIM
InputPorts
INPUT_CIM_ia_InputPort-0
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t\t"icomp INPUT_CIM":"OutputPort-INPUT_CIM_ia_InputPort-0" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t\t"icomp PARAMETER_CIM" [label=<
PARAMETER_CIM_ia_interceptPARAMETER_CIM_ia_noisePARAMETER_CIM_ia_slope
OutputPorts
Mechanism:
icomp Parameter_CIM
InputPorts
PARAMETER_CIM_ia_interceptPARAMETER_CIM_ia_noisePARAMETER_CIM_ia_slope
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_intercept" -> ia:"ParameterPort-intercept" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_noise" -> ia:"ParameterPort-noise" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_slope" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=blue penwidth=1 style=solid]\n\t\t\t"icomp OUTPUT_CIM" [label=<
OUTPUT_CIM_ia_RESULT
OutputPorts
Mechanism:
icomp Output_CIM
InputPorts
OUTPUT_CIM_ia_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\t\t\tia:"OutputPort-RESULT" -> "icomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ia_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\t\tcolor=red\n\t\t\tlabel=icomp\n\t\t}\n\t\tlabel=midcomp\n\t}\n}', ] @pytest.mark.parametrize( @@ -615,17 +617,17 @@ def test_of_show_3_level_nested_show_cim_and_show_node_structure( # each item corresponds to the same item in _nested_show_graph_kwargs above _of_show_nested_show_cim_and_show_node_structure_with_singleton_in_outer_comp_added_last_outputs = [ - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\tlabel=icomp\n\t}\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\toa -> ia [label="" arrowhead=normal color=black penwidth=1]\n\tctl_mech -> ia [label="" arrowhead=box color=blue penwidth=1]\n\tia -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> ia [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> ia [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\tlabel=icomp\n\t}\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"ocomp INPUT_CIM" -> oa [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" -> ob [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\toc -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tob -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> icomp [label="" arrowhead=normal color=blue penwidth=1]\n\toa -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"ocomp INPUT_CIM" -> oa [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" -> ob [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\toc -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tob -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> icomp [label="" arrowhead=normal color=purple penwidth=1]\n\tocm -> icomp [label="" arrowhead=normal color=purple penwidth=1]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\t"icomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t"icomp INPUT_CIM" -> ia [label="" arrowhead=normal color=black penwidth=1]\n\t\t"icomp PARAMETER_CIM" [color=purple penwidth=1 rank=same shape=rectangle]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=blue penwidth=1]\n\t\t"icomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\tia -> "icomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\tlabel=icomp\n\t}\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\toa -> "icomp INPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tctl_mech -> "icomp PARAMETER_CIM" [label="" arrowhead=normal color=blue penwidth=1]\n\t"icomp OUTPUT_CIM" -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"ocomp INPUT_CIM" -> oa [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" -> ob [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\toc -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tob -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> "icomp PARAMETER_CIM" [label="" arrowhead=normal color=purple penwidth=1]\n\tocm -> "icomp PARAMETER_CIM" [label="" arrowhead=normal color=purple penwidth=1]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\t"icomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t"icomp INPUT_CIM" -> ia [label="" arrowhead=normal color=black penwidth=1]\n\t\t"icomp PARAMETER_CIM" [color=purple penwidth=1 rank=same shape=rectangle]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=blue penwidth=1]\n\t\t"icomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\tia -> "icomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1]\n\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\tlabel=icomp\n\t}\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-Shadowed input of of oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-Shadowed input of of ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of oa[InputPort-0]Shadowed input of of ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-Shadowed input of of oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-Shadowed input of of ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of oa[InputPort-0]Shadowed input of of ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\tlabel=icomp\n\t}\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\toa:"OutputPort-RESULT" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=blue penwidth=1]\n\tia:"OutputPort-RESULT" -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> ia:"ParameterPort-noise" [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> ia:"ParameterPort-intercept" [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-Shadowed input of of oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-Shadowed input of of ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of oa[InputPort-0]Shadowed input of of ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\tlabel=icomp\n\t}\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [label=<
INPUT_CIM_oa_InputPort-0INPUT_CIM_ob_InputPort-0
OutputPorts
Mechanism:
ocomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> oa:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ob:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp OUTPUT_CIM" [label=<
Mechanism:
ocomp Output_CIM
InputPorts
OUTPUT_CIM_oc_RESULTOUTPUT_CIM_ob_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\toc:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_oc_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\tob:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ob_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-Shadowed input of of oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-Shadowed input of of ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of oa[InputPort-0]Shadowed input of of ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}', - 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> icomp [label="" arrowhead=normal color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [label=<
INPUT_CIM_oa_InputPort-0INPUT_CIM_ob_InputPort-0
OutputPorts
Mechanism:
ocomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> oa:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ob:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp OUTPUT_CIM" [label=<
Mechanism:
ocomp Output_CIM
InputPorts
OUTPUT_CIM_oc_RESULTOUTPUT_CIM_ob_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\toc:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_oc_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\tob:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ob_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> icomp [label="" arrowhead=normal color=purple penwidth=1]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> icomp [label="" arrowhead=normal color=purple penwidth=1]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-Shadowed input of of oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-Shadowed input of of ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMEShadowed input of of oa[InputPort-0]Shadowed input of of ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\t"icomp INPUT_CIM" [label=<
INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
icomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"icomp INPUT_CIM":"OutputPort-INPUT_CIM_ia_InputPort-0" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"icomp PARAMETER_CIM" [label=<
PARAMETER_CIM_ia_interceptPARAMETER_CIM_ia_noisePARAMETER_CIM_ia_slope
OutputPorts
Mechanism:
icomp Parameter_CIM
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_intercept" -> ia:"ParameterPort-intercept" [label="" arrowhead=box color=purple penwidth=1]\n\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_noise" -> ia:"ParameterPort-noise" [label="" arrowhead=box color=purple penwidth=1]\n\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_slope" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=blue penwidth=1]\n\t\t"icomp OUTPUT_CIM" [label=<
Mechanism:
icomp Output_CIM
InputPorts
OUTPUT_CIM_ia_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\t\tia:"OutputPort-RESULT" -> "icomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ia_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\tlabel=icomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\tlabel=icomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\toa -> ia [label="" arrowhead=normal color=black penwidth=1]\n\tctl_mech -> ia [label="" arrowhead=box color=blue penwidth=1]\n\tia -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\tocm -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\tlabel=icomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"ocomp INPUT_CIM" -> oa [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ob [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\toc -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tob -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech -> icomp [label="" arrowhead=normal color=blue penwidth=1]\n\toa -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc [label="" arrowhead=normal color=black penwidth=1]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"ocomp INPUT_CIM" -> oa [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ob [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\toc -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tob -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tocm -> icomp [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm -> icomp [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\t"icomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t"icomp INPUT_CIM" -> ia [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM" [color=purple penwidth=1 rank=same shape=rectangle]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=blue penwidth=1 style=solid]\n\t\t"icomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\tia -> "icomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\tlabel=icomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [color=green penwidth=3 rank=source shape=oval]\n\toa -> "icomp INPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tctl_mech -> "icomp PARAMETER_CIM" [label="" arrowhead=normal color=blue penwidth=1 style=solid]\n\t"icomp OUTPUT_CIM" -> oc [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\toc -> ctl_mech [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"ocomp INPUT_CIM" -> oa [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ob [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\toc -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tob -> "ocomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tocm -> "icomp PARAMETER_CIM" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm -> "icomp PARAMETER_CIM" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm -> oa [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM" -> ocm [label="" arrowhead=normal color=purple penwidth=1]\n\toc [color=red penwidth=3 rank=max shape=oval]\n\tctl_mech [color=blue penwidth=3 rank=max shape=octagon]\n\tob [color=brown penwidth=3 rank=same shape=oval]\n\tocm [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\t"icomp INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t"icomp INPUT_CIM" -> ia [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM" [color=purple penwidth=1 rank=same shape=rectangle]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM" -> ia [label="" arrowhead=box color=blue penwidth=1 style=solid]\n\t\t"icomp OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\tia -> "icomp OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tia [color=brown penwidth=3 rank=same shape=oval]\n\t\tlabel=icomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\tlabel=icomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\toa:"OutputPort-RESULT" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=blue penwidth=1]\n\tia:"OutputPort-RESULT" -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> ia:"ParameterPort-noise" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> ia:"ParameterPort-intercept" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\tlabel=icomp\n\t}\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> icomp [label="" arrowhead=box color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [label=<
INPUT_CIM_oa_InputPort-0INPUT_CIM_ob_InputPort-0
OutputPorts
Mechanism:
ocomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> oa:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ob:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp OUTPUT_CIM" [label=<
Mechanism:
ocomp Output_CIM
InputPorts
OUTPUT_CIM_oc_RESULTOUTPUT_CIM_ob_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\toc:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_oc_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tob:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ob_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> icomp [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}', + 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\ticomp [color=pink penwidth=3 rank=same shape=rectangle]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> icomp [label="" arrowhead=normal color=blue penwidth=1]\n\toa:"OutputPort-RESULT" -> icomp [label="" arrowhead=normal color=black penwidth=1]\n\ticomp -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT_CIM" [label=<
INPUT_CIM_oa_InputPort-0INPUT_CIM_ob_InputPort-0
OutputPorts
Mechanism:
ocomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> oa:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ob:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"ocomp OUTPUT_CIM" [label=<
Mechanism:
ocomp Output_CIM
InputPorts
OUTPUT_CIM_oc_RESULTOUTPUT_CIM_ob_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\toc:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_oc_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tob:"OutputPort-RESULT" -> "ocomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ob_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> icomp [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> icomp [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_oa_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"ocomp INPUT_CIM":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ocm:"InputPort-SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF oa[InputPort-0] FOR oa[InputPort-0]SHADOWED INPUT OF ob[InputPort-0] FOR ob[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\t"icomp INPUT_CIM" [label=<
INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
icomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"icomp INPUT_CIM":"OutputPort-INPUT_CIM_ia_InputPort-0" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM" [label=<
PARAMETER_CIM_ia_interceptPARAMETER_CIM_ia_noisePARAMETER_CIM_ia_slope
OutputPorts
Mechanism:
icomp Parameter_CIM
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_intercept" -> ia:"ParameterPort-intercept" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_noise" -> ia:"ParameterPort-noise" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"icomp PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_slope" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=blue penwidth=1 style=solid]\n\t\t"icomp OUTPUT_CIM" [label=<
Mechanism:
icomp Output_CIM
InputPorts
OUTPUT_CIM_ia_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\t\tia:"OutputPort-RESULT" -> "icomp OUTPUT_CIM":"InputPort-OUTPUT_CIM_ia_RESULT" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\tlabel=icomp\n\t}\n}', # FIX: NEEDS TO BE CORRECTED ONCE BUG IS FIXED (SEE MESSAGE FOR COMMIT eb61303808ad2a5ba46fdd18d0e583283397915c) # 'digraph ocomp {\n\tgraph [label=ocomp overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\toa [label=<
RESULT
OutputPorts
Mechanism:
oa
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\toa:"OutputPort-RESULT" -> "icomp INPUT":"InputPort-INPUT_CIM_ia_InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\tctl_mech:"OutputPort-ia[slope] ControlSignal" -> "icomp CONTROL":"InputPort-PARAMETER_CIM_ia_slope" [label="" arrowhead=normal color=blue penwidth=1]\n\t"icomp OUTPUT":"OutputPort-OUTPUT_CIM_ia_RESULT" -> oc:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\toc:"OutputPort-RESULT" -> ctl_mech:"InputPort-OUTCOME" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT" [label=<
INPUT_CIM_oa_InputPort-0INPUT_CIM_ob_InputPort-0
OutputPorts
Mechanism:
ocomp Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"ocomp INPUT":"OutputPort-INPUT_CIM_oa_InputPort-0" -> oa:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp INPUT":"OutputPort-INPUT_CIM_ob_InputPort-0" -> ob:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"ocomp OUTPUT" [label=<
Mechanism:
ocomp Output_CIM
InputPorts
OUTPUT_CIM_oc_RESULTOUTPUT_CIM_ob_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\toc:"OutputPort-RESULT" -> "ocomp OUTPUT":"InputPort-OUTPUT_CIM_oc_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\tob:"OutputPort-RESULT" -> "ocomp OUTPUT":"InputPort-OUTPUT_CIM_ob_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\tocm:"OutputPort-ia[noise] ControlSignal" -> "icomp CONTROL":"InputPort-PARAMETER_CIM_ia_noise" [label="" arrowhead=normal color=purple penwidth=1]\n\tocm:"OutputPort-ia[intercept] ControlSignal" -> "icomp CONTROL":"InputPort-PARAMETER_CIM_ia_intercept" [label="" arrowhead=normal color=purple penwidth=1]\n\tocm:"OutputPort-oa[slope] ControlSignal" -> oa:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1]\n\toc [label=<
RESULT
OutputPorts
Mechanism:
oc
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\tctl_mech [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
ctl_mech
InputPorts
OUTCOME
> color=blue penwidth=3 rank=max shape=plaintext]\n\tob [label=<
RESULT
OutputPorts
Mechanism:
ob
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\tocm [label=<
ia[noise] ControlSignalia[intercept] ControlSignaloa[slope] ControlSignal
OutputPorts
Mechanism:
ocm
InputPorts
OUTCOMEOUTCOME-1
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph cluster_icomp {\n\t\tgraph [label=icomp overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\t"icomp INPUT" [label=<
INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
icomp Input_CIM
InputPorts
INPUT_CIM_ia_InputPort-0
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"icomp INPUT":"OutputPort-INPUT_CIM_ia_InputPort-0" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"icomp CONTROL" [label=<
PARAMETER_CIM_ia_interceptPARAMETER_CIM_ia_noisePARAMETER_CIM_ia_slope
OutputPorts
Mechanism:
icomp Parameter_CIM
InputPorts
PARAMETER_CIM_ia_interceptPARAMETER_CIM_ia_noisePARAMETER_CIM_ia_slope
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t"icomp CONTROL":"OutputPort-PARAMETER_CIM_ia_intercept" -> ia:"ParameterPort-intercept" [label="" arrowhead=box color=purple penwidth=1]\n\t\t"icomp CONTROL":"OutputPort-PARAMETER_CIM_ia_noise" -> ia:"ParameterPort-noise" [label="" arrowhead=box color=purple penwidth=1]\n\t\t"icomp CONTROL":"OutputPort-PARAMETER_CIM_ia_slope" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=blue penwidth=1]\n\t\t"icomp OUTPUT" [label=<
OUTPUT_CIM_ia_RESULT
OutputPorts
Mechanism:
icomp Output_CIM
InputPorts
OUTPUT_CIM_ia_RESULT
> color=red penwidth=1 rank=same shape=plaintext]\n\t\tia:"OutputPort-RESULT" -> "icomp OUTPUT":"InputPort-OUTPUT_CIM_ia_RESULT" [label="" arrowhead=normal color=black penwidth=1]\n\t\tia [label=<
RESULT
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
noise
offset
rate
slope
InputPorts
InputPort-0
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\tlabel=icomp\n\t}\n}' ] @@ -666,3 +668,160 @@ def test_of_show_nested_show_cim_and_show_node_structure_with_singleton_in_outer ocomp.add_controller(ocm) gv = ocomp.show_graph(output_fmt='source', **show_graph_kwargs) assert gv.strip() == expected_output + + + # each item corresponds to the same item in _nested_show_graph_kwargs above + _nested_comp_to_ocm_or_obj_mech = [ + # monitor_for_control: + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"INNER COMP" [color=brown penwidth=3 rank=same shape=rectangle]\n\t"OptimizationControlMechanism-0" -> "INNER COMP" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"OUTER COMP INPUT_CIM" -> "OptimizationControlMechanism-0" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}', + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"INNER COMP" [color=brown penwidth=3 rank=same shape=rectangle]\n\t"OptimizationControlMechanism-0" -> "INNER COMP" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"OUTER COMP INPUT_CIM" -> "OptimizationControlMechanism-0" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph "cluster_INNER COMP" {\n\t\tgraph [label="INNER COMP" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [color=green penwidth=3 rank=source shape=oval]\n\t\tib [color=pink penwidth=3 rank=max shape=oval]\n\t\tia -> ib [label="" arrowhead=normal color=black penwidth=1]\n\t\tic [color=pink penwidth=3 rank=max shape=oval]\n\t\tib -> ic [label="" arrowhead=normal color=black penwidth=1]\n\t\tic -> id [label="" arrowhead=normal color=black penwidth=1]\n\t\tid [color=red penwidth=3 rank=max shape=oval]\n\t\tcolor=brown\n\t\tlabel="INNER COMP"\n\t}\n}', + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"OUTER COMP INPUT_CIM" -> ia [label="" arrowhead=normal color=black penwidth=1]\n\t"OptimizationControlMechanism-0" -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tib -> "OptimizationControlMechanism-0" [label="" arrowhead=normal color=purple penwidth=1]\n\tic -> "OptimizationControlMechanism-0" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM" -> "OptimizationControlMechanism-0" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph "cluster_INNER COMP" {\n\t\tgraph [label="INNER COMP" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [color=green penwidth=3 rank=source shape=oval]\n\t\tib [color=pink penwidth=3 rank=max shape=oval]\n\t\tia -> ib [label="" arrowhead=normal color=black penwidth=1]\n\t\tic [color=pink penwidth=3 rank=max shape=oval]\n\t\tib -> ic [label="" arrowhead=normal color=black penwidth=1]\n\t\tic -> id [label="" arrowhead=normal color=black penwidth=1]\n\t\tid [color=red penwidth=3 rank=max shape=oval]\n\t\tcolor=brown\n\t\tlabel="INNER COMP"\n\t}\n}', + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"INNER COMP" [color=brown penwidth=3 rank=same shape=rectangle]\n\t"OUTER COMP INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"OUTER COMP INPUT_CIM" -> "INNER COMP" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OUTER COMP OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0" -> "INNER COMP" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"INNER COMP OUTPUT_CIM" -> "OptimizationControlMechanism-0" [label="" color=purple penwidth=1]\n\t"INNER COMP OUTPUT_CIM" -> "OptimizationControlMechanism-0" [label="" color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM" -> "OptimizationControlMechanism-0" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}', + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"INNER COMP" [color=brown penwidth=3 rank=same shape=rectangle]\n\t"OUTER COMP INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"OUTER COMP INPUT_CIM" -> "INNER COMP" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OUTER COMP OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0" -> "INNER COMP" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\t"INNER COMP OUTPUT_CIM" -> "OptimizationControlMechanism-0" [label="" color=purple penwidth=1]\n\t"INNER COMP OUTPUT_CIM" -> "OptimizationControlMechanism-0" [label="" color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM" -> "OptimizationControlMechanism-0" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph "cluster_INNER COMP" {\n\t\tgraph [label="INNER COMP" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [color=green penwidth=3 rank=source shape=oval]\n\t\tib [color=pink penwidth=3 rank=max shape=oval]\n\t\tia -> ib [label="" arrowhead=normal color=black penwidth=1]\n\t\tic [color=pink penwidth=3 rank=max shape=oval]\n\t\tib -> ic [label="" arrowhead=normal color=black penwidth=1]\n\t\tic -> id [label="" arrowhead=normal color=black penwidth=1]\n\t\t"INNER COMP INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t"INNER COMP INPUT_CIM" -> ia [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"INNER COMP PARAMETER_CIM" [color=purple penwidth=1 rank=same shape=rectangle]\n\t\t"INNER COMP PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"INNER COMP OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\tib -> "INNER COMP OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tic -> "INNER COMP OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tid -> "INNER COMP OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tid [color=red penwidth=3 rank=max shape=oval]\n\t\tcolor=brown\n\t\tlabel="INNER COMP"\n\t}\n}', + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"OUTER COMP INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"OUTER COMP INPUT_CIM" -> "INNER COMP INPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OUTER COMP OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t"INNER COMP OUTPUT_CIM" -> "OUTER COMP OUTPUT_CIM" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP OUTPUT_CIM" -> "OUTER COMP OUTPUT_CIM" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP OUTPUT_CIM" -> "OUTER COMP OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0" -> "INNER COMP PARAMETER_CIM" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\t"INNER COMP OUTPUT_CIM" -> "OptimizationControlMechanism-0" [label="" color=purple penwidth=1]\n\t"INNER COMP OUTPUT_CIM" -> "OptimizationControlMechanism-0" [label="" color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM" -> "OptimizationControlMechanism-0" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph "cluster_INNER COMP" {\n\t\tgraph [label="INNER COMP" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [color=green penwidth=3 rank=source shape=oval]\n\t\tib [color=pink penwidth=3 rank=max shape=oval]\n\t\tia -> ib [label="" arrowhead=normal color=black penwidth=1]\n\t\tic [color=pink penwidth=3 rank=max shape=oval]\n\t\tib -> ic [label="" arrowhead=normal color=black penwidth=1]\n\t\tic -> id [label="" arrowhead=normal color=black penwidth=1]\n\t\t"INNER COMP INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t"INNER COMP INPUT_CIM" -> ia [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"INNER COMP PARAMETER_CIM" [color=purple penwidth=1 rank=same shape=rectangle]\n\t\t"INNER COMP PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"INNER COMP OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\tib -> "INNER COMP OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tic -> "INNER COMP OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tid -> "INNER COMP OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tid [color=red penwidth=3 rank=max shape=oval]\n\t\tcolor=brown\n\t\tlabel="INNER COMP"\n\t}\n}', + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"INNER COMP" [color=brown penwidth=3 rank=same shape=rectangle]\n\t"OptimizationControlMechanism-0":"OutputPort-ia[slope] ControlSignal" -> "INNER COMP" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0" -> "OptimizationControlMechanism-0":"InputPort-SHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
OptimizationControlMechanism-0
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}', + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"INNER COMP" [color=brown penwidth=3 rank=same shape=rectangle]\n\t"OptimizationControlMechanism-0":"OutputPort-ia[slope] ControlSignal" -> "INNER COMP" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0" -> "OptimizationControlMechanism-0":"InputPort-SHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
OptimizationControlMechanism-0
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph "cluster_INNER COMP" {\n\t\tgraph [label="INNER COMP" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [label=<
OutputPort-0
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\tib [label=<
OutputPort-0
OutputPorts
Mechanism:
ib
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=pink penwidth=3 rank=max shape=plaintext]\n\t\tia:"OutputPort-OutputPort-0" -> ib:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tic [label=<
OutputPort-0
OutputPorts
Mechanism:
ic
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=pink penwidth=3 rank=max shape=plaintext]\n\t\tib:"OutputPort-OutputPort-0" -> ic:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tic:"OutputPort-OutputPort-0" -> id:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tid [label=<
OutputPort-0
OutputPorts
Mechanism:
id
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\t\tcolor=brown\n\t\tlabel="INNER COMP"\n\t}\n}', + # # THE FOLLOWING IS INCORRECT (SEE COMMENTS IN TEST) + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"OptimizationControlMechanism-0":"OutputPort-ia[slope] ControlSignal" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\tib:"OutputPort-OutputPort-0" -> "OptimizationControlMechanism-0":"InputPort-OUTCOME" [label="" arrowhead=normal color=purple penwidth=1]\n\tic:"OutputPort-OutputPort-0" -> "OptimizationControlMechanism-0":"InputPort-OUTCOME" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0" -> "OptimizationControlMechanism-0":"InputPort-SHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
OptimizationControlMechanism-0
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph "cluster_INNER COMP" {\n\t\tgraph [label="INNER COMP" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [label=<
OutputPort-0
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\tib [label=<
OutputPort-0
OutputPorts
Mechanism:
ib
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=pink penwidth=3 rank=max shape=plaintext]\n\t\tia:"OutputPort-OutputPort-0" -> ib:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tic [label=<
OutputPort-0
OutputPorts
Mechanism:
ic
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=pink penwidth=3 rank=max shape=plaintext]\n\t\tib:"OutputPort-OutputPort-0" -> ic:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tic:"OutputPort-OutputPort-0" -> id:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tid [label=<
OutputPort-0
OutputPorts
Mechanism:
id
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\t\tcolor=brown\n\t\tlabel="INNER COMP"\n\t}\n}', + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"INNER COMP" [color=brown penwidth=3 rank=same shape=rectangle]\n\t"OUTER COMP INPUT_CIM" [label=<
INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
OUTER COMP Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0" -> "INNER COMP" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OUTER COMP OUTPUT_CIM" [label=<
Mechanism:
OUTER COMP Output_CIM
InputPorts
OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ib_OutputPort-0OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ic_OutputPort-0OUTPUT_CIM_INNER COMP_OUTPUT_CIM_id_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ib_OutputPort-0" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ic_OutputPort-0" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_id_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0":"OutputPort-ia[slope] ControlSignal" -> "INNER COMP" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"INNER COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_ic_OutputPort-0" -> "OptimizationControlMechanism-0":"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\t"INNER COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_ib_OutputPort-0" -> "OptimizationControlMechanism-0":"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0" -> "OptimizationControlMechanism-0":"InputPort-SHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
OptimizationControlMechanism-0
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}', + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"INNER COMP" [color=brown penwidth=3 rank=same shape=rectangle]\n\t"OUTER COMP INPUT_CIM" [label=<
INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
OUTER COMP Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0" -> "INNER COMP" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OUTER COMP OUTPUT_CIM" [label=<
Mechanism:
OUTER COMP Output_CIM
InputPorts
OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ib_OutputPort-0OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ic_OutputPort-0OUTPUT_CIM_INNER COMP_OUTPUT_CIM_id_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ib_OutputPort-0" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ic_OutputPort-0" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_id_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0":"OutputPort-ia[slope] ControlSignal" -> "INNER COMP" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\t"INNER COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_ic_OutputPort-0" -> "OptimizationControlMechanism-0":"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\t"INNER COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_ib_OutputPort-0" -> "OptimizationControlMechanism-0":"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0" -> "OptimizationControlMechanism-0":"InputPort-SHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
OptimizationControlMechanism-0
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph "cluster_INNER COMP" {\n\t\tgraph [label="INNER COMP" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [label=<
OutputPort-0
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\tib [label=<
OutputPort-0
OutputPorts
Mechanism:
ib
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=pink penwidth=3 rank=max shape=plaintext]\n\t\tia:"OutputPort-OutputPort-0" -> ib:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tic [label=<
OutputPort-0
OutputPorts
Mechanism:
ic
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=pink penwidth=3 rank=max shape=plaintext]\n\t\tib:"OutputPort-OutputPort-0" -> ic:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tic:"OutputPort-OutputPort-0" -> id:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"INNER COMP INPUT_CIM" [label=<
INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
INNER COMP Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"INNER COMP INPUT_CIM":"OutputPort-INPUT_CIM_ia_InputPort-0" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"INNER COMP PARAMETER_CIM" [label=<
PARAMETER_CIM_ia_slope
OutputPorts
Mechanism:
INNER COMP Parameter_CIM
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t"INNER COMP PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_slope" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"INNER COMP OUTPUT_CIM" [label=<
Mechanism:
INNER COMP Output_CIM
InputPorts
OUTPUT_CIM_ib_OutputPort-0OUTPUT_CIM_ic_OutputPort-0OUTPUT_CIM_id_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t\tib:"OutputPort-OutputPort-0" -> "INNER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_ib_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tic:"OutputPort-OutputPort-0" -> "INNER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_ic_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tid:"OutputPort-OutputPort-0" -> "INNER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_id_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tid [label=<
OutputPort-0
OutputPorts
Mechanism:
id
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\t\tcolor=brown\n\t\tlabel="INNER COMP"\n\t}\n}', + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"OUTER COMP INPUT_CIM" [label=<
INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
OUTER COMP Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0" -> "INNER COMP INPUT_CIM":"InputPort-INPUT_CIM_ia_InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OUTER COMP OUTPUT_CIM" [label=<
Mechanism:
OUTER COMP Output_CIM
InputPorts
OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ib_OutputPort-0OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ic_OutputPort-0OUTPUT_CIM_INNER COMP_OUTPUT_CIM_id_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t"INNER COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_ib_OutputPort-0" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ib_OutputPort-0" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_ic_OutputPort-0" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ic_OutputPort-0" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_id_OutputPort-0" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_id_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0":"OutputPort-ia[slope] ControlSignal" -> "INNER COMP PARAMETER_CIM":"InputPort-PARAMETER_CIM_ia_slope" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\t"INNER COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_ic_OutputPort-0" -> "OptimizationControlMechanism-0":"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\t"INNER COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_ib_OutputPort-0" -> "OptimizationControlMechanism-0":"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0" -> "OptimizationControlMechanism-0":"InputPort-SHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
OptimizationControlMechanism-0
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph "cluster_INNER COMP" {\n\t\tgraph [label="INNER COMP" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [label=<
OutputPort-0
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\tib [label=<
OutputPort-0
OutputPorts
Mechanism:
ib
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=pink penwidth=3 rank=max shape=plaintext]\n\t\tia:"OutputPort-OutputPort-0" -> ib:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tic [label=<
OutputPort-0
OutputPorts
Mechanism:
ic
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=pink penwidth=3 rank=max shape=plaintext]\n\t\tib:"OutputPort-OutputPort-0" -> ic:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tic:"OutputPort-OutputPort-0" -> id:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"INNER COMP INPUT_CIM" [label=<
INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
INNER COMP Input_CIM
InputPorts
INPUT_CIM_ia_InputPort-0
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"INNER COMP INPUT_CIM":"OutputPort-INPUT_CIM_ia_InputPort-0" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"INNER COMP PARAMETER_CIM" [label=<
PARAMETER_CIM_ia_slope
OutputPorts
Mechanism:
INNER COMP Parameter_CIM
InputPorts
PARAMETER_CIM_ia_slope
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t"INNER COMP PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_slope" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"INNER COMP OUTPUT_CIM" [label=<
OUTPUT_CIM_ib_OutputPort-0OUTPUT_CIM_ic_OutputPort-0OUTPUT_CIM_id_OutputPort-0
OutputPorts
Mechanism:
INNER COMP Output_CIM
InputPorts
OUTPUT_CIM_ib_OutputPort-0OUTPUT_CIM_ic_OutputPort-0OUTPUT_CIM_id_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t\tib:"OutputPort-OutputPort-0" -> "INNER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_ib_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tic:"OutputPort-OutputPort-0" -> "INNER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_ic_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tid:"OutputPort-OutputPort-0" -> "INNER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_id_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tid [label=<
OutputPort-0
OutputPorts
Mechanism:
id
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\t\tcolor=brown\n\t\tlabel="INNER COMP"\n\t}\n}', + # obj_mech + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"INNER COMP" [color=brown penwidth=3 rank=same shape=rectangle]\n\t"OptimizationControlMechanism-0" -> "INNER COMP" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism" [color=purple penwidth=1 rank=min shape=oval]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism" -> "OptimizationControlMechanism-0" [label="" color=purple penwidth=1]\n\tic -> "OptimizationControlMechanism-0_ObjectiveMechanism" [label="" color=purple penwidth=1]\n\tib -> "OptimizationControlMechanism-0_ObjectiveMechanism" [label="" color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM" -> "OptimizationControlMechanism-0" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}', + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"INNER COMP" [color=brown penwidth=3 rank=same shape=rectangle]\n\t"OptimizationControlMechanism-0" -> "INNER COMP" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism" [color=purple penwidth=1 rank=min shape=oval]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism" -> "OptimizationControlMechanism-0" [label="" color=purple penwidth=1]\n\tic -> "OptimizationControlMechanism-0_ObjectiveMechanism" [label="" color=purple penwidth=1]\n\tib -> "OptimizationControlMechanism-0_ObjectiveMechanism" [label="" color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM" -> "OptimizationControlMechanism-0" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph "cluster_INNER COMP" {\n\t\tgraph [label="INNER COMP" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [color=green penwidth=3 rank=source shape=oval]\n\t\tib [color=pink penwidth=3 rank=max shape=oval]\n\t\tia -> ib [label="" arrowhead=normal color=black penwidth=1]\n\t\tic [color=pink penwidth=3 rank=max shape=oval]\n\t\tib -> ic [label="" arrowhead=normal color=black penwidth=1]\n\t\tic -> id [label="" arrowhead=normal color=black penwidth=1]\n\t\tid [color=red penwidth=3 rank=max shape=oval]\n\t\tcolor=brown\n\t\tlabel="INNER COMP"\n\t}\n}', + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"OUTER COMP INPUT_CIM" -> ia [label="" arrowhead=normal color=black penwidth=1]\n\t"OptimizationControlMechanism-0" -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism" [color=purple penwidth=1 rank=min shape=oval]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism" -> "OptimizationControlMechanism-0" [label="" color=purple penwidth=1]\n\tic -> "OptimizationControlMechanism-0_ObjectiveMechanism" [label="" color=purple penwidth=1]\n\tib -> "OptimizationControlMechanism-0_ObjectiveMechanism" [label="" color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM" -> "OptimizationControlMechanism-0" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph "cluster_INNER COMP" {\n\t\tgraph [label="INNER COMP" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [color=green penwidth=3 rank=source shape=oval]\n\t\tib [color=pink penwidth=3 rank=max shape=oval]\n\t\tia -> ib [label="" arrowhead=normal color=black penwidth=1]\n\t\tic [color=pink penwidth=3 rank=max shape=oval]\n\t\tib -> ic [label="" arrowhead=normal color=black penwidth=1]\n\t\tic -> id [label="" arrowhead=normal color=black penwidth=1]\n\t\tid [color=red penwidth=3 rank=max shape=oval]\n\t\tcolor=brown\n\t\tlabel="INNER COMP"\n\t}\n}', + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"INNER COMP" [color=brown penwidth=3 rank=same shape=rectangle]\n\t"OUTER COMP INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"OUTER COMP INPUT_CIM" -> "INNER COMP" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OUTER COMP OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0" -> "INNER COMP" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism" [color=purple penwidth=1 rank=min shape=oval]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism" -> "OptimizationControlMechanism-0" [label="" color=purple penwidth=1]\n\t"INNER COMP OUTPUT_CIM" -> "OptimizationControlMechanism-0_ObjectiveMechanism" [label="" color=purple penwidth=1]\n\t"INNER COMP OUTPUT_CIM" -> "OptimizationControlMechanism-0_ObjectiveMechanism" [label="" color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM" -> "OptimizationControlMechanism-0" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [color=purple penwidth=1 rank=min shape=doubleoctagon]\n}', + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"INNER COMP" [color=brown penwidth=3 rank=same shape=rectangle]\n\t"OUTER COMP INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"OUTER COMP INPUT_CIM" -> "INNER COMP" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OUTER COMP OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0" -> "INNER COMP" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism" [color=purple penwidth=1 rank=min shape=oval]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism" -> "OptimizationControlMechanism-0" [label="" color=purple penwidth=1]\n\t"INNER COMP OUTPUT_CIM" -> "OptimizationControlMechanism-0_ObjectiveMechanism" [label="" color=purple penwidth=1]\n\t"INNER COMP OUTPUT_CIM" -> "OptimizationControlMechanism-0_ObjectiveMechanism" [label="" color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM" -> "OptimizationControlMechanism-0" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph "cluster_INNER COMP" {\n\t\tgraph [label="INNER COMP" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [color=green penwidth=3 rank=source shape=oval]\n\t\tib [color=pink penwidth=3 rank=max shape=oval]\n\t\tia -> ib [label="" arrowhead=normal color=black penwidth=1]\n\t\tic [color=pink penwidth=3 rank=max shape=oval]\n\t\tib -> ic [label="" arrowhead=normal color=black penwidth=1]\n\t\tic -> id [label="" arrowhead=normal color=black penwidth=1]\n\t\t"INNER COMP INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t"INNER COMP INPUT_CIM" -> ia [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"INNER COMP PARAMETER_CIM" [color=purple penwidth=1 rank=same shape=rectangle]\n\t\t"INNER COMP PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"INNER COMP OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\tib -> "INNER COMP OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tic -> "INNER COMP OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tid -> "INNER COMP OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tid [color=red penwidth=3 rank=max shape=oval]\n\t\tcolor=brown\n\t\tlabel="INNER COMP"\n\t}\n}', + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"OUTER COMP INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t"OUTER COMP INPUT_CIM" -> "INNER COMP INPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OUTER COMP OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t"INNER COMP OUTPUT_CIM" -> "OUTER COMP OUTPUT_CIM" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP OUTPUT_CIM" -> "OUTER COMP OUTPUT_CIM" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP OUTPUT_CIM" -> "OUTER COMP OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0" -> "INNER COMP PARAMETER_CIM" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism" [color=purple penwidth=1 rank=min shape=oval]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism" -> "OptimizationControlMechanism-0" [label="" color=purple penwidth=1]\n\t"INNER COMP OUTPUT_CIM" -> "OptimizationControlMechanism-0_ObjectiveMechanism" [label="" color=purple penwidth=1]\n\t"INNER COMP OUTPUT_CIM" -> "OptimizationControlMechanism-0_ObjectiveMechanism" [label="" color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM" -> "OptimizationControlMechanism-0" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [color=purple penwidth=1 rank=min shape=doubleoctagon]\n\tsubgraph "cluster_INNER COMP" {\n\t\tgraph [label="INNER COMP" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [color=green penwidth=3 rank=source shape=oval]\n\t\tib [color=pink penwidth=3 rank=max shape=oval]\n\t\tia -> ib [label="" arrowhead=normal color=black penwidth=1]\n\t\tic [color=pink penwidth=3 rank=max shape=oval]\n\t\tib -> ic [label="" arrowhead=normal color=black penwidth=1]\n\t\tic -> id [label="" arrowhead=normal color=black penwidth=1]\n\t\t"INNER COMP INPUT_CIM" [color=green penwidth=1 rank=same shape=rectangle]\n\t\t"INNER COMP INPUT_CIM" -> ia [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"INNER COMP PARAMETER_CIM" [color=purple penwidth=1 rank=same shape=rectangle]\n\t\t"INNER COMP PARAMETER_CIM" -> ia [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"INNER COMP OUTPUT_CIM" [color=red penwidth=1 rank=same shape=rectangle]\n\t\tib -> "INNER COMP OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tic -> "INNER COMP OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tid -> "INNER COMP OUTPUT_CIM" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tid [color=red penwidth=3 rank=max shape=oval]\n\t\tcolor=brown\n\t\tlabel="INNER COMP"\n\t}\n}', + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"INNER COMP" [color=brown penwidth=3 rank=same shape=rectangle]\n\t"OptimizationControlMechanism-0":"OutputPort-ia[slope] ControlSignal" -> "INNER COMP" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism" [label=<
OUTCOME
OutputPorts
Mechanism:
OptimizationControlMechanism-0_ObjectiveMechanism
ParameterPorts
offset
scale
InputPorts
Value of ic [OutputPort-0]Value of ib [OutputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism":"OutputPort-OUTCOME" -> "OptimizationControlMechanism-0":"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\tic:"OutputPort-OutputPort-0" -> "OptimizationControlMechanism-0_ObjectiveMechanism":"InputPort-Value of ic [OutputPort-0]" [label="" color=purple penwidth=1]\n\tib:"OutputPort-OutputPort-0" -> "OptimizationControlMechanism-0_ObjectiveMechanism":"InputPort-Value of ib [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0" -> "OptimizationControlMechanism-0":"InputPort-SHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
OptimizationControlMechanism-0
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}', + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"INNER COMP" [color=brown penwidth=3 rank=same shape=rectangle]\n\t"OptimizationControlMechanism-0":"OutputPort-ia[slope] ControlSignal" -> "INNER COMP" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism" [label=<
OUTCOME
OutputPorts
Mechanism:
OptimizationControlMechanism-0_ObjectiveMechanism
ParameterPorts
offset
scale
InputPorts
Value of ic [OutputPort-0]Value of ib [OutputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism":"OutputPort-OUTCOME" -> "OptimizationControlMechanism-0":"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\tic:"OutputPort-OutputPort-0" -> "OptimizationControlMechanism-0_ObjectiveMechanism":"InputPort-Value of ic [OutputPort-0]" [label="" color=purple penwidth=1]\n\tib:"OutputPort-OutputPort-0" -> "OptimizationControlMechanism-0_ObjectiveMechanism":"InputPort-Value of ib [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0" -> "OptimizationControlMechanism-0":"InputPort-SHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
OptimizationControlMechanism-0
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph "cluster_INNER COMP" {\n\t\tgraph [label="INNER COMP" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [label=<
OutputPort-0
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\tib [label=<
OutputPort-0
OutputPorts
Mechanism:
ib
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=pink penwidth=3 rank=max shape=plaintext]\n\t\tia:"OutputPort-OutputPort-0" -> ib:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tic [label=<
OutputPort-0
OutputPorts
Mechanism:
ic
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=pink penwidth=3 rank=max shape=plaintext]\n\t\tib:"OutputPort-OutputPort-0" -> ic:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tic:"OutputPort-OutputPort-0" -> id:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tid [label=<
OutputPort-0
OutputPorts
Mechanism:
id
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\t\tcolor=brown\n\t\tlabel="INNER COMP"\n\t}\n}', + # THE FOLLOWING IS INCORRECT (SEE COMMENTS IN TEST) + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t"OptimizationControlMechanism-0":"OutputPort-ia[slope] ControlSignal" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism" [label=<
OUTCOME
OutputPorts
Mechanism:
OptimizationControlMechanism-0_ObjectiveMechanism
ParameterPorts
offset
scale
InputPorts
Value of ic [OutputPort-0]Value of ib [OutputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism":"OutputPort-OUTCOME" -> "OptimizationControlMechanism-0":"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\tic:"OutputPort-OutputPort-0" -> "OptimizationControlMechanism-0_ObjectiveMechanism":"InputPort-Value of ic [OutputPort-0]" [label="" color=purple penwidth=1]\n\tib:"OutputPort-OutputPort-0" -> "OptimizationControlMechanism-0_ObjectiveMechanism":"InputPort-Value of ib [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0" -> "OptimizationControlMechanism-0":"InputPort-SHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
OptimizationControlMechanism-0
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph "cluster_INNER COMP" {\n\t\tgraph [label="INNER COMP" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [label=<
OutputPort-0
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\tib [label=<
OutputPort-0
OutputPorts
Mechanism:
ib
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=pink penwidth=3 rank=max shape=plaintext]\n\t\tia:"OutputPort-OutputPort-0" -> ib:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tic [label=<
OutputPort-0
OutputPorts
Mechanism:
ic
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=pink penwidth=3 rank=max shape=plaintext]\n\t\tib:"OutputPort-OutputPort-0" -> ic:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tic:"OutputPort-OutputPort-0" -> id:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tid [label=<
OutputPort-0
OutputPorts
Mechanism:
id
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\t\tcolor=brown\n\t\tlabel="INNER COMP"\n\t}\n}', + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"INNER COMP" [color=brown penwidth=3 rank=same shape=rectangle]\n\t"OUTER COMP INPUT_CIM" [label=<
INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
OUTER COMP Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0" -> "INNER COMP" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OUTER COMP OUTPUT_CIM" [label=<
Mechanism:
OUTER COMP Output_CIM
InputPorts
OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ib_OutputPort-0OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ic_OutputPort-0OUTPUT_CIM_INNER COMP_OUTPUT_CIM_id_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ib_OutputPort-0" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ic_OutputPort-0" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_id_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0":"OutputPort-ia[slope] ControlSignal" -> "INNER COMP" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism" [label=<
OUTCOME
OutputPorts
Mechanism:
OptimizationControlMechanism-0_ObjectiveMechanism
ParameterPorts
offset
scale
InputPorts
Value of ic [OutputPort-0]Value of ib [OutputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism":"OutputPort-OUTCOME" -> "OptimizationControlMechanism-0":"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\t"INNER COMP OUTPUT_CIM" -> "OptimizationControlMechanism-0_ObjectiveMechanism":"InputPort-Value of ic [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"INNER COMP OUTPUT_CIM" -> "OptimizationControlMechanism-0_ObjectiveMechanism":"InputPort-Value of ib [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0" -> "OptimizationControlMechanism-0":"InputPort-SHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
OptimizationControlMechanism-0
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n}', + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"INNER COMP" [color=brown penwidth=3 rank=same shape=rectangle]\n\t"OUTER COMP INPUT_CIM" [label=<
INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
OUTER COMP Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0" -> "INNER COMP" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OUTER COMP OUTPUT_CIM" [label=<
Mechanism:
OUTER COMP Output_CIM
InputPorts
OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ib_OutputPort-0OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ic_OutputPort-0OUTPUT_CIM_INNER COMP_OUTPUT_CIM_id_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ib_OutputPort-0" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ic_OutputPort-0" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_id_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0":"OutputPort-ia[slope] ControlSignal" -> "INNER COMP" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism" [label=<
OUTCOME
OutputPorts
Mechanism:
OptimizationControlMechanism-0_ObjectiveMechanism
ParameterPorts
offset
scale
InputPorts
Value of ic [OutputPort-0]Value of ib [OutputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism":"OutputPort-OUTCOME" -> "OptimizationControlMechanism-0":"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\t"INNER COMP OUTPUT_CIM" -> "OptimizationControlMechanism-0_ObjectiveMechanism":"InputPort-Value of ic [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"INNER COMP OUTPUT_CIM" -> "OptimizationControlMechanism-0_ObjectiveMechanism":"InputPort-Value of ib [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0" -> "OptimizationControlMechanism-0":"InputPort-SHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
OptimizationControlMechanism-0
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph "cluster_INNER COMP" {\n\t\tgraph [label="INNER COMP" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [label=<
OutputPort-0
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\tib [label=<
OutputPort-0
OutputPorts
Mechanism:
ib
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=pink penwidth=3 rank=max shape=plaintext]\n\t\tia:"OutputPort-OutputPort-0" -> ib:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tic [label=<
OutputPort-0
OutputPorts
Mechanism:
ic
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=pink penwidth=3 rank=max shape=plaintext]\n\t\tib:"OutputPort-OutputPort-0" -> ic:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tic:"OutputPort-OutputPort-0" -> id:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"INNER COMP INPUT_CIM" [label=<
INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
INNER COMP Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"INNER COMP INPUT_CIM":"OutputPort-INPUT_CIM_ia_InputPort-0" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"INNER COMP PARAMETER_CIM" [label=<
PARAMETER_CIM_ia_slope
OutputPorts
Mechanism:
INNER COMP Parameter_CIM
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t"INNER COMP PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_slope" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"INNER COMP OUTPUT_CIM" [label=<
Mechanism:
INNER COMP Output_CIM
InputPorts
OUTPUT_CIM_ib_OutputPort-0OUTPUT_CIM_ic_OutputPort-0OUTPUT_CIM_id_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t\tib:"OutputPort-OutputPort-0" -> "INNER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_ib_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tic:"OutputPort-OutputPort-0" -> "INNER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_ic_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tid:"OutputPort-OutputPort-0" -> "INNER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_id_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tid [label=<
OutputPort-0
OutputPorts
Mechanism:
id
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\t\tcolor=brown\n\t\tlabel="INNER COMP"\n\t}\n}', + 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"OUTER COMP INPUT_CIM" [label=<
INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
OUTER COMP Input_CIM
> color=green penwidth=1 rank=same shape=plaintext]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0" -> "INNER COMP INPUT_CIM":"InputPort-INPUT_CIM_ia_InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OUTER COMP OUTPUT_CIM" [label=<
Mechanism:
OUTER COMP Output_CIM
InputPorts
OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ib_OutputPort-0OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ic_OutputPort-0OUTPUT_CIM_INNER COMP_OUTPUT_CIM_id_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t"INNER COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_ib_OutputPort-0" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ib_OutputPort-0" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_ic_OutputPort-0" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_ic_OutputPort-0" [label="" arrowhead=normal color=pink penwidth=1 style=solid]\n\t"INNER COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_id_OutputPort-0" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_id_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0":"OutputPort-ia[slope] ControlSignal" -> "INNER COMP PARAMETER_CIM":"InputPort-PARAMETER_CIM_ia_slope" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism" [label=<
OUTCOME
OutputPorts
Mechanism:
OptimizationControlMechanism-0_ObjectiveMechanism
ParameterPorts
offset
scale
InputPorts
Value of ic [OutputPort-0]Value of ib [OutputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\t"OptimizationControlMechanism-0_ObjectiveMechanism":"OutputPort-OUTCOME" -> "OptimizationControlMechanism-0":"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\t"INNER COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_ic_OutputPort-0" -> "OptimizationControlMechanism-0_ObjectiveMechanism":"InputPort-Value of ic [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"INNER COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_ib_OutputPort-0" -> "OptimizationControlMechanism-0_ObjectiveMechanism":"InputPort-Value of ib [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_ia_InputPort-0" -> "OptimizationControlMechanism-0":"InputPort-SHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]" [label="" arrowhead=normal color=purple penwidth=1]\n\t"OptimizationControlMechanism-0" [label=<
ia[slope] ControlSignal
OutputPorts
Mechanism:
OptimizationControlMechanism-0
ParameterPorts
seed
InputPorts
OUTCOMESHADOWED INPUT OF ia[InputPort-0] FOR ia[InputPort-0]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph "cluster_INNER COMP" {\n\t\tgraph [label="INNER COMP" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tia [label=<
OutputPort-0
OutputPorts
Mechanism:
ia
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=green penwidth=3 rank=source shape=plaintext]\n\t\tib [label=<
OutputPort-0
OutputPorts
Mechanism:
ib
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=pink penwidth=3 rank=max shape=plaintext]\n\t\tia:"OutputPort-OutputPort-0" -> ib:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tic [label=<
OutputPort-0
OutputPorts
Mechanism:
ic
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=pink penwidth=3 rank=max shape=plaintext]\n\t\tib:"OutputPort-OutputPort-0" -> ic:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tic:"OutputPort-OutputPort-0" -> id:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"INNER COMP INPUT_CIM" [label=<
INPUT_CIM_ia_InputPort-0
OutputPorts
Mechanism:
INNER COMP Input_CIM
InputPorts
INPUT_CIM_ia_InputPort-0
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"INNER COMP INPUT_CIM":"OutputPort-INPUT_CIM_ia_InputPort-0" -> ia:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"INNER COMP PARAMETER_CIM" [label=<
PARAMETER_CIM_ia_slope
OutputPorts
Mechanism:
INNER COMP Parameter_CIM
InputPorts
PARAMETER_CIM_ia_slope
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t"INNER COMP PARAMETER_CIM":"OutputPort-PARAMETER_CIM_ia_slope" -> ia:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t"INNER COMP OUTPUT_CIM" [label=<
OUTPUT_CIM_ib_OutputPort-0OUTPUT_CIM_ic_OutputPort-0OUTPUT_CIM_id_OutputPort-0
OutputPorts
Mechanism:
INNER COMP Output_CIM
InputPorts
OUTPUT_CIM_ib_OutputPort-0OUTPUT_CIM_ic_OutputPort-0OUTPUT_CIM_id_OutputPort-0
> color=red penwidth=1 rank=same shape=plaintext]\n\t\tib:"OutputPort-OutputPort-0" -> "INNER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_ib_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tic:"OutputPort-OutputPort-0" -> "INNER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_ic_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tid:"OutputPort-OutputPort-0" -> "INNER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_id_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tid [label=<
OutputPort-0
OutputPorts
Mechanism:
id
ParameterPorts
intercept
slope
InputPorts
InputPort-0
> color=red penwidth=3 rank=max shape=plaintext]\n\t\tcolor=brown\n\t\tlabel="INNER COMP"\n\t}\n}', + ] + num_show_graph_combos = len(_nested_show_graph_kwargs) + obj_mech = ['monitor_for_control'] * num_show_graph_combos + ['obj_mech'] * num_show_graph_combos + show_graph_args = list(zip(_nested_show_graph_kwargs * 2, _nested_comp_to_ocm_or_obj_mech)) + test_args = [] + ids = [] + for i in range(len(_nested_comp_to_ocm_or_obj_mech)): + show_graph_arg, expected_output = show_graph_args[i] + obj_mech_arg = obj_mech[i] + test_args.append((show_graph_arg, expected_output, obj_mech_arg)) + ids.append(obj_mech_arg + '-' + str(show_graph_arg)) + @pytest.mark.parametrize( + 'show_graph_kwargs, expected_output, obj_mech', test_args, + # ids=[str(x) for x in _nested_show_graph_kwargs]*2 + ids=[str(x) for x in ids] + ) + def test_projections_from_nested_comp_to_ocm_or_obj_mech(self, show_graph_kwargs, expected_output, obj_mech): + ia = ProcessingMechanism(name='ia') + ib = ProcessingMechanism(name='ib') + ic = ProcessingMechanism(name='ic') + id = ProcessingMechanism(name='id') + icomp = Composition(pathways=[ia,ib,ic,id], name='INNER COMP') + ocomp = Composition(nodes=[icomp], name='OUTER COMP') + + # # FIX: THIS IS SKIPPED DUE TO BUG ( + # # ??SAME BUG AS IN MESSAGE FOR COMMIT eb61303808ad2a5ba46fdd18d0e583283397915c ??) + # if ('show_node_structure' in show_graph_kwargs + # and not 'show_cim' in show_graph_kwargs + # and ('show_nested' in show_graph_kwargs and show_graph_kwargs['show_nested']==NESTED) + # ): + # pytest.skip("??graphviz BUG") + + if obj_mech == 'monitor_for_control': + monitor_for_control = [ic,ib] + objective_mechanism = None + else: + monitor_for_control = None + objective_mechanism = [ic,ib] + + ocm = OptimizationControlMechanism( + state_features=ia.input_port, + monitor_for_control=monitor_for_control, + objective_mechanism=objective_mechanism, + function=GridSearch(), + allow_probes=True, + control_signals=ControlSignal(modulates=(SLOPE,ia), + allocation_samples=[10, 20, 30]) + ) + ocomp.add_controller(ocm) + gv = ocomp.show_graph(output_fmt='source', **show_graph_kwargs) + + try: + assert gv.strip() == expected_output + except AssertionError: + # ??SAME BUG AS IN MESSAGE FOR COMMIT eb61303808ad2a5ba46fdd18d0e583283397915c ??) + if ('show_node_structure' in show_graph_kwargs + and 'show_cim' not in show_graph_kwargs + and ('show_nested' in show_graph_kwargs + and show_graph_kwargs['show_nested'] == NESTED) + ): + # The test in this condition is for incorrect show_graph output due an as yet undetermined bug + # in which the Projection from the OCM receives a projection to its control_signal output_port + # from a the input_port of a nested monitored node (ic) rather than from its output_port to the + # OCM's outcome_input_port. + # If the test fails in this condition, it could mean that the bug has been corrected. + # The bug may be the same one as in eb61303808ad2a5ba46fdd18d0e583283397915c + raise(AssertionError,"FAILURE TO REPLICATE BUGGY SHOW_GRAPH OUTPUT -- SEE COMMENT IN TEST") + # elif ('show_node_structure' in show_graph_kwargs + # and ('show_cim' in show_graph_kwargs + # and show_graph_kwargs['show_cim'] is True) + # and ('show_nested' in show_graph_kwargs + # and show_graph_kwargs['show_nested'] == INSET) + # ): + # pass + else: + raise(AssertionError) + + # def test_show_graph_for_nested_composition_as_agent_rep(self): + # """Note: this is the same as test_control/test_nested_composition_as_agent_rep but with show_graph()""" + # I = ProcessingMechanism(name='I') + # icomp = Composition(nodes=I, name='INNER COMP') + # + # A = ProcessingMechanism(name='A') + # B = ProcessingMechanism(name='B') + # C = ProcessingMechanism(name='C') + # mcomp = Composition(pathways=[[A,B,C], icomp], + # name='MIDDLE COMP') + # ocomp = Composition(nodes=[mcomp], name='OUTER COMP') + # ocm = OptimizationControlMechanism(name='OCM', + # agent_rep=mcomp, # Nested Composition as agent_rep + # state_features=I.input_port, + # objective_mechanism=ObjectiveMechanism(monitor=[B]), + # allow_probes=True, + # function=GridSearch(), + # control_signals=ControlSignal(modulates=(SLOPE,I), + # allocation_samples=[10, 20, 30])) + # ocomp.add_controller(ocm) + # # FIX: THE FOLLOWING IS UNSTABLE; SOMETIMES RENDERS CORRECTLY, BUT SOMETIMES INCORRECTLY SHOWS EDGE + # # FROM ocm.output_CIM.input_port -> mcomp.parameter_CIM.output_port + # # ??SAME BUG AS IN MESSAGE FOR COMMIT eb61303808ad2a5ba46fdd18d0e583283397915c + # expected_gv_correct = 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"OUTER COMP INPUT_CIM" [label=<
INPUT_CIM_MIDDLE COMP_INPUT_CIM_A_InputPort-0
Identity()
=[0.]
INPUT_CIM_MIDDLE COMP_INPUT_CIM_INNER COMP_INPUT_CIM_I_InputPort-0
Identity()
=[0.]
OutputPorts
Mechanism:
OUTER COMP Input_CIM

Identity()
=None
> color=green penwidth=1 rank=same shape=plaintext]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_MIDDLE COMP_INPUT_CIM_A_InputPort-0" -> "MIDDLE COMP INPUT_CIM":"InputPort-INPUT_CIM_A_InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_MIDDLE COMP_INPUT_CIM_INNER COMP_INPUT_CIM_I_InputPort-0" -> "MIDDLE COMP INPUT_CIM":"InputPort-INPUT_CIM_INNER COMP_INPUT_CIM_I_InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OUTER COMP OUTPUT_CIM" [label=<
Mechanism:
OUTER COMP Output_CIM

Identity()
=None
InputPorts
OUTPUT_CIM_MIDDLE COMP_OUTPUT_CIM_B_OutputPort-0
LinearCombination(scale=None, offset=None, exponents=None, weights=None)
=[0.]
OUTPUT_CIM_MIDDLE COMP_OUTPUT_CIM_C_OutputPort-0
LinearCombination(scale=None, offset=None, exponents=None, weights=None)
=[0.]
OUTPUT_CIM_MIDDLE COMP_OUTPUT_CIM_INNER COMP_OUTPUT_CIM_I_OutputPort-0
LinearCombination(scale=None, offset=None, exponents=None, weights=None)
=[0.]
> color=red penwidth=1 rank=same shape=plaintext]\n\t"MIDDLE COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_B_OutputPort-0" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_MIDDLE COMP_OUTPUT_CIM_B_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"MIDDLE COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_C_OutputPort-0" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_MIDDLE COMP_OUTPUT_CIM_C_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"MIDDLE COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_I_OutputPort-0" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_MIDDLE COMP_OUTPUT_CIM_INNER COMP_OUTPUT_CIM_I_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tOCM:"OutputPort-I[slope] ControlSignal" -> "MIDDLE COMP PARAMETER_CIM":"InputPort-PARAMETER_CIM_I_slope" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\t"ObjectiveMechanism-0" [label=<
OUTCOME
Linear(intercept=None, slope=None)
=[0.]
OutputPorts
Mechanism:
ObjectiveMechanism-0

CONTROLLER_OBJECTIVE,INTERNAL
LinearCombination(scale=None, offset=None, exponents=None, weights=None)
=[[0.]]
ParameterPorts
offset
Linear(intercept=None, slope=None)
=[0.]
scale
Linear(intercept=None, slope=None)
=[1.]
InputPorts
Value of B [OutputPort-0]
LinearCombination(scale=None, offset=None, exponents=None, weights=None)
=[0.]
> color=purple penwidth=1 rank=min shape=plaintext]\n\t"ObjectiveMechanism-0":"OutputPort-OUTCOME" -> OCM:"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\t"MIDDLE COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_B_OutputPort-0" -> "ObjectiveMechanism-0":"InputPort-Value of B [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_MIDDLE COMP_INPUT_CIM_INNER COMP_INPUT_CIM_I_InputPort-0" -> OCM:"InputPort-Shadowed input of I" [label="" arrowhead=normal color=purple penwidth=1]\n\tOCM [label=<
I[slope] ControlSignal
TransferWithCosts(combine_costs_fct_add_param=None, intensity_cost_fct_mult_param=None, intensity_cost_fct_add_param=None, duration_cost_fct_mult_param=None, adjustment_cost_fct_mult_param=None, duration_cost_fct_add_param=None, adjustment_cost_fct_add_param=None, transfer_fct_add_param=None, transfer_fct_mult_param=None, combine_costs_fct_mult_param=None)
=[1.]
OutputPorts
Mechanism:
OCM

CONTROLLER
Always()
GridSearch(max_iterations=None, seed=-1)
=[[1.]]
ParameterPorts
seed
Linear(intercept=None, slope=None)
=[-1.]
InputPorts
OUTCOME
LinearCombination(scale=None, offset=None, exponents=None, weights=None)
=[0.]
Shadowed input of I
LinearCombination(scale=None, offset=None, exponents=None, weights=None)
=[0.]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph "cluster_MIDDLE COMP" {\n\t\tgraph [label="MIDDLE COMP" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tA [label=<
OutputPort-0
Linear(intercept=None, slope=None)
=[0.]
OutputPorts
Mechanism:
A

INPUT,ORIGIN
Linear(intercept=None, slope=None)
=[[0.]]
ParameterPorts
intercept
Linear(intercept=None, slope=None)
=[0.]
slope
Linear(intercept=None, slope=None)
=[1.]
InputPorts
InputPort-0
LinearCombination(scale=None, offset=None, exponents=None, weights=None)
=[0.]
> color=green penwidth=3 rank=source shape=plaintext]\n\t\tB [label=<
OutputPort-0
Linear(intercept=None, slope=None)
=[0.]
OutputPorts
Mechanism:
B

PROBE,INTERNAL
Linear(intercept=None, slope=None)
=[[0.]]
ParameterPorts
intercept
Linear(intercept=None, slope=None)
=[0.]
slope
Linear(intercept=None, slope=None)
=[1.]
InputPorts
InputPort-0
LinearCombination(scale=None, offset=None, exponents=None, weights=None)
=[0.]
> color=black penwidth=1 rank=same shape=plaintext]\n\t\tA:"OutputPort-OutputPort-0" -> B:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tB:"OutputPort-OutputPort-0" -> C:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"MIDDLE COMP INPUT_CIM" [label=<
INPUT_CIM_A_InputPort-0
Identity()
=[0.]
INPUT_CIM_INNER COMP_INPUT_CIM_I_InputPort-0
Identity()
=[0.]
OutputPorts
Mechanism:
MIDDLE COMP Input_CIM

Identity()
=None
InputPorts
INPUT_CIM_A_InputPort-0
LinearCombination(scale=None, offset=None, exponents=None, weights=None)
=[0.]
INPUT_CIM_INNER COMP_INPUT_CIM_I_InputPort-0
LinearCombination(scale=None, offset=None, exponents=None, weights=None)
=[0.]
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"MIDDLE COMP INPUT_CIM":"OutputPort-INPUT_CIM_A_InputPort-0" -> A:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"MIDDLE COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_I_InputPort-0" -> "INNER COMP INPUT_CIM":"InputPort-INPUT_CIM_I_InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"MIDDLE COMP PARAMETER_CIM" [label=<
PARAMETER_CIM_I_slope
TransferWithCosts(combine_costs_fct_add_param=None, intensity_cost_fct_mult_param=None, intensity_cost_fct_add_param=None, duration_cost_fct_mult_param=None, adjustment_cost_fct_mult_param=None, duration_cost_fct_add_param=None, adjustment_cost_fct_add_param=None, combine_costs_fct_mult_param=None)
=[1.]
OutputPorts
Mechanism:
MIDDLE COMP Parameter_CIM

Identity()
=[[0.]\n [1.]]
InputPorts
PARAMETER_CIM_I_slope
LinearCombination(scale=None, offset=None, exponents=None, weights=None)
=[1.]
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t"MIDDLE COMP PARAMETER_CIM":"OutputPort-PARAMETER_CIM_I_slope" -> "INNER COMP PARAMETER_CIM":"InputPort-PARAMETER_CIM_I_slope" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\t\t"MIDDLE COMP OUTPUT_CIM" [label=<
OUTPUT_CIM_B_OutputPort-0
Identity()
=[0.]
OUTPUT_CIM_C_OutputPort-0
Identity()
=[0.]
OUTPUT_CIM_INNER COMP_OUTPUT_CIM_I_OutputPort-0
Identity()
=[0.]
OutputPorts
Mechanism:
MIDDLE COMP Output_CIM

Identity()
=None
InputPorts
OUTPUT_CIM_B_OutputPort-0
LinearCombination(scale=None, offset=None, exponents=None, weights=None)
=[0.]
OUTPUT_CIM_C_OutputPort-0
LinearCombination(scale=None, offset=None, exponents=None, weights=None)
=[0.]
OUTPUT_CIM_INNER COMP_OUTPUT_CIM_I_OutputPort-0
LinearCombination(scale=None, offset=None, exponents=None, weights=None)
=[0.]
> color=red penwidth=1 rank=same shape=plaintext]\n\t\tB:"OutputPort-OutputPort-0" -> "MIDDLE COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_B_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tC:"OutputPort-OutputPort-0" -> "MIDDLE COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_C_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"INNER COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_I_OutputPort-0" -> "MIDDLE COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_I_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tC [label=<
OutputPort-0
Linear(intercept=None, slope=None)
=[0.]
OutputPorts
Mechanism:
C

TERMINAL,OUTPUT
Linear(intercept=None, slope=None)
=[[0.]]
ParameterPorts
intercept
Linear(intercept=None, slope=None)
=[0.]
slope
Linear(intercept=None, slope=None)
=[1.]
InputPorts
InputPort-0
LinearCombination(scale=None, offset=None, exponents=None, weights=None)
=[0.]
> color=red penwidth=3 rank=max shape=plaintext]\n\t\tsubgraph "cluster_INNER COMP" {\n\t\t\tgraph [label="INNER COMP" overlap=False rankdir=BT]\n\t\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\t\tedge [fontname=arial fontsize=10]\n\t\t\t"INNER COMP INPUT_CIM" [label=<
INPUT_CIM_I_InputPort-0
Identity()
=[0.]
OutputPorts
Mechanism:
INNER COMP Input_CIM

Identity()
=None
InputPorts
INPUT_CIM_I_InputPort-0
LinearCombination(scale=None, offset=None, exponents=None, weights=None)
=[0.]
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t\t"INNER COMP INPUT_CIM":"OutputPort-INPUT_CIM_I_InputPort-0" -> I:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t\t"INNER COMP PARAMETER_CIM" [label=<
PARAMETER_CIM_I_slope
TransferWithCosts(combine_costs_fct_add_param=None, intensity_cost_fct_mult_param=None, intensity_cost_fct_add_param=None, duration_cost_fct_mult_param=None, adjustment_cost_fct_mult_param=None, duration_cost_fct_add_param=None, adjustment_cost_fct_add_param=None, combine_costs_fct_mult_param=None)
=[1.]
OutputPorts
Mechanism:
INNER COMP Parameter_CIM

Identity()
=None
InputPorts
PARAMETER_CIM_I_slope
LinearCombination(scale=None, offset=None, exponents=None, weights=None)
=[1.]
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t\t"INNER COMP PARAMETER_CIM":"OutputPort-PARAMETER_CIM_I_slope" -> I:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t\t"INNER COMP OUTPUT_CIM" [label=<
OUTPUT_CIM_I_OutputPort-0
Identity()
=[0.]
OutputPorts
Mechanism:
INNER COMP Output_CIM

Identity()
=None
InputPorts
OUTPUT_CIM_I_OutputPort-0
LinearCombination(scale=None, offset=None, exponents=None, weights=None)
=[0.]
> color=red penwidth=1 rank=same shape=plaintext]\n\t\t\tI:"OutputPort-OutputPort-0" -> "INNER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_I_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t\tI [label=<
OutputPort-0
Linear(intercept=None, slope=None)
=[0.]
OutputPorts
Mechanism:
I

INPUT,SINGLETON,TERMINAL,OUTPUT,ORIGIN
Linear(intercept=None, slope=None)
=[[0.]]
ParameterPorts
intercept
Linear(intercept=None, slope=None)
=[0.]
slope
Linear(intercept=None, slope=None)
=[1.]
InputPorts
InputPort-0
LinearCombination(scale=None, offset=None, exponents=None, weights=None)
=[0.]
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\t\tcolor=brown\n\t\t\tlabel="INNER COMP"\n\t\t}\n\t\tcolor=brown\n\t\tlabel="MIDDLE COMP"\n\t}\n}' + # expected_gv_incorrect = 'digraph "OUTER COMP" {\n\tgraph [label="OUTER COMP" overlap=False rankdir=BT]\n\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\tedge [fontname=arial fontsize=10]\n\t"OUTER COMP INPUT_CIM" [label=<
INPUT_CIM_MIDDLE COMP_INPUT_CIM_A_InputPort-0
Identity()
=[0.]
INPUT_CIM_MIDDLE COMP_INPUT_CIM_INNER COMP_INPUT_CIM_I_InputPort-0
Identity()
=[0.]
OutputPorts
Mechanism:
OUTER COMP Input_CIM

Identity()
=None
> color=green penwidth=1 rank=same shape=plaintext]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_MIDDLE COMP_INPUT_CIM_A_InputPort-0" -> "MIDDLE COMP INPUT_CIM":"InputPort-INPUT_CIM_A_InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_MIDDLE COMP_INPUT_CIM_INNER COMP_INPUT_CIM_I_InputPort-0" -> "MIDDLE COMP INPUT_CIM":"InputPort-INPUT_CIM_INNER COMP_INPUT_CIM_I_InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"OUTER COMP OUTPUT_CIM" [label=<
Mechanism:
OUTER COMP Output_CIM

Identity()
=None
InputPorts
OUTPUT_CIM_MIDDLE COMP_OUTPUT_CIM_B_OutputPort-0
LinearCombination(scale=None, weights=None, offset=None, exponents=None)
=[0.]
OUTPUT_CIM_MIDDLE COMP_OUTPUT_CIM_C_OutputPort-0
LinearCombination(scale=None, weights=None, offset=None, exponents=None)
=[0.]
OUTPUT_CIM_MIDDLE COMP_OUTPUT_CIM_INNER COMP_OUTPUT_CIM_I_OutputPort-0
LinearCombination(scale=None, weights=None, offset=None, exponents=None)
=[0.]
> color=red penwidth=1 rank=same shape=plaintext]\n\t"MIDDLE COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_B_OutputPort-0" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_MIDDLE COMP_OUTPUT_CIM_B_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"MIDDLE COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_C_OutputPort-0" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_MIDDLE COMP_OUTPUT_CIM_C_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t"MIDDLE COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_I_OutputPort-0" -> "OUTER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_MIDDLE COMP_OUTPUT_CIM_INNER COMP_OUTPUT_CIM_I_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\tOCM:"OutputPort-I[slope] ControlSignal" -> "MIDDLE COMP PARAMETER_CIM":"InputPort-PARAMETER_CIM_I_slope" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\t"ObjectiveMechanism-0" [label=<
OUTCOME
Linear(slope=None, intercept=None)
=[0.]
OutputPorts
Mechanism:
ObjectiveMechanism-0

INTERNAL,CONTROLLER_OBJECTIVE
LinearCombination(scale=None, weights=None, offset=None, exponents=None)
=[[0.]]
ParameterPorts
offset
Linear(slope=None, intercept=None)
=[0.]
scale
Linear(slope=None, intercept=None)
=[1.]
InputPorts
Value of B [OutputPort-0]
LinearCombination(scale=None, weights=None, offset=None, exponents=None)
=[0.]
> color=purple penwidth=1 rank=min shape=plaintext]\n\t"ObjectiveMechanism-0":"OutputPort-OUTCOME" -> OCM:"InputPort-OUTCOME" [label="" color=purple penwidth=1]\n\t"MIDDLE COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_B_OutputPort-0" -> "ObjectiveMechanism-0":"InputPort-Value of B [OutputPort-0]" [label="" color=purple penwidth=1]\n\t"OUTER COMP INPUT_CIM":"OutputPort-INPUT_CIM_MIDDLE COMP_INPUT_CIM_INNER COMP_INPUT_CIM_I_InputPort-0" -> OCM:"InputPort-Shadowed input of I" [label="" arrowhead=normal color=purple penwidth=1]\n\tOCM [label=<
I[slope] ControlSignal
TransferWithCosts(duration_cost_fct_add_param=None, intensity_cost_fct_add_param=None, duration_cost_fct_mult_param=None, combine_costs_fct_add_param=None, adjustment_cost_fct_add_param=None, combine_costs_fct_mult_param=None, adjustment_cost_fct_mult_param=None, transfer_fct_add_param=None, intensity_cost_fct_mult_param=None, transfer_fct_mult_param=None)
=[1.]
OutputPorts
Mechanism:
OCM

CONTROLLER
Always()
GridSearch(max_iterations=None, seed=-1)
=[[1.]]
ParameterPorts
seed
Linear(slope=None, intercept=None)
=[-1.]
InputPorts
OUTCOME
LinearCombination(scale=None, weights=None, offset=None, exponents=None)
=[0.]
Shadowed input of I
LinearCombination(scale=None, weights=None, offset=None, exponents=None)
=[0.]
> color=purple penwidth=1 rank=min shape=plaintext]\n\tsubgraph "cluster_MIDDLE COMP" {\n\t\tgraph [label="MIDDLE COMP" overlap=False rankdir=BT]\n\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\tedge [fontname=arial fontsize=10]\n\t\tA [label=<
OutputPort-0
Linear(slope=None, intercept=None)
=[0.]
OutputPorts
Mechanism:
A

INPUT,ORIGIN
Linear(slope=None, intercept=None)
=[[0.]]
ParameterPorts
intercept
Linear(slope=None, intercept=None)
=[0.]
slope
Linear(slope=None, intercept=None)
=[1.]
InputPorts
InputPort-0
LinearCombination(scale=None, weights=None, offset=None, exponents=None)
=[0.]
> color=green penwidth=3 rank=source shape=plaintext]\n\t\tB [label=<
OutputPort-0
Linear(slope=None, intercept=None)
=[0.]
OutputPorts
Mechanism:
B

PROBE,INTERNAL
Linear(slope=None, intercept=None)
=[[0.]]
ParameterPorts
intercept
Linear(slope=None, intercept=None)
=[0.]
slope
Linear(slope=None, intercept=None)
=[1.]
InputPorts
InputPort-0
LinearCombination(scale=None, weights=None, offset=None, exponents=None)
=[0.]
> color=black penwidth=1 rank=same shape=plaintext]\n\t\tA:"OutputPort-OutputPort-0" -> B:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\tB:"OutputPort-OutputPort-0" -> C:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1]\n\t\t"MIDDLE COMP INPUT_CIM" [label=<
INPUT_CIM_A_InputPort-0
Identity()
=[0.]
INPUT_CIM_INNER COMP_INPUT_CIM_I_InputPort-0
Identity()
=[0.]
OutputPorts
Mechanism:
MIDDLE COMP Input_CIM

Identity()
=None
InputPorts
INPUT_CIM_A_InputPort-0
LinearCombination(scale=None, weights=None, offset=None, exponents=None)
=[0.]
INPUT_CIM_INNER COMP_INPUT_CIM_I_InputPort-0
LinearCombination(scale=None, weights=None, offset=None, exponents=None)
=[0.]
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t"MIDDLE COMP INPUT_CIM":"OutputPort-INPUT_CIM_A_InputPort-0" -> A:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"MIDDLE COMP INPUT_CIM":"OutputPort-INPUT_CIM_INNER COMP_INPUT_CIM_I_InputPort-0" -> "INNER COMP INPUT_CIM":"InputPort-INPUT_CIM_I_InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"MIDDLE COMP PARAMETER_CIM" [label=<
PARAMETER_CIM_I_slope
TransferWithCosts(duration_cost_fct_add_param=None, intensity_cost_fct_add_param=None, duration_cost_fct_mult_param=None, combine_costs_fct_add_param=None, adjustment_cost_fct_add_param=None, combine_costs_fct_mult_param=None, adjustment_cost_fct_mult_param=None, intensity_cost_fct_mult_param=None)
=[1.]
OutputPorts
Mechanism:
MIDDLE COMP Parameter_CIM

Identity()
=[[0.]\n [1.]]
InputPorts
PARAMETER_CIM_I_slope
LinearCombination(scale=None, weights=None, offset=None, exponents=None)
=[1.]
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t"MIDDLE COMP PARAMETER_CIM":"OutputPort-PARAMETER_CIM_I_slope" -> "INNER COMP PARAMETER_CIM":"InputPort-PARAMETER_CIM_I_slope" [label="" arrowhead=normal color=purple penwidth=1 style=solid]\n\t\t"MIDDLE COMP OUTPUT_CIM" [label=<
OUTPUT_CIM_B_OutputPort-0
Identity()
=[0.]
OUTPUT_CIM_C_OutputPort-0
Identity()
=[0.]
OUTPUT_CIM_INNER COMP_OUTPUT_CIM_I_OutputPort-0
Identity()
=[0.]
OutputPorts
Mechanism:
MIDDLE COMP Output_CIM

Identity()
=None
InputPorts
OUTPUT_CIM_B_OutputPort-0
LinearCombination(scale=None, weights=None, offset=None, exponents=None)
=[0.]
OUTPUT_CIM_C_OutputPort-0
LinearCombination(scale=None, weights=None, offset=None, exponents=None)
=[0.]
OUTPUT_CIM_INNER COMP_OUTPUT_CIM_I_OutputPort-0
LinearCombination(scale=None, weights=None, offset=None, exponents=None)
=[0.]
> color=red penwidth=1 rank=same shape=plaintext]\n\t\tB:"OutputPort-OutputPort-0" -> "MIDDLE COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_B_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tC:"OutputPort-OutputPort-0" -> "MIDDLE COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_C_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t"INNER COMP OUTPUT_CIM":"OutputPort-OUTPUT_CIM_I_OutputPort-0" -> "MIDDLE COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_INNER COMP_OUTPUT_CIM_I_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\tC [label=<
OutputPort-0
Linear(slope=None, intercept=None)
=[0.]
OutputPorts
Mechanism:
C

TERMINAL,OUTPUT
Linear(slope=None, intercept=None)
=[[0.]]
ParameterPorts
intercept
Linear(slope=None, intercept=None)
=[0.]
slope
Linear(slope=None, intercept=None)
=[1.]
InputPorts
InputPort-0
LinearCombination(scale=None, weights=None, offset=None, exponents=None)
=[0.]
> color=red penwidth=3 rank=max shape=plaintext]\n\t\tsubgraph "cluster_INNER COMP" {\n\t\t\tgraph [label="INNER COMP" overlap=False rankdir=BT]\n\t\t\tnode [color=black fontname=arial fontsize=12 penwidth=1 shape=record]\n\t\t\tedge [fontname=arial fontsize=10]\n\t\t\t"INNER COMP INPUT_CIM" [label=<
INPUT_CIM_I_InputPort-0
Identity()
=[0.]
OutputPorts
Mechanism:
INNER COMP Input_CIM

Identity()
=None
InputPorts
INPUT_CIM_I_InputPort-0
LinearCombination(scale=None, weights=None, offset=None, exponents=None)
=[0.]
> color=green penwidth=1 rank=same shape=plaintext]\n\t\t\t"INNER COMP INPUT_CIM":"OutputPort-INPUT_CIM_I_InputPort-0" -> I:"InputPort-InputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t\t"INNER COMP PARAMETER_CIM" [label=<
PARAMETER_CIM_I_slope
TransferWithCosts(duration_cost_fct_add_param=None, intensity_cost_fct_add_param=None, duration_cost_fct_mult_param=None, combine_costs_fct_add_param=None, adjustment_cost_fct_add_param=None, combine_costs_fct_mult_param=None, adjustment_cost_fct_mult_param=None, intensity_cost_fct_mult_param=None)
=[1.]
OutputPorts
Mechanism:
INNER COMP Parameter_CIM

Identity()
=None
InputPorts
PARAMETER_CIM_I_slope
LinearCombination(scale=None, weights=None, offset=None, exponents=None)
=[1.]
> color=purple penwidth=1 rank=same shape=plaintext]\n\t\t\t"INNER COMP PARAMETER_CIM":"OutputPort-PARAMETER_CIM_I_slope" -> I:"ParameterPort-slope" [label="" arrowhead=box color=purple penwidth=1 style=solid]\n\t\t\t"INNER COMP OUTPUT_CIM" [label=<
OUTPUT_CIM_I_OutputPort-0
Identity()
=[0.]
OutputPorts
Mechanism:
INNER COMP Output_CIM

Identity()
=None
InputPorts
OUTPUT_CIM_I_OutputPort-0
LinearCombination(scale=None, weights=None, offset=None, exponents=None)
=[0.]
> color=red penwidth=1 rank=same shape=plaintext]\n\t\t\tI:"OutputPort-OutputPort-0" -> "INNER COMP OUTPUT_CIM":"InputPort-OUTPUT_CIM_I_OutputPort-0" [label="" arrowhead=normal color=black penwidth=1 style=solid]\n\t\t\tI [label=<
OutputPort-0
Linear(slope=None, intercept=None)
=[0.]
OutputPorts
Mechanism:
I

ORIGIN,INPUT,TERMINAL,SINGLETON,OUTPUT
Linear(slope=None, intercept=None)
=[[0.]]
ParameterPorts
intercept
Linear(slope=None, intercept=None)
=[0.]
slope
Linear(slope=None, intercept=None)
=[1.]
InputPorts
InputPort-0
LinearCombination(scale=None, weights=None, offset=None, exponents=None)
=[0.]
> color=brown penwidth=3 rank=same shape=plaintext]\n\t\t\tcolor=brown\n\t\t\tlabel="INNER COMP"\n\t\t}\n\t\tcolor=brown\n\t\tlabel="MIDDLE COMP"\n\t}\n}' + # gv = ocomp.show_graph(output_fmt='source', show_cim=True, show_node_structure=ALL) + # try: + # assert repr(gv) == expected_gv_correct + # except AssertionError: + # try: + # assert repr(gv) == expected_gv_incorrect + # except AssertionError: + # try: + # assert gv == expected_gv_correct + # except AssertionError: + # try: + # assert gv == expected_gv_incorrect + # except AssertionError: + # try: + # assert repr(gv) == repr(expected_gv_correct) + # except AssertionError: + # try: + # assert repr(gv) == repr(expected_gv_incorrect) + # except AssertionError: + # try: + # assert gv == repr(expected_gv_correct) + # except AssertionError: + # assert gv == repr(expected_gv_incorrect) diff --git a/tests/documentation/test_module_docs.py b/tests/documentation/test_module_docs.py index 0a951c3fcbf..ecc18564bf0 100644 --- a/tests/documentation/test_module_docs.py +++ b/tests/documentation/test_module_docs.py @@ -72,7 +72,10 @@ def test_scheduler_substitutions(mod): for pattern, repl in pnl.core.scheduling._global_doc_subs: for cls_name in mod.__all__: cls = getattr(mod, cls_name) - ext_cls = getattr(graph_scheduler, cls_name) + try: + ext_cls = getattr(graph_scheduler, cls_name) + except AttributeError: + continue # global replacements may not happen in every docstring assert re.sub(r'\\\d', '', repl) in cls.__doc__ or not re.match(pattern, ext_cls.__doc__) diff --git a/tests/functions/test_distribution.py b/tests/functions/test_distribution.py index 12f5d64d16b..dcdf066e092 100644 --- a/tests/functions/test_distribution.py +++ b/tests/functions/test_distribution.py @@ -17,12 +17,12 @@ test_data = [ (Functions.DriftDiffusionAnalytical, test_var, {}, None, (1.9774974807292212, 0.012242689689501842, 1.9774974807292207, 1.3147677945132479, 1.7929299891370192, 1.9774974807292207, 1.3147677945132479, 1.7929299891370192)), - (Functions.DriftDiffusionAnalytical, test_var, {"drift_rate": RAND1, "threshold": RAND2, "starting_point": RAND3, "t0":RAND4, "noise": RAND5}, None, + (Functions.DriftDiffusionAnalytical, test_var, {"drift_rate": RAND1, "threshold": RAND2, "starting_value": RAND3, "non_decision_time":RAND4, "noise": RAND5}, None, (0.4236547993389047, -2.7755575615628914e-17, 0.5173675420165031, 0.06942854144616283, 6.302631815990666, 1.4934079600147951, 0.4288991185241868, 1.7740760781361433)), - (Functions.DriftDiffusionAnalytical, -test_var, {"drift_rate": RAND1, "threshold": RAND2, "starting_point": RAND3, "t0":RAND4, "noise": RAND5}, None, + (Functions.DriftDiffusionAnalytical, -test_var, {"drift_rate": RAND1, "threshold": RAND2, "starting_value": RAND3, "non_decision_time":RAND4, "noise": RAND5}, None, (0.42365479933890504, 0.0, 0.5173675420165031, 0.06942854144616283, 6.302631815990666, 1.4934079600147951, 0.4288991185241868, 1.7740760781361433)), # FIXME: Rounding errors result in different behaviour on different platforms -# (Functions.DriftDiffusionAnalytical, 1e-4, {"drift_rate": 1e-5, "threshold": RAND2, "starting_point": RAND3, "t0":RAND4, "noise": RAND5}, "Rounding errors", +# (Functions.DriftDiffusionAnalytical, 1e-4, {"drift_rate": 1e-5, "threshold": RAND2, "starting_value": RAND3, "non_decision_time":RAND4, "noise": RAND5}, "Rounding errors", # (0.5828813465336954, 0.04801236718458773, 0.532471083815943, 0.09633801362499317, 6.111833139205608, 1.5821207676710864, 0.5392724012504414, 1.8065252817609618)), # Two tests with different inputs to show that input is ignored. (Functions.NormalDist, 1e14, {"mean": RAND1, "standard_deviation": RAND2}, None, (1.0890232855122397)), diff --git a/tests/functions/test_integrator.py b/tests/functions/test_integrator.py index 78f19dabcb4..26600d7cc7c 100644 --- a/tests/functions/test_integrator.py +++ b/tests/functions/test_integrator.py @@ -89,47 +89,51 @@ def DriftIntFun(init, value, iterations, noise, **kwargs): 2.36535325, 2.3125881 , 1.94195457, 3.4923464 , 2.73809322], [3., 3., 3., 3., 3., 3., 3., 3., 3., 3.]) -def DriftSphereFun(init, value, iterations, noise, **kwargs): +def LeakyFun(init, value, iterations, noise, **kwargs): assert iterations == 3 + if np.isscalar(noise): if "initializer" not in kwargs: - return ([ 0.61237972, -0.00123971, -0.03658525, 0.06254701, -0.0946239, - 0.29805191, 0.49116849, 0.5427334, 0.57919715, 0.15871794, 0.02219184]) + return [2.20813608, 2.25674001, 2.22389663, 2.2069879, 2.17157305, 2.23649656, 2.17564317, 2.30832598, 2.32932737, 2.15982541] + else: + return [2.93867224, 2.74475902, 2.74803958, 3.06104933, 2.23711905, 2.31689203, 2.19429898, 3.07659637, 3.04734388, 2.96259823] + elif isinstance(noise, pnl.DistributionFunction): + if "initializer" not in kwargs: + return [2.55912037, 1.24455938, 1.43417309, 1.638423, 1.91298882, 1.22700281, 1.71226825, 1.67794471, 1.20395947, 1.48326449] else: - return ([-.132269048, .0000435051787, .0000387398441, -.00000395620568, .000127324586, - -.000501625256, -.000837794371, .125048720, .747570336, -.652303943, -.0000657270465]) + return [3.28965653, 1.73257839, 1.95831604, 2.49248443, 1.97853482, 1.30739828, 1.73092406, 2.4462151, 1.92197598, 2.28603731] else: if "initializer" not in kwargs: - return ([ 0.70894136, 0.00176493, 0.10988845, -0.16462855, -0.17717841, 0.55087821, - 0.39641091, 0.67452852, 0.09826617, 0.06205703, -0.01794999]) + return [2.39694798, 2.27976578, 1.9349721, 2.21280371, 1.5655935, 2.11241762, 1.59283164, 2.46577518, 2.09617208, 1.82765063] else: - return ([-.00372900858, -.000338148799, -.000643154678, .0000436274120, .000667038983, - -.00287440868, -.00208163440, .441976901, .531162110, -.722848147, .000466808385]) + return [3.12748415, 2.76778478, 2.45911505, 3.06686514, 1.6311395, 2.19281309, 1.61148745, 3.23404557, 2.81418859, 2.63042344] -def LeakyFun(init, value, iterations, noise, **kwargs): + +def AccumulatorFun(init, value, iterations, noise, **kwargs): assert iterations == 3 if np.isscalar(noise): if "initializer" not in kwargs: - return [2.20813608, 2.25674001, 2.22389663, 2.2069879, 2.17157305, - 2.23649656, 2.17564317, 2.30832598, 2.32932737, 2.15982541] + # variable is not used in Accumulator + return [[1.38631136, 1.38631136, 1.38631136, 1.38631136, 1.38631136, + 1.38631136, 1.38631136, 1.38631136, 1.38631136, 1.38631136]] else: - return [2.93867224, 2.74475902, 2.74803958, 3.06104933, 2.23711905, - 2.31689203, 2.19429898, 3.07659637, 3.04734388, 2.96259823] + return [[1.40097107, 1.39610447, 1.39682937, 1.40344986, 1.38762668, + 1.38792466, 1.38668573, 1.40172829, 1.40071984, 1.40242065]] elif isinstance(noise, pnl.DistributionFunction): if "initializer" not in kwargs: - return [2.55912037, 1.24455938, 1.43417309, 1.638423, 1.91298882, - 1.22700281, 1.71226825, 1.67794471, 1.20395947, 1.48326449] + return [[1.46381634, 0.97440038, 0.54931704, 0.28681701, 0.26162584, + 0.66800459, 1.1010486, 0.02587729, 0.38761176, -0.56452977]] else: - return [3.28965653, 1.73257839, 1.95831604, 2.49248443, 1.97853482, - 1.30739828, 1.73092406, 2.4462151, 1.92197598, 2.28603731] + return [[1.47847605, 0.98419348, 0.55983505, 0.30395551, 0.26294116, + 0.66961789, 1.10142297, 0.04129421, 0.40202024, -0.54842049]] else: if "initializer" not in kwargs: - return [2.39694798, 2.27976578, 1.9349721, 2.21280371, 1.5655935, - 2.11241762, 1.59283164, 2.46577518, 2.09617208, 1.82765063] + return [[1.65907194, 1.41957474, 0.96892655, 1.39471298, 0.51090402, + 1.20706503, 0.5443729, 1.61376489, 1.04949166, 0.90644658]] else: - return [3.12748415, 2.76778478, 2.45911505, 3.06686514, 1.6311395, - 2.19281309, 1.61148745, 3.23404557, 2.81418859, 2.63042344] + return [[1.67373165, 1.42936784, 0.97944456, 1.41185147, 0.51221934, + 1.20867833, 0.54474727, 1.62918182, 1.06390014, 0.92255587]] GROUP_PREFIX="IntegratorFunction " @@ -147,8 +151,8 @@ def LeakyFun(init, value, iterations, noise, **kwargs): (Functions.AdaptiveIntegrator, AdaptiveIntFun), (Functions.SimpleIntegrator, SimpleIntFun), (Functions.DriftDiffusionIntegrator, DriftIntFun), - (Functions.DriftOnASphereIntegrator, DriftSphereFun), (Functions.LeakyCompetingIntegrator, LeakyFun), + (Functions.AccumulatorIntegrator, AccumulatorFun), ], ids=lambda x: x[0]) @pytest.mark.benchmark def test_execute(func, func_mode, variable, noise, params, benchmark): @@ -160,7 +164,7 @@ def test_execute(func, func_mode, variable, noise, params, benchmark): raise e from None else: assert isinstance(noise, pnl.DistributionFunction) - if func[1] == DriftIntFun or func[1] == DriftSphereFun: + if func[1] == DriftIntFun: pytest.skip("DriftDiffusionIntegrator doesn't support functional noise") if 'DriftOnASphereIntegrator' in func[0].componentName: @@ -171,7 +175,20 @@ def test_execute(func, func_mode, variable, noise, params, benchmark): if 'dimension' in params: params.pop('dimension') - f = func[0](default_variable=variable, noise=noise, **params) + if 'AccumulatorIntegrator' in func[0].componentName: + params = { + **params, + 'increment': RAND0_1, + } + params.pop('offset') + + # If we are dealing with a DriftDiffusionIntegrator, noise and time_step_size defaults + # have changed since this test was created. Hard code their old values. + if 'DriftDiffusionIntegrator' in str(func[0]): + f = func[0](default_variable=variable, noise=np.sqrt(noise), time_step_size=1.0, **params) + else: + f = func[0](default_variable=variable, noise=noise, **params) + ex = pytest.helpers.get_func_execution(f, func_mode) ex(variable) diff --git a/tests/functions/test_memory.py b/tests/functions/test_memory.py index c3f61f6e590..fe712bc49bb 100644 --- a/tests/functions/test_memory.py +++ b/tests/functions/test_memory.py @@ -219,7 +219,7 @@ def test_DictionaryMemory_with_initializer_and_key_size_same_as_val_size(self): em.function.duplicate_keys = False stim = 'A' - text = r'More than one item matched key \(\[1 2 3\]\) in memory for DictionaryMemory' + text = r'More than one item matched key \(\[1. 2. 3.\]\) in memory for DictionaryMemory' with pytest.warns(UserWarning, match=text): retrieved = em.execute(stimuli[stim]) @@ -271,7 +271,7 @@ def test_DictionaryMemory_with_initializer_and_key_size_diff_from_val_size(self) em.function.duplicate_keys = False stim = 'A' - text = r'More than one item matched key \(\[1 2 3\]\) in memory for DictionaryMemory' + text = r'More than one item matched key \(\[1. 2. 3.\]\) in memory for DictionaryMemory' with pytest.warns(UserWarning, match=text): retrieved = em.execute(stimuli[stim]) @@ -341,7 +341,7 @@ def test_DictionaryMemory_without_initializer_and_key_size_same_as_val_size(self em.function.duplicate_keys = False stim = 'A' - text = r'More than one item matched key \(\[1 2 3\]\) in memory for DictionaryMemory' + text = r'More than one item matched key \(\[1. 2. 3.\]\) in memory for DictionaryMemory' with pytest.warns(UserWarning, match=text): retrieved = em.execute(stimuli[stim]) @@ -391,7 +391,7 @@ def test_DictionaryMemory_without_initializer_and_key_size_diff_from_val_size(se em.function.duplicate_keys = False stim = 'A' - text = r'More than one item matched key \(\[1 2 3\]\) in memory for DictionaryMemory' + text = r'More than one item matched key \(\[1. 2. 3.\]\) in memory for DictionaryMemory' with pytest.warns(UserWarning, match=text): retrieved = em.execute(stimuli[stim]) diff --git a/tests/functions/test_optimization.py b/tests/functions/test_optimization.py index 2cf83047290..2069c2b2356 100644 --- a/tests/functions/test_optimization.py +++ b/tests/functions/test_optimization.py @@ -79,7 +79,7 @@ def test_grid_search(obj_func, metric, normalize, direction, selection, benchmar f = OPTFunctions.GridSearch(objective_function=of, default_variable=variable, search_space=search_space, direction=direction, select_randomly_from_optimal_values=(selection=='RANDOM'), - seed=0) + seed=0, save_values=False) EX = pytest.helpers.get_func_execution(f, func_mode) res = EX(variable) diff --git a/tests/functions/test_selection.py b/tests/functions/test_selection.py index 1dc450f9989..3ca5059706a 100644 --- a/tests/functions/test_selection.py +++ b/tests/functions/test_selection.py @@ -19,6 +19,7 @@ test_data = [ (Functions.OneHot, test_var, {'mode':kw.MAX_VAL}, [0., 0., 0., 0., 0., 0., 0., 0., 0.92732552, 0.]), (Functions.OneHot, test_var, {'mode':kw.MAX_ABS_VAL}, [0., 0., 0., 0., 0., 0., 0., 0., 0.92732552, 0.]), + (Functions.OneHot, -test_var, {'mode':kw.MAX_ABS_VAL}, [0., 0., 0., 0., 0., 0., 0., 0., 0.92732552, 0.]), (Functions.OneHot, test_var, {'mode':kw.MAX_INDICATOR}, [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.]), (Functions.OneHot, test_var, {'mode':kw.MAX_ABS_INDICATOR}, [0., 0., 0., 0., 0., 0., 0., 0., 1., 0.]), (Functions.OneHot, test_var, {'mode':kw.MIN_VAL}, [0., 0., 0., 0., 0., 0., 0., 0., 0., -0.23311696]), @@ -35,6 +36,7 @@ names = [ "OneHot MAX_VAL", "OneHot MAX_ABS_VAL", + "OneHot MAX_ABS_VAL_NEG", "OneHot MAX_INDICATOR", "OneHot MAX_ABS_INDICATOR", "OneHot MIN_VAL", diff --git a/tests/functions/test_user_defined_func.py b/tests/functions/test_user_defined_func.py index a11907e944c..d6786284fde 100644 --- a/tests/functions/test_user_defined_func.py +++ b/tests/functions/test_user_defined_func.py @@ -31,7 +31,7 @@ def binDiv(_, param1, param2): def binPow(_, param1, param2): - return param1 / param2 + return param1 ** param2 @pytest.mark.parametrize("param1", [1, np.ones(2), np.ones((2, 2))], ids=['scalar', 'vector', 'matrix']) @@ -295,6 +295,9 @@ def condValReturn(variable, param1, param2): val = param2 + 0.3 return val +def lambdaGen(): + return lambda var, param1, param2: var + param1 * param2 + @pytest.mark.parametrize("func,var,params,expected", [ (simpleFun, [1, 3], {"param1":None, "param2":3}, [5, 9]), @@ -302,6 +305,7 @@ def condValReturn(variable, param1, param2): (condReturn, [1], {"param1":1, "param2":2}, [1.5]), (condValReturn, [0], {"param1":1, "param2":2}, [2.3]), (condValReturn, [1], {"param1":1, "param2":2}, [1.5]), + (lambdaGen(), [3], {"param1":3, "param2":-0.5}, [1.5]), ]) @pytest.mark.benchmark(group="Function UDF") def test_user_def_func(func, var, params, expected, func_mode, benchmark): diff --git a/tests/json/model_basic.py b/tests/json/model_basic.py index ce970179dd4..92ce6a7679b 100644 --- a/tests/json/model_basic.py +++ b/tests/json/model_basic.py @@ -16,5 +16,5 @@ comp.termination_processing = { pnl.TimeScale.RUN: pnl.AfterNTrials(1), - pnl.TimeScale.TRIAL: pnl.AfterNCalls(B, 4) + pnl.TimeScale.TRIAL: pnl.All(pnl.Not(pnl.BeforeNCalls(B, 5))) } diff --git a/tests/json/model_basic_non_identity.py b/tests/json/model_basic_non_identity.py new file mode 100644 index 00000000000..2b76494c351 --- /dev/null +++ b/tests/json/model_basic_non_identity.py @@ -0,0 +1,20 @@ +import psyneulink as pnl + +comp = pnl.Composition(name='comp') +A = pnl.TransferMechanism(function=pnl.Linear(slope=5.0, intercept=2.0), name='A') +B = pnl.TransferMechanism(function=pnl.Logistic, name='B') + +for m in [A, B]: + comp.add_node(m) + +comp.add_projection(pnl.MappingProjection(matrix=[[2]]), A, B) + +comp.scheduler.add_condition_set({ + A: pnl.EveryNPasses(1), + B: pnl.EveryNCalls(A, 2), +}) + +comp.termination_processing = { + pnl.TimeScale.RUN: pnl.AfterNTrials(1), + pnl.TimeScale.TRIAL: pnl.AfterNCalls(B, 4) +} diff --git a/tests/json/model_integrators.py b/tests/json/model_integrators.py new file mode 100644 index 00000000000..100b7985319 --- /dev/null +++ b/tests/json/model_integrators.py @@ -0,0 +1,67 @@ +import psyneulink as pnl + +comp = pnl.Composition(name="comp") +A = pnl.TransferMechanism( + name="A", + function=pnl.Linear(slope=0.5, intercept=1.0), + integrator_mode=True, + integrator_function=pnl.SimpleIntegrator( + rate=0.5, + noise=pnl.UniformDist(low=-1.0, high=1.0, seed=0) + ), +) +B = pnl.TransferMechanism( + name="B", + function=pnl.Logistic(gain=0.1), + integrator_mode=True, + integration_rate=0.9, + integrator_function=pnl.AdaptiveIntegrator( + offset=-1, + noise=pnl.NormalDist(mean=-1.0, standard_deviation=0.5, seed=0) + ), +) + +C = pnl.TransferMechanism( + name="C", + integrator_mode=True, + integration_rate=0.5, + integrator_function=pnl.AccumulatorIntegrator( + noise=pnl.NormalDist(standard_deviation=0.25, seed=0) + ), +) + +D = pnl.TransferMechanism( + name="D", + integrator_mode=True, + integration_rate=0.5, + integrator_function=pnl.LeakyCompetingIntegrator( + noise=pnl.UniformDist(low=-0.5, high=0.5, seed=0), + time_step_size=0.2, + ), +) + +E = pnl.IntegratorMechanism( + name="E", + function=pnl.SimpleIntegrator( + rate=0.5, + offset=-1, + noise=pnl.UniformDist(low=-0.25, high=0.5, seed=0) + ) +) + +comp.add_linear_processing_pathway([A, B, C, D, E]) + +comp.scheduler.add_condition_set( + { + A: pnl.EveryNPasses(1), + B: pnl.EveryNCalls(A, 2), + C: pnl.EveryNCalls(B, 2), + D: pnl.EveryNCalls(C, 2), + E: pnl.EveryNCalls(D, 2), + } +) + +comp.termination_processing = { + pnl.TimeScale.RUN: pnl.AfterNTrials(1), + pnl.TimeScale.TRIAL: pnl.All(pnl.Not(pnl.BeforeNCalls(E, 5))), +} diff --git a/tests/json/model_nested_comp_with_scheduler.py b/tests/json/model_nested_comp_with_scheduler.py index 045e4eed4c1..637c2cd86d0 100644 --- a/tests/json/model_nested_comp_with_scheduler.py +++ b/tests/json/model_nested_comp_with_scheduler.py @@ -29,7 +29,8 @@ comp.scheduler.add_condition_set({ A: pnl.EveryNPasses(1), B: pnl.EveryNCalls(A, 2), - C: pnl.EveryNCalls(B, 2) + C: pnl.EveryNCalls(B, 2), + D: pnl.TimeInterval(start=1), }) comp.termination_processing = { diff --git a/tests/json/model_udfs.py b/tests/json/model_udfs.py new file mode 100644 index 00000000000..6fb3cfba841 --- /dev/null +++ b/tests/json/model_udfs.py @@ -0,0 +1,23 @@ +import graph_scheduler +import modeci_mdf.functions.standard + +import psyneulink as pnl + +A = pnl.TransferMechanism(name='A') +B = pnl.ProcessingMechanism( + name='B', + function=pnl.UserDefinedFunction( + modeci_mdf.functions.standard.mdf_functions['sin']['function'], + scale=1 + ) +) +C = pnl.ProcessingMechanism( + name='C', + function=pnl.UserDefinedFunction( + modeci_mdf.functions.standard.mdf_functions['cos']['function'], + scale=1 + ) +) +comp = pnl.Composition(name='comp', pathways=[A, B, C]) +comp.scheduler.add_condition(B, pnl.EveryNCalls(A, 2)) +comp.scheduler.add_condition(C, graph_scheduler.EveryNCalls(B, 2)) diff --git a/tests/json/model_varied_matrix_sizes.py b/tests/json/model_varied_matrix_sizes.py new file mode 100644 index 00000000000..900f0b570f1 --- /dev/null +++ b/tests/json/model_varied_matrix_sizes.py @@ -0,0 +1,15 @@ +import psyneulink as pnl + +comp = pnl.Composition(name='comp') +A = pnl.TransferMechanism(name='A', size=2) +B = pnl.TransferMechanism(name='B', size=3) +C = pnl.TransferMechanism(name='C', size=4) +D = pnl.TransferMechanism(name='D', size=5) + +for n in [A, B, C, D]: + comp.add_node(n) + +comp.add_projection(pnl.MappingProjection(matrix=[[1, 2, 3], [4, 5, 6]]), A, B) +comp.add_projection(pnl.MappingProjection(matrix=[[1, 2, 3, 4], [5, 6, 7, 8]]), A, C) +comp.add_projection(pnl.MappingProjection(matrix=[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]]), B, D) +comp.add_projection(pnl.MappingProjection(matrix=[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16, 17, 18, 19, 20]]), C, D) diff --git a/tests/json/model_with_control.py b/tests/json/model_with_control.py index 17240875340..54b1ac053ad 100644 --- a/tests/json/model_with_control.py +++ b/tests/json/model_with_control.py @@ -27,8 +27,8 @@ ), ), noise=0.5, - starting_point=0, - t0=0.45, + starting_value=0, + non_decision_time=0.45, ), output_ports=[ pnl.DECISION_VARIABLE, @@ -48,7 +48,7 @@ controller=pnl.OptimizationControlMechanism( agent_rep=comp, state_features=[Input.input_port, reward.input_port], - state_feature_functions=pnl.AdaptiveIntegrator(rate=0.5), + state_feature_function=pnl.AdaptiveIntegrator(rate=0.5), objective_mechanism=pnl.ObjectiveMechanism( function=pnl.LinearCombination(operation=pnl.PRODUCT), monitor=[ diff --git a/tests/json/test_json.py b/tests/json/test_json.py index 09c9f700215..091e55def88 100644 --- a/tests/json/test_json.py +++ b/tests/json/test_json.py @@ -2,6 +2,13 @@ import os import psyneulink as pnl import pytest +import sys + + +pytest.importorskip( + 'modeci_mdf', + reason='JSON methods require modeci_mdf package' +) # stroop stimuli red = [1, 0] @@ -18,30 +25,55 @@ json_results_parametrization = [ - # ('model_basic.py', 'comp', '{A: 1}'), - # ('model_nested_comp_with_scheduler.py', 'comp', '{A: 1}'), - # ( - # 'model_with_control.py', - # 'comp', - # '{Input: [0.5, 0.123], reward: [20, 20]}' - # ), + ('model_basic.py', 'comp', '{A: 1}', True), + ('model_basic.py', 'comp', '{A: 1}', False), + ('model_basic_non_identity.py', 'comp', '{A: 1}', True), + ('model_basic_non_identity.py', 'comp', '{A: 1}', False), + ('model_udfs.py', 'comp', '{A: 10}', True), + ('model_udfs.py', 'comp', '{A: 10}', False), + ('model_varied_matrix_sizes.py', 'comp', '{A: [1, 2]}', True), + ('model_varied_matrix_sizes.py', 'comp', '{A: [1, 2]}', False), + ('model_integrators.py', 'comp', '{A: 1.0}', True), + ('model_integrators.py', 'comp', '{A: 1.0}', False), + pytest.param( + 'model_nested_comp_with_scheduler.py', + 'comp', + '{A: 1}', + True, + marks=pytest.mark.xfail(reason='Nested Graphs not supported in MDF') + ), + pytest.param( + 'model_nested_comp_with_scheduler.py', + 'comp', + '{A: 1}', + False, + marks=pytest.mark.xfail(reason='Nested Graphs not supported in MDF') + ), + ( + 'model_with_control.py', + 'comp', + '{Input: [0.5, 0.123], reward: [20, 20]}', + False + ), ( 'stroop_conflict_monitoring.py', 'Stroop_model', - str(stroop_stimuli).replace("'", '') + str(stroop_stimuli).replace("'", ''), + False ), - # ('model_backprop.py', 'comp', '{a: [1, 2, 3]}'), + ('model_backprop.py', 'comp', '{a: [1, 2, 3]}', False), ] @pytest.mark.parametrize( - 'filename, composition_name, input_dict_str', + 'filename, composition_name, input_dict_str, simple_edge_format', json_results_parametrization ) def test_json_results_equivalence( filename, composition_name, input_dict_str, + simple_edge_format, ): # Get python script from file and execute filename = f'{os.path.dirname(__file__)}/{filename}' @@ -52,23 +84,23 @@ def test_json_results_equivalence( # reset random seed pnl.core.globals.utilities.set_global_seed(0) - # Generate python script from JSON summary of composition and execute - json_summary = eval(f'{composition_name}.json_summary') + json_summary = pnl.generate_json(eval(f'{composition_name}'), simple_edge_format=simple_edge_format) exec(pnl.generate_script_from_json(json_summary)) exec(f'{composition_name}.run(inputs={input_dict_str})') new_results = eval(f'{composition_name}.results') - assert orig_results == new_results + assert pnl.safe_equals(orig_results, new_results) @pytest.mark.parametrize( - 'filename, composition_name, input_dict_str', + 'filename, composition_name, input_dict_str, simple_edge_format', json_results_parametrization ) def test_write_json_file( filename, composition_name, input_dict_str, + simple_edge_format, ): # Get python script from file and execute filename = f'{os.path.dirname(__file__)}/{filename}' @@ -82,12 +114,12 @@ def test_write_json_file( # Save json_summary of Composition to file and read back in. json_filename = filename.replace('.py','.json') - exec(f'pnl.write_json_file({composition_name}, json_filename)') + exec(f'pnl.write_json_file({composition_name}, json_filename, simple_edge_format=simple_edge_format)') exec(pnl.generate_script_from_json(json_filename)) # exec(f'{composition_name}.run(inputs={input_dict_str})') exec(f'pnl.get_compositions()[0].run(inputs={input_dict_str})') final_results = eval(f'{composition_name}.results') - assert orig_results == final_results + assert pnl.safe_equals(orig_results, final_results) @pytest.mark.parametrize( @@ -129,3 +161,82 @@ def test_write_json_file_multiple_comps( exec(f'{composition_name}.run(inputs={input_dict_strs[composition_name]})') final_results = eval(f'{composition_name}.results') assert orig_results[composition_name] == final_results, f'{composition_name}:' + + +# These runtime_params are necessary because noise seeding is not +# replicable between numpy and onnx. +# Values are generated from running onnx function RandomUniform and +# RandomNormal with parameters used in model_integrators.py (seed 0). +# RandomNormal values are different on mac versus linux and windows +if sys.platform == 'linux': + onnx_integrators_fixed_seeded_noise = { + 'A': [[-0.9999843239784241]], + 'B': [[-1.1295466423034668]], + 'C': [[-0.0647732987999916]], + 'D': [[-0.499992161989212]], + 'E': [[-0.2499941289424896]], + } +elif sys.platform == 'win32': + onnx_integrators_fixed_seeded_noise = { + 'A': [[0.0976270437240601]], + 'B': [[-0.4184607267379761]], + 'C': [[0.290769636631012]], + 'D': [[0.04881352186203]], + 'E': [[0.1616101264953613]], + } +else: + assert sys.platform == 'darwin' + onnx_integrators_fixed_seeded_noise = { + 'A': [[-0.9999550580978394]], + 'B': [[-0.8846577405929565]], + 'C': [[0.0576711297035217]], + 'D': [[-0.4999775290489197]], + 'E': [[-0.2499831467866898]], + } + +integrators_runtime_params = ( + 'runtime_params={' + + ','.join([f'{k}: {{ "noise": {v} }}' for k, v in onnx_integrators_fixed_seeded_noise.items()]) + + '}' +) + + +@pytest.mark.parametrize( + 'filename, composition_name, input_dict, simple_edge_format, run_args', + [ + ('model_basic.py', 'comp', {'A': [[1.0]]}, True, ''), + ('model_basic.py', 'comp', {'A': 1}, False, ''), + ('model_basic_non_identity.py', 'comp', {'A': [[1.0]]}, True, ''), # requires simple edges + ('model_udfs.py', 'comp', {'A': [[10.0]]}, True, ''), + ('model_udfs.py', 'comp', {'A': 10}, False, ''), + ('model_varied_matrix_sizes.py', 'comp', {'A': [[1.0, 2.0]]}, True, ''), + ('model_integrators.py', 'comp', {'A': 1.0}, True, integrators_runtime_params), + ('model_integrators.py', 'comp', {'A': 1.0}, False, integrators_runtime_params), + ] +) +def test_mdf_equivalence(filename, composition_name, input_dict, simple_edge_format, run_args): + from modeci_mdf.utils import load_mdf + import modeci_mdf.execution_engine as ee + + # Get python script from file and execute + filename = f'{os.path.dirname(__file__)}/{filename}' + with open(filename, 'r') as orig_file: + exec(orig_file.read()) + inputs_str = str(input_dict).replace("'", '') + exec(f'{composition_name}.run(inputs={inputs_str}, {run_args})') + orig_results = eval(f'{composition_name}.results') + + # Save json_summary of Composition to file and read back in. + json_filename = filename.replace('.py', '.json') + pnl.write_json_file(eval(composition_name), json_filename, simple_edge_format=simple_edge_format) + + m = load_mdf(json_filename) + eg = ee.EvaluableGraph(m.graphs[0], verbose=True) + eg.evaluate(initializer={f'{node}_InputPort_0': i for node, i in input_dict.items()}) + + mdf_results = [ + [eo.curr_value for _, eo in eg.enodes[node.id].evaluable_outputs.items()] + for node in eg.scheduler.consideration_queue[-1] + ] + + assert pnl.safe_equals(orig_results, mdf_results) diff --git a/tests/llvm/test_builtins_intrinsics.py b/tests/llvm/test_builtins_intrinsics.py index 37d0204656b..dad65836dd8 100644 --- a/tests/llvm/test_builtins_intrinsics.py +++ b/tests/llvm/test_builtins_intrinsics.py @@ -13,8 +13,8 @@ (np.log, (x,), "__pnl_builtin_log", np.log(x)), (np.power, (x,y), "__pnl_builtin_pow", np.power(x, y)), (np.tanh, (x,), "__pnl_builtin_tanh", np.tanh(x)), - (lambda x: 1 / np.tanh(x), (x,), "__pnl_builtin_coth", 1 / np.tanh(x)), - (lambda x: 1 / np.sinh(x), (x,), "__pnl_builtin_csch", 1 / np.sinh(x)), + (lambda x: 1.0 / np.tanh(x), (x,), "__pnl_builtin_coth", 1 / np.tanh(x)), + (lambda x: 1.0 / np.sinh(x), (x,), "__pnl_builtin_csch", 1 / np.sinh(x)), ], ids=["EXP", "LOG", "POW", "TANH", "COTH", "CSCH"]) def test_builtin_op(benchmark, op, args, builtin, result, func_mode): if func_mode == 'Python': diff --git a/tests/llvm/test_builtins_matrix.py b/tests/llvm/test_builtins_matrix.py index 5660fbc862a..8010f3d317c 100644 --- a/tests/llvm/test_builtins_matrix.py +++ b/tests/llvm/test_builtins_matrix.py @@ -9,6 +9,7 @@ DIM_X = 1000 DIM_Y = 2000 u = np.random.rand(DIM_X, DIM_Y) +trans_u = u.transpose() v = np.random.rand(DIM_X, DIM_Y) vector = np.random.rand(DIM_X) trans_vector = np.random.rand(DIM_Y) @@ -24,7 +25,7 @@ mat_sub_res = np.subtract(u,v) mat_mul_res = np.multiply(u, v) dot_res = np.dot(vector, u) -trans_dot_res = np.dot(trans_vector, u.transpose()) +trans_dot_res = np.dot(trans_vector, trans_u) mat_sadd_res = np.add(u, scalar) mat_smul_res = np.multiply(u, scalar) @@ -95,7 +96,8 @@ def ex(): @pytest.mark.benchmark(group="Dot") def test_dot(benchmark, func_mode): if func_mode == 'Python': - ex = lambda : np.dot(vector, u) + def ex(): + return np.dot(vector, u) elif func_mode == 'LLVM': bin_f = pnlvm.LLVMBinaryFunction.get("__pnl_builtin_vxm") def ex(): @@ -153,8 +155,8 @@ def test_dot_llvm_constant_dim(benchmark, mode): @pytest.mark.benchmark(group="Dot") def test_dot_transposed(benchmark, func_mode): if func_mode == 'Python': - trans_u = u.transpose() - ex = lambda : np.dot(trans_vector, trans_u) + def ex(): + return np.dot(trans_vector, trans_u) elif func_mode == 'LLVM': bin_f = pnlvm.LLVMBinaryFunction.get("__pnl_builtin_vxm_transposed") def ex(): diff --git a/tests/llvm/test_debug_composition.py b/tests/llvm/test_debug_composition.py index b12698c9d13..5555e601791 100644 --- a/tests/llvm/test_debug_composition.py +++ b/tests/llvm/test_debug_composition.py @@ -9,7 +9,7 @@ from psyneulink.core.components.mechanisms.processing.transfermechanism import TransferMechanism from psyneulink.core.compositions.composition import Composition -debug_options=["const_input=[[[7]]]", "const_input", "const_data", "const_params", "const_data", "const_state", "stat", "time_stat"] +debug_options=["const_input=[[[7]]]", "const_input", "const_data", "const_params", "const_data", "const_state", "stat", "time_stat", "unaligned_copy"] options_combinations = (";".join(("debug_info", *c)) for i in range(len(debug_options) + 1) for c in combinations(debug_options, i)) @pytest.mark.composition diff --git a/tests/llvm/test_helpers.py b/tests/llvm/test_helpers.py index 7d41f9930fc..6862c784d00 100644 --- a/tests/llvm/test_helpers.py +++ b/tests/llvm/test_helpers.py @@ -102,15 +102,27 @@ def test_helper_fclamp_const(mode): @pytest.mark.llvm @pytest.mark.parametrize('mode', ['CPU', pytest.param('PTX', marks=pytest.mark.cuda)]) -def test_helper_is_close(mode): +@pytest.mark.parametrize('rtol,atol', + [[0, 0], [None, None], [None, 100], [2, None]]) +@pytest.mark.parametrize('var1,var2', + [[1, 1], [1, 100], [1,2], [-4,5], [0, -100], [-1,-2], + [[1,1,1,-4,0,-1], [1,100,2,5,-100,-2]] + ]) +def test_helper_is_close(mode, var1, var2, rtol, atol): + + tolerance = {} + if rtol is not None: + tolerance['rtol'] = rtol + if atol is not None: + tolerance['atol'] = atol + with pnlvm.LLVMBuilderContext.get_current() as ctx: double_ptr_ty = ir.DoubleType().as_pointer() func_ty = ir.FunctionType(ir.VoidType(), [double_ptr_ty, double_ptr_ty, double_ptr_ty, ctx.int32_ty]) - # Create clamp function - custom_name = ctx.get_unique_name("all_close") + custom_name = ctx.get_unique_name("is_close") function = ir.Function(ctx.module, func_ty, name=custom_name) in1, in2, out, count = function.args block = function.append_basic_block(name="entry") @@ -122,7 +134,7 @@ def test_helper_is_close(mode): val2_ptr = b1.gep(in2, [index]) val1 = b1.load(val1_ptr) val2 = b1.load(val2_ptr) - close = pnlvm.helpers.is_close(ctx, b1, val1, val2) + close = pnlvm.helpers.is_close(ctx, b1, val1, val2, **tolerance) out_ptr = b1.gep(out, [index]) out_val = b1.select(close, val1.type(1), val1.type(0)) res = b1.select(close, out_ptr.type.pointee(1), @@ -131,14 +143,12 @@ def test_helper_is_close(mode): builder.ret_void() - vec1 = copy.deepcopy(VECTOR) - tmp = np.random.rand(DIM_X) - tmp[0::2] = vec1[0::2] - vec2 = np.asfarray(tmp) + vec1 = np.atleast_1d(np.asfarray(var1)) + vec2 = np.atleast_1d(np.asfarray(var2)) assert len(vec1) == len(vec2) res = np.empty_like(vec2) - ref = np.isclose(vec1, vec2) + ref = np.isclose(vec1, vec2, **tolerance) bin_f = pnlvm.LLVMBinaryFunction.get(custom_name) if mode == 'CPU': ct_ty = ctypes.POINTER(bin_f.byref_arg_types[0]) @@ -146,7 +156,7 @@ def test_helper_is_close(mode): ct_vec2 = vec2.ctypes.data_as(ct_ty) ct_res = res.ctypes.data_as(ct_ty) - bin_f(ct_vec1, ct_vec2, ct_res, DIM_X) + bin_f(ct_vec1, ct_vec2, ct_res, len(res)) else: bin_f.cuda_wrap_call(vec1, vec2, res, np.int32(DIM_X)) @@ -156,10 +166,26 @@ def test_helper_is_close(mode): @pytest.mark.llvm @pytest.mark.parametrize('mode', ['CPU', pytest.param('PTX', marks=pytest.mark.cuda)]) -def test_helper_all_close(mode): +@pytest.mark.parametrize('rtol,atol', + [[0, 0], [None, None], [None, 100], [2, None]]) +@pytest.mark.parametrize('var1,var2', + [[1, 1], [1, 100], [1,2], [-4,5], [0, -100], [-1,-2], + [[1,1,1,-4,0,-1], [1,100,2,5,-100,-2]] + ]) +def test_helper_all_close(mode, var1, var2, atol, rtol): + + tolerance = {} + if rtol is not None: + tolerance['rtol'] = rtol + if atol is not None: + tolerance['atol'] = atol + + vec1 = np.atleast_1d(np.asfarray(var1)) + vec2 = np.atleast_1d(np.asfarray(var2)) + assert len(vec1) == len(vec2) with pnlvm.LLVMBuilderContext.get_current() as ctx: - arr_ptr_ty = ir.ArrayType(ir.DoubleType(), DIM_X).as_pointer() + arr_ptr_ty = ir.ArrayType(ir.DoubleType(), len(vec1)).as_pointer() func_ty = ir.FunctionType(ir.VoidType(), [arr_ptr_ty, arr_ptr_ty, ir.IntType(32).as_pointer()]) @@ -169,15 +195,13 @@ def test_helper_all_close(mode): block = function.append_basic_block(name="entry") builder = ir.IRBuilder(block) - all_close = pnlvm.helpers.all_close(ctx, builder, in1, in2) + all_close = pnlvm.helpers.all_close(ctx, builder, in1, in2, **tolerance) res = builder.select(all_close, out.type.pointee(1), out.type.pointee(0)) builder.store(res, out) builder.ret_void() - vec1 = copy.deepcopy(VECTOR) - vec2 = copy.deepcopy(VECTOR) - ref = np.allclose(vec1, vec2) + ref = np.allclose(vec1, vec2, **tolerance) bin_f = pnlvm.LLVMBinaryFunction.get(custom_name) if mode == 'CPU': ct_ty = ctypes.POINTER(bin_f.byref_arg_types[0]) @@ -196,10 +220,9 @@ def test_helper_all_close(mode): @pytest.mark.llvm @pytest.mark.parametrize("ir_argtype,format_spec,values_to_check", [ (pnlvm.ir.IntType(32), "%u", range(0, 20)), - (pnlvm.ir.IntType(64), "%ld", [int(-4E10), int(-3E10), int(-2E10)]), + (pnlvm.ir.IntType(64), "%lld", [int(-4E10), int(-3E10), int(-2E10)]), (pnlvm.ir.DoubleType(), "%lf", [x *.5 for x in range(0, 5)]), ], ids=["i32", "i64", "double"]) -@pytest.mark.skipif(sys.platform == 'win32', reason="Loading C library is complicated on windows") def test_helper_printf(capfd, ir_argtype, format_spec, values_to_check): format_str = f"Hello {(format_spec+' ')*len(values_to_check)} \n" with pnlvm.LLVMBuilderContext.get_current() as ctx: @@ -216,12 +239,16 @@ def test_helper_printf(capfd, ir_argtype, format_spec, values_to_check): bin_f = pnlvm.LLVMBinaryFunction.get(custom_name) - # Printf is buffered in libc. bin_f() - libc = ctypes.util.find_library("c") + # Printf is buffered in libc. + libc = ctypes.util.find_library("msvcrt" if sys.platform == "win32" else "c") libc = ctypes.CDLL(libc) libc.fflush(0) - assert capfd.readouterr().out == format_str % tuple(values_to_check) + + # Convert format specifier to Python compatible + python_format_spec = {"%lld":"%ld"}.get(format_spec, format_spec) + python_format_str = f"Hello {(python_format_spec+' ')*len(values_to_check)} \n" + assert capfd.readouterr().out == python_format_str % tuple(values_to_check) class TestHelperTypegetters: FLOAT_TYPE = pnlvm.ir.FloatType() diff --git a/tests/log/test_log.py b/tests/log/test_log.py index 37e6a50bf06..2229e2f3d30 100644 --- a/tests/log/test_log.py +++ b/tests/log/test_log.py @@ -780,15 +780,8 @@ def test_log_dictionary_with_scheduler(self): function=psyneulink.core.components.functions.nonstateful.transferfunctions.Linear(slope=6.0)) COMP = pnl.Composition(name='log_test_COMP', pathways=[T1, T2]) - def pass_threshold(mech, thresh): - results = mech.output_ports[0].parameters.value.get(COMP) - for val in results: - if abs(val) >= thresh: - return True - return False - terminate_trial = { - pnl.TimeScale.TRIAL: pnl.While(pass_threshold, T2, 5.0) + pnl.TimeScale.TRIAL: pnl.Threshold(T2, 'value', 5.0, '>=') } T1.set_log_conditions(pnl.VALUE) @@ -833,15 +826,8 @@ def test_log_array_with_scheduler(self): function=psyneulink.core.components.functions.nonstateful.transferfunctions.Linear(slope=6.0)) COMP = pnl.Composition(name='log_test_COMP', pathways=[T1, T2]) - def pass_threshold(mech, thresh): - results = mech.output_ports[0].parameters.value.get(COMP) - for val in results: - if abs(val) >= thresh: - return True - return False - terminate_trial = { - pnl.TimeScale.TRIAL: pnl.While(pass_threshold, T2, 5.0) + pnl.TimeScale.TRIAL: pnl.Threshold(T2, 'value', 5.0, '>=') } T1.set_log_conditions(pnl.VALUE) @@ -908,15 +894,8 @@ def test_log_dictionary_with_scheduler_many_time_step_increments(self): integration_rate=0.05) COMP = pnl.Composition(name='log_test_COMP', pathways=[T1]) - def pass_threshold(mech, thresh): - results = mech.output_ports[0].parameters.value.get(COMP) - for val in results: - if abs(val) >= thresh: - return True - return False - terminate_trial = { - pnl.TimeScale.TRIAL: pnl.While(pass_threshold, T1, 0.95) + pnl.TimeScale.TRIAL: pnl.Threshold(T1, 'value', 0.95, '>=') } T1.set_log_conditions(pnl.VALUE) @@ -1145,8 +1124,8 @@ def node_logged_in_simulation(self): control_signal_params={pnl.ALLOCATION_SAMPLES: np.arange(0.1, 1.01, 0.3)}) ), noise=0.5, - starting_point=0, - t0=0.45 + starting_value=0, + non_decision_time=0.45 ), output_ports=[ pnl.DECISION_VARIABLE, @@ -1165,7 +1144,7 @@ def node_logged_in_simulation(self): controller=pnl.OptimizationControlMechanism( agent_rep=comp, state_features=[Input.input_port, reward.input_port], - state_feature_functions=pnl.AdaptiveIntegrator(rate=0.5), + state_feature_function=pnl.AdaptiveIntegrator(rate=0.5), objective_mechanism=pnl.ObjectiveMechanism( function=pnl.LinearCombination(operation=pnl.PRODUCT), monitor=[ diff --git a/tests/log/test_rpc.py b/tests/log/test_rpc.py index 213673efecb..405706cf97c 100644 --- a/tests/log/test_rpc.py +++ b/tests/log/test_rpc.py @@ -259,15 +259,8 @@ def test_log_dictionary_with_scheduler(self): con_with_rpc_pipeline = pnl.Context(rpc_pipeline=Queue(), execution_id=COMP) pipeline = con_with_rpc_pipeline.rpc_pipeline - def pass_threshold(mech, thresh): - results = mech.output_ports[0].parameters.value.get(COMP) - for val in results: - if abs(val) >= thresh: - return True - return False - terminate_trial = { - pnl.TimeScale.TRIAL: pnl.While(pass_threshold, T2, 5.0) + pnl.TimeScale.TRIAL: pnl.Threshold(T2, 'value', 5.0, '>=', (0, 0)) } T1.set_delivery_conditions(pnl.VALUE) @@ -332,15 +325,8 @@ def test_log_dictionary_with_scheduler_many_time_step_increments(self): con_with_rpc_pipeline = pnl.Context(rpc_pipeline=Queue(), execution_id=COMP) pipeline = con_with_rpc_pipeline.rpc_pipeline - def pass_threshold(mech, thresh): - results = mech.output_ports[0].parameters.value.get(COMP) - for val in results: - if abs(val) >= thresh: - return True - return False - terminate_trial = { - pnl.TimeScale.TRIAL: pnl.While(pass_threshold, T1, 0.95) + pnl.TimeScale.TRIAL: pnl.Threshold(T1, 'value', 0.95, '>=') } T1.set_delivery_conditions(pnl.VALUE) diff --git a/tests/mechanisms/test_control_mechanism.py b/tests/mechanisms/test_control_mechanism.py index 916dee927b7..f43fdaf04b4 100644 --- a/tests/mechanisms/test_control_mechanism.py +++ b/tests/mechanisms/test_control_mechanism.py @@ -257,11 +257,12 @@ def test_control_signal_default_allocation_specification(self): name='C3', default_variable=[10], default_allocation=[4], - control_signals=[pnl.ControlSignal(modulates=(pnl.SLOPE, m1)), # tests for assignment to default_allocation + # Test synonyms allowed for **control**: generic **modulates**, and even more generic **projections**): + control_signals=[pnl.ControlSignal(control=(pnl.SLOPE, m1)), # tests for assignment to default_allocation pnl.ControlSignal(default_allocation=5, # tests for override of default_allocation modulates=(pnl.SLOPE, m2)), pnl.ControlSignal(default_allocation=[6], # as above same but with array - modulates=(pnl.SLOPE, m3))]) + projections=(pnl.SLOPE, m3))]) comp = pnl.Composition() comp.add_nodes([m1,m2,m3]) comp.add_controller(c2) diff --git a/tests/mechanisms/test_ddm_mechanism.py b/tests/mechanisms/test_ddm_mechanism.py index ef9f2ac0643..13f6b9703ae 100644 --- a/tests/mechanisms/test_ddm_mechanism.py +++ b/tests/mechanisms/test_ddm_mechanism.py @@ -9,6 +9,7 @@ from psyneulink.core.components.functions.nonstateful.distributionfunctions import DriftDiffusionAnalytical, NormalDist from psyneulink.core.components.functions.function import FunctionError from psyneulink.core.components.functions.stateful.integratorfunctions import DriftDiffusionIntegrator +from psyneulink.core.components.mechanisms.mechanism import MechanismError from psyneulink.core.components.mechanisms.processing.processingmechanism import ProcessingMechanism from psyneulink.core.compositions.composition import Composition from psyneulink.core.scheduling.condition import Never, WhenFinished @@ -23,7 +24,8 @@ class TestReset: def test_valid(self): D = DDM( name='DDM', - function=DriftDiffusionIntegrator(seed=0), + function=DriftDiffusionIntegrator(seed=0, time_step_size=1.0), + execute_until_finished=False, ) # returns previous_value + rate * variable * time_step_size + noise @@ -76,7 +78,7 @@ def test_valid(self): # reset only decision variable D.function.initializer = 1.0 - D.function.starting_point = 0.0 + D.function.non_decision_time = 0.0 D.reset() assert np.allclose(D.function.value[0], 1.0) assert np.allclose(D.function.previous_value, 1.0) @@ -88,7 +90,7 @@ def test_valid(self): class TestThreshold: def test_threshold_param(self): D = DDM(name='DDM', - function=DriftDiffusionIntegrator(threshold=10.0)) + function=DriftDiffusionIntegrator(threshold=10.0, time_step_size=1.0)) assert D.function.threshold.base == 10.0 @@ -97,7 +99,9 @@ def test_threshold_param(self): def test_threshold_sets_is_finished(self): D = DDM(name='DDM', - function=DriftDiffusionIntegrator(threshold=5.0)) + function=DriftDiffusionIntegrator(threshold=5.0, time_step_size=1.0), + execute_until_finished=False, + reset_stateful_function_when=Never()) D.execute(2.0) # 2.0 < 5.0 assert not D.is_finished() @@ -116,7 +120,8 @@ def test_threshold_sets_is_finished(self): ], ids=["POSITIVE", "NEGATIVE"]) def test_threshold_stops_accumulation(self, mech_mode, variable, expected, benchmark): D = DDM(name='DDM', - function=DriftDiffusionIntegrator(threshold=5.0)) + function=DriftDiffusionIntegrator(threshold=5.0, time_step_size=1.0), + execute_until_finished=False) ex = pytest.helpers.get_mech_execution(D, mech_mode) decision_variables = [] @@ -156,7 +161,9 @@ def test_threshold_stops_accumulation(self, mech_mode, variable, expected, bench def test_is_finished_stops_composition(self): D = DDM(name='DDM', - function=DriftDiffusionIntegrator(threshold=10.0)) + function=DriftDiffusionIntegrator(threshold=10.0, time_step_size=1.0), + execute_until_finished=False, + reset_stateful_function_when=Never()) C = Composition(pathways=[D], reset_stateful_function_when=Never()) C.run(inputs={D: 2.0}, termination_processing={TimeScale.TRIAL: WhenFinished(D)}) @@ -225,13 +232,16 @@ def test_selected_input_array(self): output_ports=[SELECTED_INPUT_ARRAY], name='DDM' ) - action_selection.execute([1.0]) + with pytest.raises(MechanismError) as error: + action_selection.execute([1.0]) + assert 'Length (1) of input ([1.]) does not match required length (2) ' \ + 'for input to InputPort \'ARRAY\' of DDM.' in str(error.value) + action_selection.execute([1.0, 0.0]) # ------------------------------------------------------------------------------------------------ # TEST 2 # function = Bogacz - @pytest.mark.ddm_mechanism @pytest.mark.mechanism @pytest.mark.benchmark @@ -280,8 +290,8 @@ def test_DDM_Integrator_Bogacz(benchmark, mech_mode, prng): @pytest.mark.benchmark(group="DDM") @pytest.mark.parametrize("noise, expected", [ (0., 10), - (0.5, 8.194383551861414), - (2., 6.388767103722829), + (np.sqrt(0.5), 8.194383551861414), + (np.sqrt(2.0), 6.388767103722829), ], ids=["0", "0.5", "2.0"]) def test_DDM_noise(mech_mode, benchmark, noise, expected): T = DDM( @@ -290,7 +300,8 @@ def test_DDM_noise(mech_mode, benchmark, noise, expected): noise=noise, rate=1.0, time_step_size=1.0 - ) + ), + execute_until_finished=False ) ex = pytest.helpers.get_mech_execution(T, mech_mode) @@ -342,6 +353,7 @@ def test_DDM_input(stim): rate=1.0, time_step_size=1.0 ), + execute_until_finished=False, ) val = float(T.execute(stim)[0]) assert val == 10 @@ -367,6 +379,7 @@ def test_DDM_input_list_len_2(): rate=1.0, time_step_size=1.0 ), + execute_until_finished=False, ) float(T.execute(stim)[0]) assert "single numeric item" in str(error_text.value) @@ -382,20 +395,21 @@ def test_DDM_input_list_len_2(): def test_DDM_input_fn(): - with pytest.raises(TypeError) as error_text: + with pytest.raises(MechanismError) as error_text: stim = NormalDist() T = DDM( name='DDM', function=DriftDiffusionIntegrator( - noise=0.0, rate=1.0, time_step_size=1.0 ), + execute_until_finished=False, ) float(T.execute(stim)) - assert "not supported for the input types" in str(error_text.value) - + assert '"Input to \'DDM\' ([(NormalDist Normal Distribution Function' in str(error_text.value) + assert 'is incompatible with its corresponding InputPort (DDM[InputPort-0]): ' \ + '\'unsupported operand type(s) for *: \'NormalDist\' and \'float\'.\'"' in str(error_text.value) # ======================================= RATE TESTS ============================================ @@ -419,6 +433,7 @@ def test_DDM_rate(benchmark, rate, expected, mech_mode): rate=rate, time_step_size=1.0 ), + execute_until_finished=False, ) ex = pytest.helpers.get_mech_execution(T, mech_mode) @@ -452,6 +467,7 @@ def test_DDM_rate_fn(): rate=NormalDist().function, time_step_size=1.0 ), + execute_until_finished=False, ) float(T.execute(stim)[0]) assert "incompatible value" in str(error_text.value) @@ -477,6 +493,7 @@ def test_DDM_size_int_check_var(): rate=-5.0, time_step_size=1.0 ), + execute_until_finished=False, ) assert len(T.defaults.variable) == 1 and T.defaults.variable[0][0] == 0 @@ -494,6 +511,7 @@ def test_DDM_size_int_inputs(): rate=-5.0, time_step_size=1.0 ), + execute_until_finished=False, ) val = T.execute([.4]) decision_variable = val[0][0] @@ -520,6 +538,7 @@ def test_DDM_mech_size_zero(): rate=-5.0, time_step_size=1.0 ), + execute_until_finished=False, ) assert "is not a positive number" in str(error_text.value) @@ -538,6 +557,7 @@ def test_DDM_mech_size_negative_one(): rate=-5.0, time_step_size=1.0 ), + execute_until_finished=False, ) assert "is not a positive number" in str(error_text.value) @@ -556,6 +576,7 @@ def test_DDM_size_too_large(): rate=-5.0, time_step_size=1.0 ), + execute_until_finished=False, ) assert "single numeric item" in str(error_text.value) @@ -574,6 +595,7 @@ def test_DDM_size_too_long(): rate=-5.0, time_step_size=1.0 ), + execute_until_finished=False, ) assert "is greater than 1, implying there are" in str(error_text.value) @@ -586,8 +608,9 @@ def test_DDM_time(): noise=0.0, rate=-5.0, time_step_size=0.2, - starting_point=0.5 - ) + non_decision_time=0.5 + ), + execute_until_finished=False, ) time_0 = D.function.previous_time # t_0 = 0.5 @@ -618,9 +641,11 @@ def test_DDM_in_composition(benchmark, comp_mode): rate=1, noise=0.0, offset=0.0, - starting_point=0.0, + non_decision_time=0.0, time_step_size=0.1, ), + execute_until_finished=False, + reset_stateful_function_when=Never() ) C = pnl.Composition() C.add_linear_processing_pathway([M]) @@ -671,9 +696,18 @@ def test_DDM_threshold_modulation(comp_mode): (100.0, 100.0, (100.0, 76.0)), ]) def test_ddm_is_finished(comp_mode, noise, threshold, expected_results): + + # 3/5/2021 - DDM' default behaviour now requires resetting stateful + # functions after each trial. This is not supported in LLVM execution mode. + # See: https://github.com/PrincetonUniversity/PsyNeuLink/issues/1935 + if comp_mode == pnl.ExecutionMode.LLVM: + pytest.xfail(reason="DDM' default behaviour now requires resetting stateful functions after each trial. " + "This is not supported in LLVM execution mode. " + "See: https://github.com/PrincetonUniversity/PsyNeuLink/issues/1935") + comp = Composition() - ddm = DDM(execute_until_finished=True, - function=DriftDiffusionIntegrator(threshold=threshold, noise=noise)) + ddm = DDM(function=DriftDiffusionIntegrator(threshold=threshold, noise=np.sqrt(noise), time_step_size=1.0), + execute_until_finished=True) comp.add_node(ddm) results = comp.run([0], execution_mode=comp_mode) @@ -687,7 +721,7 @@ def test_sequence_of_DDM_mechs_in_Composition_Pathway(): function=DriftDiffusionAnalytical( drift_rate=(1.0), threshold=(10.0), - starting_point=0.0, + starting_value=0.0, ), name='My_DDM', ) @@ -741,7 +775,18 @@ def test_sequence_of_DDM_mechs_in_Composition_Pathway(): @pytest.mark.mechanism @pytest.mark.ddm_mechanism def test_DDMMechanism_LCA_equivalent(comp_mode): - ddm = DDM(default_variable=[0], function=DriftDiffusionIntegrator(rate=1, time_step_size=0.1)) + + # 3/5/2021 - DDM' default behaviour now requires resetting stateful + # functions after each trial. This is not supported in LLVM execution mode. + # See: https://github.com/PrincetonUniversity/PsyNeuLink/issues/1935 + if comp_mode == pnl.ExecutionMode.LLVM: + pytest.xfail(reason="DDM' default behaviour now requires resetting stateful functions after each trial. " + "This is not supported in LLVM execution mode. " + "See: https://github.com/PrincetonUniversity/PsyNeuLink/issues/1935") + + + ddm = DDM(default_variable=[0], function=DriftDiffusionIntegrator(rate=1, time_step_size=0.1), + execute_until_finished=False) comp2 = Composition() comp2.add_node(ddm) result2 = comp2.run(inputs={ddm:[1]}, execution_mode=comp_mode) diff --git a/tests/mechanisms/test_drift_diffusion_analytical.py b/tests/mechanisms/test_drift_diffusion_analytical.py index 62ec88cdd3d..ececfb8b867 100644 --- a/tests/mechanisms/test_drift_diffusion_analytical.py +++ b/tests/mechanisms/test_drift_diffusion_analytical.py @@ -13,7 +13,7 @@ def check_drift_diffusion_analytical(B, data, degenerate_cases=False): Helper function to check a DriftDiffusionAnalytical Function against a set of data. Format of the data follows the following column ordering: - stim, drift_rate, threshold, starting_point, bias, t0, noise, mean ER, mean RT, + stim, drift_rate, threshold, starting_value, bias, non_decision_time, noise, mean ER, mean RT, correct RT mean, correct RT variance, correct RT skew See gen_matlab_ddm_test_data.py script to generate more test data in this form. This script has since @@ -25,13 +25,13 @@ def check_drift_diffusion_analytical(B, data, degenerate_cases=False): """ NUM_CHECKS = data.shape[0] for i in range(NUM_CHECKS): - r_stim, r_drift_rate, r_threshold, r_starting_point, r_bias, r_t0, r_noise = data[i, 0:7].tolist() + r_stim, r_drift_rate, r_threshold, r_starting_value, r_bias, r_non_decision_time, r_noise = data[i, 0:7].tolist() ground_truth = data[i,7:] B.function.drift_rate.base = r_drift_rate B.function.threshold.base = r_threshold - B.function.starting_point.base = r_starting_point - B.function.t0.base = r_t0 + B.function.starting_value.base = r_starting_value + B.function.non_decision_time.base = r_non_decision_time B.function.noise.base = r_noise results_b = B.execute(r_stim) diff --git a/tests/mechanisms/test_episodic_memory.py b/tests/mechanisms/test_episodic_memory.py index b4d02760546..ab27e385c9a 100644 --- a/tests/mechanisms/test_episodic_memory.py +++ b/tests/mechanisms/test_episodic_memory.py @@ -209,15 +209,12 @@ def test_with_contentaddressablememory(name, func, func_params, mech_params, tes assert em.input_ports.names == input_port_names assert em.output_ports.names == output_port_names - if mech_mode == 'Python': - def EX(variable): - em.execute(variable) - return em.output_values - elif mech_mode == 'LLVM': - pytest.skip("LLVM not yet implemented for ContentAddressableMemory") - elif mech_mode == 'PTX': + if mech_mode != 'Python': pytest.skip("PTX not yet implemented for ContentAddressableMemory") + EX = pytest.helpers.get_mech_execution(em, mech_mode) + + # EX(test_var) actual_output = EX(test_var) for i,j in zip(actual_output,expected_output): diff --git a/tests/mechanisms/test_gating_mechanism.py b/tests/mechanisms/test_gating_mechanism.py index a57dae02a9f..2d1a59a35eb 100644 --- a/tests/mechanisms/test_gating_mechanism.py +++ b/tests/mechanisms/test_gating_mechanism.py @@ -1,15 +1,16 @@ import numpy as np + import psyneulink as pnl import psyneulink.core.components.functions.nonstateful.transferfunctions - -from psyneulink.core.components.functions.stateful.integratorfunctions import AccumulatorIntegrator from psyneulink.core.components.functions.nonstateful.transferfunctions import Logistic +from psyneulink.core.components.functions.stateful.integratorfunctions import AccumulatorIntegrator from psyneulink.core.components.mechanisms.modulatory.control.gating.gatingmechanism import GatingMechanism from psyneulink.core.components.mechanisms.processing.transfermechanism import TransferMechanism from psyneulink.core.components.projections.pathway.mappingprojection import MappingProjection +from psyneulink.core.compositions.composition import Composition from psyneulink.core.globals.keywords import \ DEFAULT_VARIABLE, FUNCTION, FUNCTION_PARAMS, INITIALIZER, RATE, VALUE -from psyneulink.core.compositions.composition import Composition + def test_gating_with_composition(): """Tests same configuration as control of InputPort in tests/mechansims/test_identicalness_of_control_and_gating @@ -131,7 +132,7 @@ def my_sinusoidal_fct( output_ports={ pnl.NAME: 'RESULTS USING UDF', # pnl.VARIABLE: (pnl.OWNER_VALUE, 0), - pnl.FUNCTION: psyneulink.core.components.functions.nonstateful.transferfunctions.Linear(slope=pnl.GATING) + pnl.FUNCTION: psyneulink.core.components.functions.nonstateful.transferfunctions.Linear(slope=pnl.GATE) } ) diff --git a/tests/mechanisms/test_integrator_mechanism.py b/tests/mechanisms/test_integrator_mechanism.py index 65be1bad305..c5e974a4c20 100644 --- a/tests/mechanisms/test_integrator_mechanism.py +++ b/tests/mechanisms/test_integrator_mechanism.py @@ -578,7 +578,7 @@ def test_ornstein_uhlenbeck_integrator_time(self): initializer=10.0, rate=10, time_step_size=0.2, - starting_point=0.5, + non_decision_time=0.5, decay=0.1, offset=10, ) @@ -758,7 +758,7 @@ def test_integrator_type_diffusion_rate_float(self): I = IntegratorMechanism( name='IntegratorMechanism', function=DriftDiffusionIntegrator( - rate=5.0 + rate=5.0, time_step_size=1.0 ) ) # P = Process(pathway=[I]) @@ -1138,7 +1138,8 @@ def test_integrator_drift_diffusion_noise_val(self): I = IntegratorMechanism( name='IntegratorMechanism', function=DriftDiffusionIntegrator( - noise=5.0, + noise=np.sqrt(5.0), + time_step_size=1.0, ), ) diff --git a/tests/mechanisms/test_kwta.py b/tests/mechanisms/test_kwta.py index 15115567376..905e5d33df5 100644 --- a/tests/mechanisms/test_kwta.py +++ b/tests/mechanisms/test_kwta.py @@ -51,13 +51,14 @@ def test_kwta_no_inputs(self): assert(np.allclose(val, [[0.5]])) def test_kwta_inputs_list_of_strings(self): - with pytest.raises(KWTAError) as error_text: + with pytest.raises(MechanismError) as error_text: K = KWTAMechanism( name='K', size = 4, ) K.execute(["one", "two", "three", "four"]) - assert("which is not supported for KWTA" in str(error_text.value)) + assert('"Input to \'K\' ([\'one\' \'two\' \'three\' \'four\']) is incompatible with its corresponding ' + 'InputPort (K[InputPort-0]): \'cannot perform reduce with flexible type.\'"' in str(error_text.value)) def test_kwta_var_list_of_strings(self): with pytest.raises(ParameterError) as error_text: diff --git a/tests/mechanisms/test_mechanisms.py b/tests/mechanisms/test_mechanisms.py index 34569eb6ee9..9714350edfd 100644 --- a/tests/mechanisms/test_mechanisms.py +++ b/tests/mechanisms/test_mechanisms.py @@ -45,7 +45,7 @@ def test_value_shapes(self, mechanism_type, default_variable, mechanism_value, f 'noise', [pnl.GaussianDistort, pnl.NormalDist] ) - def test_noise_variations(self, noise): + def test_noise_assignment_equivalence(self, noise): t1 = pnl.TransferMechanism(name='t1', size=2, noise=noise()) t2 = pnl.TransferMechanism(name='t2', size=2) t2.integrator_function.parameters.noise.set(noise()) @@ -56,6 +56,80 @@ def test_noise_variations(self, noise): for _ in range(5): np.testing.assert_equal(t1.execute([1, 1]), t2.execute([1, 1])) + @pytest.mark.parametrize( + 'noise, included_parameter_ports, excluded_parameter_ports, noise_statefulness', + [ + (0, ['noise'], ['seed'], True), + ([0], ['noise'], ['seed'], True), + ([0, 0], ['noise'], ['seed'], True), + ([0, pnl.NormalDist()], [], ['noise', 'seed'], False), + (pnl.NormalDist, ['seed'], ['noise'], False), + ([pnl.NormalDist(), pnl.NormalDist()], [], ['noise', 'seed'], False), + ] + ) + def test_numeric_noise_specifications( + self, + noise, + included_parameter_ports, + excluded_parameter_ports, + noise_statefulness + ): + try: + size = len(noise) + except TypeError: + size = 1 + + t = pnl.TransferMechanism(size=size, noise=noise) + + assert all(p in t.parameter_ports for p in included_parameter_ports) + assert all(p not in t.parameter_ports for p in excluded_parameter_ports) + + assert t.parameters.noise.stateful is noise_statefulness + + @pytest.mark.parametrize( + 'noise', + [ + [0, pnl.NormalDist()], + pnl.NormalDist, + [pnl.NormalDist(), pnl.NormalDist()] + ] + ) + def test_noise_change_warning_to_numeric(self, noise): + try: + size = len(noise) + except TypeError: + size = 1 + + t = pnl.TransferMechanism(size=size, noise=noise) + + with pytest.warns( + UserWarning, + match='Setting noise to a numeric value after instantiation.*' + ): + t.parameters.noise.set(0) + + @pytest.mark.parametrize( + 'noise', + [ + 0, + [0], + [0, 0], + ] + ) + def test_noise_change_warning_to_function(self, noise): + try: + size = len(noise) + except TypeError: + size = 1 + + t = pnl.TransferMechanism(size=size, noise=noise) + + with pytest.warns( + UserWarning, + match='Setting noise to a value containing functions after instantiation.*' + ): + t.parameters.noise.set(pnl.NormalDist) + class TestMechanismFunctionParameters: f = pnl.Linear() @@ -155,7 +229,7 @@ def test_function_parameter_assignment(self, param_name, function): class TestResetValues: def test_reset_state_integrator_mechanism(self): - A = pnl.IntegratorMechanism(name='A', function=pnl.DriftDiffusionIntegrator()) + A = pnl.IntegratorMechanism(name='A', function=pnl.DriftDiffusionIntegrator(time_step_size=1.0)) # Execute A twice # [0] saves decision variable only (not time) diff --git a/tests/mechanisms/test_processing_mechanism.py b/tests/mechanisms/test_processing_mechanism.py index 7741cc0a102..ced6f68ae8a 100644 --- a/tests/mechanisms/test_processing_mechanism.py +++ b/tests/mechanisms/test_processing_mechanism.py @@ -66,7 +66,7 @@ def test_processing_mechanism_linear_function(self): (SoftMax, [[1,]]), (SimpleIntegrator, [[1.]]), (AdaptiveIntegrator, [[1.]]), - (DriftDiffusionIntegrator, [[[1.]], [[1.]]]), + (DriftDiffusionIntegrator(time_step_size=1.0), [[[1.]], [[1.]]]), (OrnsteinUhlenbeckIntegrator, [[[-1.]], [[1.]]]), (AccumulatorIntegrator, [[0.]]), (FitzHughNagumoIntegrator, [[[0.05127053]], [[0.00279552]], [[0.05]]]), @@ -246,6 +246,8 @@ class TestProcessingMechanismStandardOutputPorts: @pytest.mark.parametrize("op, expected", [(MAX_ONE_HOT, [0, 2, 0]), (MAX_INDICATOR, [0, 1, 0]), (MAX_ABS_INDICATOR, [0, 0, 1]), + (MAX_ABS_ONE_HOT, [0, 0, 4]), + (MAX_VAL, [2]), ], ids=lambda x: x if isinstance(x, str) else "") def test_output_ports(self, mech_mode, op, expected, benchmark): @@ -262,9 +264,7 @@ def test_output_ports(self, mech_mode, op, expected, benchmark): (MEDIAN, [2]), (STANDARD_DEVIATION, [1.24721913]), (VARIANCE, [1.55555556]), - (MAX_VAL, [2]), (MAX_ABS_VAL, [4]), - (MAX_ABS_ONE_HOT, [0, 0, 4]), (PROB, [0, 2, 0]), ], ids=lambda x: x if isinstance(x, str) else "") diff --git a/tests/mechanisms/test_recurrent_transfer_mechanism.py b/tests/mechanisms/test_recurrent_transfer_mechanism.py index 2a24df650c0..6fc87408ffb 100644 --- a/tests/mechanisms/test_recurrent_transfer_mechanism.py +++ b/tests/mechanisms/test_recurrent_transfer_mechanism.py @@ -206,14 +206,16 @@ def test_recurrent_mech_no_inputs(self, benchmark, mech_mode): benchmark(EX, [1]) def test_recurrent_mech_inputs_list_of_strings(self): - with pytest.raises(FunctionError) as error_text: + with pytest.raises(MechanismError) as error_text: R = RecurrentTransferMechanism( name='R', default_variable=[0, 0, 0, 0], integrator_mode=True ) R.execute(["one", "two", "three", "four"]) - assert "Unrecognized type" in str(error_text.value) + assert '"Input to \'R\' ([\'one\' \'two\' \'three\' \'four\']) is incompatible ' \ + 'with its corresponding InputPort (R[InputPort-0]): ' \ + '\'cannot perform reduce with flexible type.\'"' in str(error_text.value) def test_recurrent_mech_var_list_of_strings(self): with pytest.raises(ParameterError) as error_text: diff --git a/tests/mechanisms/test_transfer_mechanism.py b/tests/mechanisms/test_transfer_mechanism.py index ac528e7fdd0..e6a295ce05a 100644 --- a/tests/mechanisms/test_transfer_mechanism.py +++ b/tests/mechanisms/test_transfer_mechanism.py @@ -101,14 +101,16 @@ def test_transfer_mech_variable_none_size_none(self): @pytest.mark.mechanism @pytest.mark.transfer_mechanism def test_transfer_mech_inputs_list_of_strings(self): - with pytest.raises(FunctionError) as error_text: + with pytest.raises(MechanismError) as error_text: T = TransferMechanism( name='T', default_variable=[0, 0, 0, 0], integrator_mode=True ) T.execute(["one", "two", "three", "four"]) - assert "Unrecognized type" in str(error_text.value) + assert '"Input to \'T\' ([\'one\' \'two\' \'three\' \'four\']) is incompatible ' \ + 'with its corresponding InputPort (T[InputPort-0]): ' \ + '\'cannot perform reduce with flexible type.\'"' in str(error_text.value) @pytest.mark.mechanism @pytest.mark.transfer_mechanism @@ -965,12 +967,7 @@ def test_transfer_mech_integration_rate_0_8_initial_0_5(self, mech_mode): T.noise.base = 10 - if mech_mode == 'Python': - val = T.execute([1, 2, -3, 0]) - elif mech_mode == 'LLVM': - val = e.execute([1, 2, -3, 0]) - elif mech_mode == 'PTX': - val = e.cuda_execute([1, 2, -3, 0]) + val = EX([1, 2, -3, 0]) assert np.allclose(val, [[10.98, 11.78, 7.779999999999999, 10.18]]) # testing noise changes to an integrator # @pytest.mark.mechanism @@ -991,17 +988,19 @@ def test_transfer_mech_integration_rate_0_8_initial_0_5(self, mech_mode): # ) @pytest.mark.mechanism @pytest.mark.transfer_mechanism - def test_transfer_mech_integration_rate_0_8_list(self): + def test_transfer_mech_integration_rate_0_8_list(self, mech_mode): T = TransferMechanism( name='T', default_variable=[0, 0, 0, 0], function=Linear(), - integration_rate=[0.8, 0.8, 0.8, 0.8], + integration_rate=[0.8, 0.7, 0.6, 0.5], integrator_mode=True ) - T.execute([1, 1, 1, 1]) - val = T.execute([1, 1, 1, 1]) - assert np.allclose(val, [[ 0.96, 0.96, 0.96, 0.96]]) + EX = pytest.helpers.get_mech_execution(T, mech_mode) + + EX([1, 1, 1, 1]) + val = EX([1, 1, 1, 1]) + assert np.allclose(val, [[ 0.96, 0.91, 0.84, 0.75]]) @pytest.mark.mechanism diff --git a/tests/models/test_greedy_agent.py b/tests/models/test_greedy_agent.py index 8a75534e408..676150e3e1d 100644 --- a/tests/models/test_greedy_agent.py +++ b/tests/models/test_greedy_agent.py @@ -192,7 +192,8 @@ def action_fn(variable): agent_comp.exclude_node_roles(direct_move, NodeRole.OUTPUT) - ocm = OptimizationControlMechanism(state_features={SHADOW_INPUTS: [player_pos, predator_pos, prey_pos]}, + ocm = OptimizationControlMechanism(state_features=[player_pos, prey_pos, predator_pos], + # ocm = OptimizationControlMechanism(state_features={SHADOW_INPUTS: [player_pos, prey_pos, predator_pos]}, agent_rep=agent_comp, function=GridSearch(direction=MINIMIZE, save_values=True), diff --git a/tests/naming/test_naming.py b/tests/naming/test_naming.py index fb44f6bc44b..adb655c8ba0 100644 --- a/tests/naming/test_naming.py +++ b/tests/naming/test_naming.py @@ -154,8 +154,9 @@ def test_input_port_and_assigned_projection_names(self): # ------------------------------------------------------------------------------------------------ # TEST 11 # Test that ControlSignals and ControlProjections are properly named - - def test_control_signal_and_control_projection_names(self): + @pytest.mark.control + @pytest.mark.parametrize('control_spec', [pnl.CONTROL, pnl.PROJECTIONS]) + def test_control_signal_and_control_projection_names(self, control_spec): D1 = pnl.DDM(name='D1') D2 = pnl.DDM(name='D2') @@ -166,16 +167,16 @@ def test_control_signal_and_control_projection_names(self): assert C1.control_signals[0].efferents[0].name == 'ControlProjection for D1[drift_rate]' # ControlSignal with two ControlProjection to two parameters of same Mechanism - C2 = pnl.ControlMechanism(control_signals=[{pnl.PROJECTIONS:[D1.parameter_ports[ - psyneulink.core.components.functions.nonstateful.distributionfunctions.DRIFT_RATE], - D1.parameter_ports[ - psyneulink.core.globals.keywords.THRESHOLD]]}]) + C2 = pnl.ControlMechanism(control_signals=[{control_spec:[D1.parameter_ports[ + psyneulink.core.components.functions.nonstateful.distributionfunctions.DRIFT_RATE], + D1.parameter_ports[ + psyneulink.core.globals.keywords.THRESHOLD]]}]) assert C2.control_signals[0].name == 'D1[drift_rate, threshold] ControlSignal' assert C2.control_signals[0].efferents[0].name == 'ControlProjection for D1[drift_rate]' assert C2.control_signals[0].efferents[1].name == 'ControlProjection for D1[threshold]' # ControlSignal with two ControlProjection to two parameters of different Mechanisms - C3 = pnl.ControlMechanism(control_signals=[{pnl.PROJECTIONS:[D1.parameter_ports[ + C3 = pnl.ControlMechanism(control_signals=[{control_spec:[D1.parameter_ports[ psyneulink.core.components.functions.nonstateful.distributionfunctions.DRIFT_RATE], D2.parameter_ports[ psyneulink.core.components.functions.nonstateful.distributionfunctions.DRIFT_RATE]]}]) @@ -187,6 +188,7 @@ def test_control_signal_and_control_projection_names(self): # TEST 12 # Test that GatingSignals and GatingProjections are properly named + @pytest.mark.control def test_gating_signal_and_gating_projection_names(self): T3 = pnl.TransferMechanism(name='T3') T4 = pnl.TransferMechanism(name='T4', input_ports=['First Port','Second Port']) diff --git a/tests/ports/test_input_ports.py b/tests/ports/test_input_ports.py index 242bc62f62d..a2c1d807a71 100644 --- a/tests/ports/test_input_ports.py +++ b/tests/ports/test_input_ports.py @@ -1,7 +1,7 @@ import numpy as np -import psyneulink as pnl import pytest +import psyneulink as pnl import psyneulink.core.components.functions.nonstateful.combinationfunctions import psyneulink.core.components.functions.nonstateful.transferfunctions @@ -96,3 +96,43 @@ def test_internal_only(self): m = pnl.TransferMechanism(input_ports=['EXTERNAL', pnl.InputPort(name='INTERNAL_ONLY', internal_only=True)]) assert m.input_values == [[ 0.],[ 0.]] assert m.external_input_values == [[0.]] + + @pytest.mark.parametrize('default_input', [None, pnl.DEFAULT_VARIABLE]) + def test_default_input(self, default_input): + variable = [22] + m = pnl.TransferMechanism(input_ports=[pnl.InputPort(name='INTERNAL_NODE', + default_input=default_input, + variable=variable)]) + m.execute() + assert m.input_port.value == variable + if default_input: + assert m.input_port.internal_only is True + else: + assert m.input_port.internal_only is False + comp = pnl.Composition(nodes=(m, pnl.NodeRole.INTERNAL)) + assert pnl.NodeRole.INTERNAL in comp.get_roles_by_node(m) + assert pnl.NodeRole.INPUT not in comp.get_roles_by_node(m) + assert not m.path_afferents + if default_input is None: + with pytest.warns(UserWarning) as warning: # Warn, since default_input is NOT set + comp.run() + assert repr(warning[1].message.args[0]) == '"InputPort (\'INTERNAL_NODE\') of \'TransferMechanism-0\' ' \ + 'doesn\'t have any afferent Projections."' + assert m.input_port.value == variable # For Mechanisms other than controller, default_variable seems + assert m.value == variable # to still be used even though default_input is NOT set + else: + assert not m.path_afferents # No path_afferents since internal_only is set by default_input + comp.run() # No warning since default_input is set + assert m.input_port.value == variable + assert m.value == variable + + def test_no_efferents(self): + A = pnl.InputPort() + with pytest.raises(pnl.PortError) as error: + A.efferents + assert '"InputPorts do not have \'efferents\'; (access attempted for Deferred Init InputPort)."' \ + in str(error.value) + with pytest.raises(pnl.PortError) as error: + A.efferents = ['test'] + assert '"InputPorts are not allowed to have \'efferents\' ' \ + '(assignment attempted for Deferred Init InputPort)."' in str(error.value) diff --git a/tests/ports/test_output_ports.py b/tests/ports/test_output_ports.py index 74774381862..71761b860f4 100644 --- a/tests/ports/test_output_ports.py +++ b/tests/ports/test_output_ports.py @@ -7,7 +7,6 @@ class TestOutputPorts: @pytest.mark.mechanism - @pytest.mark.lca_mechanism def test_output_port_variable_spec(self, mech_mode): # Test specification of OutputPort's variable mech = pnl.ProcessingMechanism(default_variable=[[1.],[2.],[3.]], @@ -33,25 +32,47 @@ def test_output_port_variable_spec(self, mech_mode): assert np.array_equal(i, e) @pytest.mark.mechanism - @pytest.mark.lca_mechanism - def test_output_port_variable_spec_composition(self, comp_mode): + @pytest.mark.parametrize('spec, expected1, expected2', + [((pnl.OWNER_VALUE, 0), [1], [1]), + ((pnl.OWNER_VALUE, 1), [2], [2]), + ((pnl.OWNER_VALUE, 2), [3], [3]), + pytest.param((pnl.OWNER_VALUE, 3), [3], [3], marks=[pytest.mark.xfail()]), + ((pnl.OWNER_EXECUTION_COUNT), [4], [8]), + (("num_executions", pnl.TimeScale.LIFE), [4], [8]), + (("num_executions", pnl.TimeScale.RUN), [4], [4]), + (("num_executions", pnl.TimeScale.TRIAL), [2], [2]), + (("num_executions", pnl.TimeScale.PASS), [1], [1]), + (("num_executions", pnl.TimeScale.TIME_STEP), [1], [1]), + ], ids=lambda x: str(x) if len(x) != 1 else '') + @pytest.mark.usefixtures("comp_mode_no_llvm") + def tests_output_port_variable_spec_composition(self, comp_mode, spec, expected1, expected2): + if (len(spec) == 2) and (spec[1] == pnl.TimeScale.RUN) and \ + ((comp_mode & pnl.ExecutionMode._Exec) == pnl.ExecutionMode._Exec): + pytest.skip("{} is not supported in {}".format(spec[1], comp_mode)) + # Test specification of OutputPort's variable # OutputPort mech.output_ports['all'] has a different dimensionality than the other OutputPorts; # as a consequence, when added as a terminal node, the Composition can't construct an IDENTITY_MATRIX # from the mech's OutputPorts to the Composition's output_CIM. # FIX: Remove the following line and correct assertions below once above condition is resolved - mech = pnl.ProcessingMechanism(default_variable=[[1.],[2.],[3.]], - name='MyMech', - output_ports=[ - pnl.OutputPort(name='z', variable=(pnl.OWNER_VALUE, 2)), - pnl.OutputPort(name='y', variable=(pnl.OWNER_VALUE, 1)), - pnl.OutputPort(name='x', variable=(pnl.OWNER_VALUE, 0)), -# pnl.OutputPort(name='all', variable=(pnl.OWNER_VALUE)), - pnl.OutputPort(name='execution count', variable=(pnl.OWNER_EXECUTION_COUNT)) - ]) + var = [[1], [2], [3]] + mech = pnl.ProcessingMechanism(default_variable=var, name='MyMech', + output_ports=[pnl.OutputPort(variable=spec)]) C = pnl.Composition(name='MyComp') C.add_node(node=mech) - outs = C.run(inputs={mech: [[1.],[2.],[3.]]}, execution_mode=comp_mode) - assert np.array_equal(outs, [[3], [2], [1], [1]]) - outs = C.run(inputs={mech: [[1.],[2.],[3.]]}, execution_mode=comp_mode) - assert np.array_equal(outs, [[3], [2], [1], [2]]) + C.termination_processing[pnl.TimeScale.TRIAL] = pnl.AtPass(2) + outs = C.run(inputs={mech: var}, num_trials=2, execution_mode=comp_mode) + assert np.allclose(outs, expected1) + outs = C.run(inputs={mech: var}, num_trials=2, execution_mode=comp_mode) + assert np.allclose(outs, expected2) + + def test_no_path_afferents(self): + A = pnl.OutputPort() + with pytest.raises(pnl.PortError) as error: + A.path_afferents + assert '"OutputPorts do not have \'path_afferents\'; (access attempted for Deferred Init OutputPort)."' \ + in str(error.value) + with pytest.raises(pnl.PortError) as error: + A.path_afferents = ['test'] + assert '"OutputPorts are not allowed to have \'path_afferents\' ' \ + '(assignment attempted for Deferred Init OutputPort)."' in str(error.value) diff --git a/tests/ports/test_parameter_ports.py b/tests/ports/test_parameter_ports.py index f294cfd003c..aca2979ae32 100644 --- a/tests/ports/test_parameter_ports.py +++ b/tests/ports/test_parameter_ports.py @@ -70,6 +70,28 @@ def test_direct_call_to_constructor_error(self): ParameterPort(owner='SOMETHING') assert "Contructor for ParameterPort cannot be called directly(context: None" in str(error_text.value) + def test_no_path_afferents(self): + A = TransferMechanism() + with pytest.raises(pnl.PortError) as error: + A.parameter_ports['slope'].path_afferents + assert '"ParameterPorts do not have \'path_afferents\'; (access attempted for TransferMechanism-0[slope])."' \ + in str(error.value) + with pytest.raises(pnl.PortError) as error: + A.parameter_ports['slope'].path_afferents = ['test'] + assert '"ParameterPorts are not allowed to have \'path_afferents\' ' \ + '(assignment attempted for TransferMechanism-0[slope])."' in str(error.value) + + def test_no_efferents(self): + A = TransferMechanism() + with pytest.raises(pnl.PortError) as error: + A.parameter_ports['slope'].efferents + assert '"ParameterPorts do not have \'efferents\'; (access attempted for TransferMechanism-0[slope])."' \ + in str(error.value) + with pytest.raises(pnl.PortError) as error: + A.parameter_ports['slope'].efferents = ['test'] + assert '"ParameterPorts are not allowed to have \'efferents\' ' \ + '(assignment attempted for TransferMechanism-0[slope])."' in str(error.value) + class TestConfigurableParameters: def test_configurable_params(self): old_value = 0.2 @@ -137,6 +159,7 @@ def test_configurable_params(self): assert np.allclose(T.noise.base, new_value) assert np.allclose(T.noise.modulated, new_value) + class TestModParams: def test_mod_param_error(self): T = TransferMechanism() diff --git a/tests/projections/test_projection_specifications.py b/tests/projections/test_projection_specifications.py index bd3dd78fb7b..52358f04f52 100644 --- a/tests/projections/test_projection_specifications.py +++ b/tests/projections/test_projection_specifications.py @@ -1,16 +1,17 @@ -import psyneulink as pnl import numpy as np import pytest +import psyneulink as pnl import psyneulink.core.components.functions.nonstateful.distributionfunctions -import psyneulink.core.components.functions.stateful.integratorfunctions import psyneulink.core.components.functions.nonstateful.transferfunctions +import psyneulink.core.components.functions.stateful.integratorfunctions + class TestProjectionSpecificationFormats: def test_projection_specification_formats(self): """Test various matrix and Projection specifications - Also tests assignment of Projections to pathay of Composition using add_linear_processing_pathway: + Also tests assignment of Projections to pathway of Composition using add_linear_processing_pathway: - Projection explicitly specified in sequence (M1_M2_proj) - Projection pre-constructed and assigned to Mechanisms, but not specified in pathway(M2_M3_proj) - Projection specified in pathway that is duplicate one preconstructed and assigned to Mechanisms (M3_M4_proj) @@ -52,26 +53,118 @@ def test_projection_specification_formats(self): # assert np.allclose(c.results, [[-130.19166667, -152.53333333, -174.875]]) assert np.allclose(c.results, [[ -78.115, -91.52 , -104.925]]) - def test_multiple_modulatory_projection_specs(self): + @pytest.mark.parametrize('args', [ + (pnl.CONTROL, None), + (pnl.MODULATES, None), + (pnl.PROJECTIONS, None), + ('mod and ctl', '"Both \'control\' and \'modulates\' arguments are specified in ' + 'the constructor for \'ControlSignal; Should use just \'control\'."'), + ('proj and ctl', 'Both \'control\' and \'projections\' arguments are specified in the constructor for ' + '\'ControlSignal; Must use just one or the other.'), + ('proj and mod','"Both \'modulates\' and \'projections\' arguments are specified in the constructor for ' + '\'ControlSignal; Should use just \'projections\' (or \'control\') "') + ]) + @pytest.mark.control + def test_control_signal_projections_arg(self, args): + M = pnl.ProcessingMechanism() + control_specs = {pnl.CONTROL: {'control':(pnl.SLOPE, M)}, + pnl.MODULATES: {pnl.MODULATES:(pnl.SLOPE, M)}, + pnl.PROJECTIONS: {pnl.PROJECTIONS:(pnl.SLOPE, M)}, + 'mod and ctl': {'control':(pnl.SLOPE, M), + pnl.MODULATES:(pnl.SLOPE, M)}, + 'proj and ctl': {'control':(pnl.SLOPE, M), + pnl.PROJECTIONS:(pnl.SLOPE, M)}, + 'proj and mod': {pnl.MODULATES:(pnl.SLOPE, M), + pnl.PROJECTIONS:(pnl.SLOPE, M)} + } + if args[0] in {'mod and ctl', 'proj and ctl', 'proj and mod'}: + from psyneulink.core.components.ports.modulatorysignals.controlsignal import ControlSignalError + with pytest.raises(ControlSignalError) as err: + pnl.ControlSignal(**control_specs[args[0]]) + assert args[1] in str(err.value) + else: + ctl_sig = pnl.ControlSignal(**control_specs[args[0]]) + assert ctl_sig._init_args[pnl.PROJECTIONS][0][0] == pnl.SLOPE + assert ctl_sig._init_args[pnl.PROJECTIONS][0][1] is M + + @pytest.mark.parametrize('args', [ + (pnl.GATE, None), + (pnl.MODULATES, None), + (pnl.PROJECTIONS, None), + ('mod and gate', '"Both \'gate\' and \'modulates\' arguments are specified in the constructor for ' + '\'GatingSignal; Should use just \'gate\'."'), + ('proj and gate', 'Both \'gate\' and \'projections\' arguments are specified in the constructor for ' + '\'GatingSignal; Must use just one or the other.'), + ('proj and mod','"Both \'modulates\' and \'projections\' arguments are specified in the constructor for ' + '\'GatingSignal; Should use just \'projections\' (or \'gate\') "') + ]) + @pytest.mark.control + def test_gating_signal_projections_arg(self, args): + M = pnl.ProcessingMechanism() + gating_specs = {pnl.GATE: {'gate':(pnl.SLOPE, M)}, + pnl.MODULATES: {pnl.MODULATES:(pnl.SLOPE, M)}, + pnl.PROJECTIONS: {pnl.PROJECTIONS:(pnl.SLOPE, M)}, + 'mod and gate': {'gate':(pnl.SLOPE, M), + pnl.MODULATES:(pnl.SLOPE, M)}, + 'proj and gate': {'gate':(pnl.SLOPE, M), + pnl.PROJECTIONS:(pnl.SLOPE, M)}, + 'proj and mod': {pnl.MODULATES:(pnl.SLOPE, M), + pnl.PROJECTIONS:(pnl.SLOPE, M)} + } + if args[0] in {'mod and gate', 'proj and gate', 'proj and mod'}: + from psyneulink.core.components.ports.modulatorysignals.gatingsignal import GatingSignalError + with pytest.raises(GatingSignalError) as err: + pnl.GatingSignal(**gating_specs[args[0]]) + assert args[1] in str(err.value) + else: + gating_sig = pnl.GatingSignal(**gating_specs[args[0]]) + assert gating_sig._init_args[pnl.PROJECTIONS][0][0] == pnl.SLOPE + assert gating_sig._init_args[pnl.PROJECTIONS][0][1] is M + + @pytest.mark.parametrize("control_spec, gating_spec, extra_spec", + [ + [pnl.CONTROL, pnl.GATE, ''], + [pnl.PROJECTIONS, pnl.PROJECTIONS, ''], + [pnl.CONTROL, pnl.GATE, pnl.PROJECTIONS] + ] + ) + @pytest.mark.control + def test_multiple_modulatory_projection_specs(self, control_spec, gating_spec, extra_spec): M = pnl.DDM(name='MY DDM') - C = pnl.ControlMechanism(control_signals=[{pnl.PROJECTIONS: [M.parameter_ports[ - psyneulink.core.components.functions.nonstateful.distributionfunctions.DRIFT_RATE], - M.parameter_ports[ - psyneulink.core.globals.keywords.THRESHOLD]]}]) - G = pnl.GatingMechanism(gating_signals=[{pnl.PROJECTIONS: [M.output_ports[pnl.DECISION_VARIABLE], - M.output_ports[pnl.RESPONSE_TIME]]}]) - assert len(C.control_signals)==1 - assert len(C.control_signals[0].efferents)==2 - assert M.parameter_ports[ - psyneulink.core.components.functions.nonstateful.distributionfunctions.DRIFT_RATE].mod_afferents[0] == C.control_signals[0].efferents[0] - assert M.parameter_ports[ - psyneulink.core.globals.keywords.THRESHOLD].mod_afferents[0] == C.control_signals[0].efferents[1] - assert len(G.gating_signals)==1 - assert len(G.gating_signals[0].efferents)==2 - assert M.output_ports[pnl.DECISION_VARIABLE].mod_afferents[0]==G.gating_signals[0].efferents[0] - assert M.output_ports[pnl.RESPONSE_TIME].mod_afferents[0]==G.gating_signals[0].efferents[1] - + ctl_sig_spec = {control_spec: [M.parameter_ports[pnl.DRIFT_RATE], + M.parameter_ports[pnl.THRESHOLD]]} + gating_sig_spec = {gating_spec: [M.output_ports[pnl.DECISION_VARIABLE], + M.output_ports[pnl.RESPONSE_TIME]]} + if extra_spec: + ctl_sig_spec.update({extra_spec:[M.parameter_ports[pnl.STARTING_VALUE]]}) + gating_sig_spec.update({extra_spec:[M.output_ports[pnl.RESPONSE_TIME]]}) + ctl_err_msg = '"Both \'PROJECTIONS\' and \'CONTROL\' entries found in specification dict for ' \ + '\'ControlSignal\' of \'ControlMechanism-0\'. Must use only one or the other."' + with pytest.raises(pnl.ControlSignalError) as err: + pnl.ControlMechanism(control_signals=[ctl_sig_spec]) + assert ctl_err_msg == str(err.value) + gating_err_msg = '"Both \'PROJECTIONS\' and \'GATE\' entries found in specification dict for ' \ + '\'GatingSignal\' of \'GatingMechanism-0\'. Must use only one or the other."' + with pytest.raises(pnl.GatingSignalError) as err: + pnl.GatingMechanism(gating_signals=[gating_sig_spec]) + assert gating_err_msg == str(err.value) + else: + # G = pnl.GatingMechanism(gating_signals=[gating_sig_spec]) + C = pnl.ControlMechanism(control_signals=[ctl_sig_spec]) + G = pnl.GatingMechanism(gating_signals=[gating_sig_spec]) + assert len(C.control_signals)==1 + assert len(C.control_signals[0].efferents)==2 + assert M.parameter_ports[ + psyneulink.core.components.functions.nonstateful.distributionfunctions.DRIFT_RATE].mod_afferents[0] == C.control_signals[0].efferents[0] + assert M.parameter_ports[ + psyneulink.core.globals.keywords.THRESHOLD].mod_afferents[0] == C.control_signals[0].efferents[1] + assert len(G.gating_signals)==1 + assert len(G.gating_signals[0].efferents)==2 + assert M.output_ports[pnl.DECISION_VARIABLE].mod_afferents[0]==G.gating_signals[0].efferents[0] + assert M.output_ports[pnl.RESPONSE_TIME].mod_afferents[0]==G.gating_signals[0].efferents[1] + + @pytest.mark.control def test_multiple_modulatory_projections_with_port_Name(self): M = pnl.DDM(name='MY DDM') @@ -94,6 +187,7 @@ def test_multiple_modulatory_projections_with_port_Name(self): assert M.output_ports[pnl.DECISION_VARIABLE].mod_afferents[0]==G.gating_signals[0].efferents[0] assert M.output_ports[pnl.RESPONSE_TIME].mod_afferents[0]==G.gating_signals[0].efferents[1] + @pytest.mark.control def test_multiple_modulatory_projections_with_mech_and_port_Name_specs(self): M = pnl.DDM(name='MY DDM') @@ -179,6 +273,7 @@ def test_2_item_tuple_from_control_signal_to_parameter_port(self): assert C.control_signals[0].efferents[0].receiver.name == 'drift_rate' assert C.control_signals[0].efferents[1].receiver.name == 'threshold' + @pytest.mark.control def test_2_item_tuple_from_parameter_port_to_control_signals(self): C = pnl.ControlMechanism(control_signals=['a','b']) @@ -191,6 +286,7 @@ def test_2_item_tuple_from_parameter_port_to_control_signals(self): assert D.parameter_ports[ psyneulink.core.globals.keywords.THRESHOLD].mod_afferents[0].sender == C.control_signals[1] + @pytest.mark.control def test_2_item_tuple_from_gating_signal_to_output_ports(self): D4 = pnl.DDM(name='D4') @@ -206,6 +302,7 @@ def test_2_item_tuple_from_gating_signal_to_output_ports(self): assert G.gating_signals[0].efferents[0].receiver.name == 'DECISION_VARIABLE' assert G.gating_signals[0].efferents[1].receiver.name == 'RESPONSE_TIME' + @pytest.mark.control def test_2_item_tuple_from_input_and_output_ports_to_gating_signals(self): G = pnl.GatingMechanism(gating_signals=['a','b']) @@ -243,6 +340,7 @@ def test_2_item_tuple_from_input_and_output_ports_to_gating_signals(self): 'noise, gain', [(noise, gain) for noise, gain in [j for j in zip(control_spec_list, reversed(control_spec_list))]] ) + @pytest.mark.control def test_formats_for_control_specification_for_mechanism_and_function_params(self, noise, gain): # This shenanigans is to avoid assigning the same instantiated ControlProjection more than once if noise == 'CP_OBJECT': @@ -267,7 +365,7 @@ def test_formats_for_control_specification_for_mechanism_and_function_params(sel 'ControlProjection for R-CONTROL[gain]' gating_spec_list = [ - pnl.GATING, + pnl.GATE, pnl.CONTROL, pnl.GATING_SIGNAL, pnl.CONTROL_SIGNAL, @@ -283,7 +381,7 @@ def test_formats_for_control_specification_for_mechanism_and_function_params(sel pnl.ControlMechanism, pnl.GatingMechanism(), pnl.ControlMechanism(), - (0.3, pnl.GATING), + (0.3, pnl.GATE), (0.3, pnl.CONTROL), (0.3, pnl.GATING_SIGNAL), (0.3, pnl.CONTROL_SIGNAL), @@ -306,6 +404,7 @@ def test_formats_for_control_specification_for_mechanism_and_function_params(sel 'input_port, output_port', [(inp, outp) for inp, outp in [j for j in zip(gating_spec_list, reversed(gating_spec_list))]] ) + @pytest.mark.control def test_formats_for_gating_specification_of_input_and_output_ports(self, input_port, output_port): G_IN, G_OUT = input_port, output_port @@ -323,12 +422,14 @@ def test_formats_for_gating_specification_of_input_and_output_ports(self, input_ IN_NAME = G_IN[1] else: IN_NAME = G_IN - IN_CONTROL = pnl.CONTROL in repr(IN_NAME).split(".")[-1].upper() + # IN_CONTROL = pnl.CONTROL in repr(IN_NAME).split(".")[-1].upper() + IN_CONTROL = 'CONTROL' in repr(IN_NAME).split(".")[-1].upper() if isinstance(G_OUT, tuple): OUT_NAME = G_OUT[1] else: OUT_NAME = G_OUT - OUT_CONTROL = pnl.CONTROL in repr(OUT_NAME).split(".")[-1].upper() + # OUT_CONTROL = pnl.CONTROL in repr(OUT_NAME).split(".")[-1].upper() + OUT_CONTROL = 'CONTROL' in repr(OUT_NAME).split(".")[-1].upper() T = pnl.TransferMechanism( name='T-GATING', diff --git a/tests/scheduling/test_condition.py b/tests/scheduling/test_condition.py index 9933f601b4a..f9684059100 100644 --- a/tests/scheduling/test_condition.py +++ b/tests/scheduling/test_condition.py @@ -1,5 +1,7 @@ import logging +import numpy as np +import psyneulink as pnl import pytest from psyneulink import _unit_registry from psyneulink.core.components.functions.nonstateful.transferfunctions import Linear @@ -690,6 +692,104 @@ def test_AllHaveRun_2(self): ] assert output == pytest.helpers.setify_expected_output(expected_output) + @pytest.mark.parametrize( + 'parameter, indices, default_variable, integration_rate, expected_results', + [ + ('value', None, None, 1, [[[10]]]), + ('value', (0, 0), [[0, 0]], [1, 2], [[[10, 20]]]), + ('value', (0, 1), [[0, 0]], [1, 2], [[[5, 10]]]), + ('num_executions', TimeScale.TRIAL, None, 1, [[[10]]]), + ('execution_count', None, None, 1, [[[10]]]), + ] + ) + @pytest.mark.parametrize('threshold', [10, 10.0]) + @pytest.mark.usefixtures("comp_mode_no_llvm") + def test_Threshold_parameters( + self, parameter, indices, default_variable, integration_rate, expected_results, threshold, comp_mode + ): + A = TransferMechanism( + default_variable=default_variable, + integrator_mode=True, + integrator_function=pnl.SimpleIntegrator, + integration_rate=integration_rate, + ) + comp = Composition(pathways=[A]) + + comp.termination_processing = { + pnl.TimeScale.TRIAL: pnl.Threshold(A, parameter, threshold, '>=', indices=indices) + } + + comp.run(inputs={A: np.ones(A.defaults.variable.shape)}, execution_mode=comp_mode) + + np.testing.assert_array_equal(comp.results, expected_results) + + @pytest.mark.parametrize( + 'comparator, increment, threshold, expected_results', + [ + ('>', 1, 5, [[[6]]]), + ('>=', 1, 5, [[[5]]]), + ('<', -1, -5, [[[-6]]]), + ('<=', -1, -5, [[[-5]]]), + ('==', 1, 5, [[[5]]]), + ('!=', 1, 0, [[[1]]]), + ('!=', -1, 0, [[[-1]]]), + ] + ) + def test_Threshold_comparators( + self, comparator, increment, threshold, expected_results, comp_mode + ): + if comp_mode is pnl.ExecutionMode.LLVM: + pytest.skip('ExecutionMode.LLVM does not support Parameter access in conditions') + + A = TransferMechanism( + integrator_mode=True, + integrator_function=pnl.AccumulatorIntegrator(rate=1, increment=increment), + ) + comp = Composition(pathways=[A]) + + comp.termination_processing = { + pnl.TimeScale.TRIAL: pnl.Threshold(A, 'value', threshold, comparator) + } + + comp.run(inputs={A: np.ones(A.defaults.variable.shape)}, execution_mode=comp_mode) + + np.testing.assert_array_equal(comp.results, expected_results) + + @pytest.mark.parametrize( + 'comparator, increment, threshold, atol, rtol, expected_results', + [ + ('==', 1, 10, 1, 0.1, [[[8]]]), + ('==', 1, 10, 1, 0, [[[9]]]), + ('==', 1, 10, 0, 0.1, [[[9]]]), + ('!=', 1, 2, 1, 0.5, [[[5]]]), + ('!=', 1, 1, 1, 0, [[[3]]]), + ('!=', 1, 1, 0, 1, [[[3]]]), + ('!=', -1, -2, 1, 0.5, [[[-5]]]), + ('!=', -1, -1, 1, 0, [[[-3]]]), + ('!=', -1, -1, 0, 1, [[[-3]]]), + ] + ) + def test_Threshold_tolerances( + self, comparator, increment, threshold, atol, rtol, expected_results, comp_mode + ): + if comp_mode is pnl.ExecutionMode.LLVM: + pytest.skip('ExecutionMode.LLVM does not support Parameter access in conditions') + + A = TransferMechanism( + integrator_mode=True, + integrator_function=pnl.AccumulatorIntegrator(rate=1, increment=increment), + ) + comp = Composition(pathways=[A]) + + comp.termination_processing = { + pnl.TimeScale.TRIAL: pnl.Threshold(A, 'value', threshold, comparator, atol=atol, rtol=rtol) + } + + comp.run(inputs={A: np.ones(A.defaults.variable.shape)}, execution_mode=comp_mode) + + np.testing.assert_array_equal(comp.results, expected_results) + + class TestWhenFinished: @classmethod diff --git a/tests/scheduling/test_scheduler.py b/tests/scheduling/test_scheduler.py index 392f81b42b1..459512441f6 100644 --- a/tests/scheduling/test_scheduler.py +++ b/tests/scheduling/test_scheduler.py @@ -12,7 +12,7 @@ from psyneulink.core.components.projections.pathway.mappingprojection import MappingProjection from psyneulink.core.compositions.composition import Composition, EdgeType from psyneulink.core.globals.keywords import VALUE -from psyneulink.core.scheduling.condition import AfterNCalls, AfterNPasses, AfterNTrials, AfterPass, All, AllHaveRun, Always, Any, AtPass, BeforeNCalls, BeforePass, EveryNCalls, EveryNPasses, JustRan, TimeInterval, WhenFinished +from psyneulink.core.scheduling.condition import AfterNCalls, AfterNPasses, AfterNTrials, AfterPass, All, AllHaveRun, Always, Any, AtPass, BeforeNCalls, BeforePass, EveryNCalls, EveryNPasses, JustRan, TimeInterval, WhenFinished, Never from psyneulink.core.scheduling.scheduler import Scheduler from psyneulink.core.scheduling.time import TimeScale from psyneulink.library.components.mechanisms.processing.integrator.ddm import DDM @@ -159,7 +159,9 @@ def test_one_composition_two_contexts(self): assert output == pytest.helpers.setify_expected_output(expected_output) def test_change_termination_condition(self): - D = DDM(function=DriftDiffusionIntegrator(threshold=10)) + D = DDM(function=DriftDiffusionIntegrator(threshold=10, time_step_size=1.0), + execute_until_finished=False, + reset_stateful_function_when=Never()) C = Composition(pathways=[D]) D.set_log_conditions(VALUE) @@ -1559,10 +1561,12 @@ def test_time_termination_measures(self, comp_mode, timescale, expected): @pytest.mark.usefixtures("comp_mode_no_llvm") def test_scheduler_conditions(self, comp_mode, condition, scale, expected_result): decisionMaker = pnl.DDM( - function=pnl.DriftDiffusionIntegrator(starting_point=0, + function=pnl.DriftDiffusionIntegrator(starting_value=0, threshold=1, - noise=0.0), + noise=0.0, + time_step_size=1.0), reset_stateful_function_when=pnl.AtTrialStart(), + execute_until_finished=False, output_ports=[pnl.DECISION_VARIABLE, pnl.RESPONSE_TIME], name='DDM') diff --git a/tests/scheduling/test_system_newsched.py b/tests/scheduling/test_system_newsched.py index a2e204d2337..63b663184e6 100644 --- a/tests/scheduling/test_system_newsched.py +++ b/tests/scheduling/test_system_newsched.py @@ -39,8 +39,8 @@ def test_create_scheduler_from_system_StroopDemo(self): drift_rate=(1.0), threshold=(0.1654), noise=(0.5), - starting_point=(0), - t0=0.25, + starting_value=(0), + non_decision_time=0.25, ), name='Decision', ) diff --git a/tutorial_requirements.txt b/tutorial_requirements.txt index 98ae285469c..728aa0c0eab 100644 --- a/tutorial_requirements.txt +++ b/tutorial_requirements.txt @@ -1,3 +1,3 @@ graphviz<0.20.0 jupyter<=1.0.0 -matplotlib<3.4.4 +matplotlib<3.5.2