# ValueError: Equations of type 'parameter' cannot have a flag 'linked', only the following flags are allowed: \['constant', 'shared'\]

**URL:** <https://brian.discourse.group/t/valueerror-equations-of-type-parameter-cannot-have-a-flag-linked-only-the-following-flags-are-allowed-constant-shared/1373>\
**Category:** Support\
**Tags:** synapses, linked-variable\
**Created:** [21 January 2025 17:39 UTC](https://brian.discourse.group/t/valueerror-equations-of-type-parameter-cannot-have-a-flag-linked-only-the-following-flags-are-allowed-constant-shared/1373 "2025-01-21T17:39:21Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![paulbrodersen](https://yyz2.discourse-cdn.com/free1/user_avatar/brian.discourse.group/paulbrodersen/32/664_2.png) [@paulbrodersen](https://brian.discourse.group/u/paulbrodersen)\
**Post date:** [21 January 2025 17:39 UTC](https://brian.discourse.group/t/valueerror-equations-of-type-parameter-cannot-have-a-flag-linked-only-the-following-flags-are-allowed-constant-shared/1373/1 "2025-01-21T17:39:21Z")

</div>

# Description of problem

I am trying to implement the homeostatic inhibitory STDP rule used in [Zenke (2015)](https://www.nature.com/articles/ncomms7922) in Brian2. The rule uses a symmetric STDP kernel that is modulated in size and sign by a global factor `G,` which corresponds to the difference between a (smoothed) estimate of the population firing rate `H` and a desired firing rate `gamma`. I am trying to implement this rule using a synapse model with a linked variable. However, my current attempt results in a cryptic error message.

# Full traceback of error (if relevant)

```auto
Traceback (most recent call last):
  File "/home/paul/work/gothard/code/inhibitory_homeostatic_plasticity_with_shared_global_factor.py", line 61, in <module>
    synapses = b2.Synapses(
               ^^^^^^^^^^^^
  File "/home/paul/opt/miniconda3/envs/brian2/lib/python3.11/site-packages/brian2/synapses/synapses.py", line 853, in __init__
    model.check_flags(
  File "/home/paul/opt/miniconda3/envs/brian2/lib/python3.11/site-packages/brian2/equations/equations.py", line 1234, in check_flags
    raise ValueError(
ValueError: Equations of type 'parameter' cannot have a flag 'linked', only the following flags are allowed: ['constant', 'shared']

```

# Minimal code to reproduce problem

```python
"""
This script implements a STDP rule with a global/shared factor as in Zenke et al. (2015).
"""

import numpy as np
import matplotlib.pyplot as plt
import brian2 as b2

b2.start_scope()

net = b2.Network(b2.collect())

# set (target) population firing rate; 
# in a non-toy simulation, spikes would be recorded from a large pyramidal neuron population
total_epochs = 11
epoch_length = 1 * b2.second
population_size = 1
spike_rates = np.geomspace(1, 50, total_epochs)
spike_rates_array = b2.TimedArray(spike_rates * b2.Hz, dt=epoch_length)
spike_generators = b2.PoissonGroup(population_size, rates="spike_rates_array(t)")
net.add(spike_generators)

# compute global factor G
gamma = 5 * b2.Hz
tau_H = 10 * b2.second
global_factor_model = """
G = H - gamma : Hz
dH/dt = -H/tau_H : Hz
"""
global_factor = b2.NeuronGroup(1, model=global_factor_model)
net.add(global_factor)
spike_aggregator = b2.Synapses(spike_generators, global_factor, on_pre="H_post += 1/(tau_H * population_size)")
spike_aggregator.connect()
net.add(spike_aggregator)

# initialize the pre- and post-synaptic neuron
indices = np.zeros(total_epochs)
times = epoch_length * np.arange(total_epochs) + 0.5 * epoch_length
presynaptic_neuron = b2.SpikeGeneratorGroup(1, indices, times)
net.add(presynaptic_neuron)
delta = 10 * b2.msecond
postsynaptic_neuron = b2.SpikeGeneratorGroup(1, indices, times + delta)
net.add(postsynaptic_neuron)

# initialize the synapse
tau_stdp = 20. * b2.msecond
eta = 1. * b2.nsiemens * b2.second
synapse_model = """
G : Hz (linked)
wij : siemens
dzi/dt = -zi / tau_stdp : 1 (event-driven)
dzj/dt = -zj / tau_stdp : 1 (event-driven)
"""
on_pre = """
zi += 1.
wij += eta * G * zj
"""
on_post = """
zj += 1.
wij += eta * G * (zi + 1)
"""
synapses = b2.Synapses(
    presynaptic_neuron, postsynaptic_neuron,
    model=synapse_model, on_pre=on_pre, on_post=on_post
)
synapses.connect(i=0, j=0)
# synapses.G = b2.linked_var(global_factor.G)
synapses.G = b2.linked_var(global_factor, "G")
synapses.wij[:] = 0 * b2.nsiemens
net.add(synapses)

# monitor synaptic variables
monitor = b2.StateMonitor(synapses, ["G", "wij"], record=True, dt=epoch_length)
net.add(monitor)

# run
net.run(total_epochs * epoch_length)

# plot
fig, axes = plt.subplots(2, 1, sharex=True)
axes[0].plot(np.squeeze(monitor.G / b2.Hz), color="gray")
axes[0].set_ylabel("Global factor [Hz]")
axes[1].plot(np.diff(np.squeeze(monitor.wij / b2.nsiemens)), color="gray")
axes[1].set_ylabel("Weight [nS]")
axes[-1].set_xlabel("Epoch")
plt.show()

```

Any insight or workaround would be appreciated.

---

<div class="post-metadata">

**Author:** ![mstimberg](https://yyz2.discourse-cdn.com/free1/user_avatar/brian.discourse.group/mstimberg/32/11_2.png) [@mstimberg](https://brian.discourse.group/u/mstimberg)\
**Post date:** [22 January 2025 11:05 UTC](https://brian.discourse.group/t/valueerror-equations-of-type-parameter-cannot-have-a-flag-linked-only-the-following-flags-are-allowed-constant-shared/1373/2 "2025-01-22T11:05:21Z")

</div>

Hi @paulbrodersen,  
great question (and an example reproducing something from Zenke (2015) would be a nice addition to the documentation 😊 ). The reason for the error is that the `linked` flag is only allowed in `NeuronGroup` equations, it cannot be used in `Synapses`. This is because when we establish a link with `linked_var`, we establish a mapping of indices between the two groups – this does not work for synapses in the general case, since their number is not fixed. However, this is an issue for non-trivial mappings, and we could actually allow linked variables in Synapses for linking to groups of size 1 (as in your example), where there’s no ambiguity about the mapping.

Until we add this feature, there’s a workaround you can use: the linked variable mechanism does several checks, verifies that the mapping is feasible and so on, and then establishes an internal reference to the variable from the other group. You can skip the linked variable mechanism and directly use the internal mechanism. For that, you have to remove `G : Hz (linked)` from the synaptic equations, and replace the `synapses.G = ...` assignment by:

```python
synapses.variables.add_reference("G", group=global_factor, index='0')

```

(the `index='0'` is a special case for scalar/shared variables, that are always index as `[0]`).

Hope that works for you!

---

<div class="post-metadata">

**Author:** ![paulbrodersen](https://yyz2.discourse-cdn.com/free1/user_avatar/brian.discourse.group/paulbrodersen/32/664_2.png) [@paulbrodersen](https://brian.discourse.group/u/paulbrodersen)\
**Post date:** [23 January 2025 14:57 UTC](https://brian.discourse.group/t/valueerror-equations-of-type-parameter-cannot-have-a-flag-linked-only-the-following-flags-are-allowed-constant-shared/1373/3 "2025-01-23T14:57:59Z")

</div>

> Hope that works for you!

It does. As always: thank you for the fast and informative response!

> (and an example reproducing something from Zenke (2015) would be a nice addition to the documentation 😊 ).

Happy to contribute whatever I can. Would a sanitized version of the code above suffice (as a proof-of-principle), or would you rather see it being used in anger as a homeostatic mechanism in a simulation with large neuronal populations (which invariably will incur additional complexity).

---

<div class="post-metadata">

**Author:** ![mstimberg](https://yyz2.discourse-cdn.com/free1/user_avatar/brian.discourse.group/mstimberg/32/11_2.png) [@mstimberg](https://brian.discourse.group/u/mstimberg)\
**Post date:** [23 January 2025 15:06 UTC](https://brian.discourse.group/t/valueerror-equations-of-type-parameter-cannot-have-a-flag-linked-only-the-following-flags-are-allowed-constant-shared/1373/4 "2025-01-23T15:06:57Z")

</div>

> [@paulbrodersen](#):
>
> Happy to contribute whatever I can. Would a sanitized version of the code above suffice (as a proof-of-principle), or would you rather see it being used in anger as a homeostatic mechanism in a simulation with large neuronal populations (which invariably will incur additional complexity).

Hi @paulbrodersen – either would be nice, actually. Something like your example above would be a nice addition to the `synapses` section of the documentation, demonstrating how one could set up such a mechanism (similar in spirit to [Example: spike\_based\_homeostasis — Brian 2 2.8.0.2 documentation](https://brian2.readthedocs.io/en/stable/examples/synapses.spike_based_homeostasis.html)). Reproducing one of the figures from Zenke (2015) would be great for the `frompapers` section, but is maybe a bit too much work.

---

<div class="post-metadata">

**Author:** ![paulbrodersen](https://yyz2.discourse-cdn.com/free1/user_avatar/brian.discourse.group/paulbrodersen/32/664_2.png) [@paulbrodersen](https://brian.discourse.group/u/paulbrodersen)\
**Post date:** [23 January 2025 16:31 UTC](https://brian.discourse.group/t/valueerror-equations-of-type-parameter-cannot-have-a-flag-linked-only-the-following-flags-are-allowed-constant-shared/1373/5 "2025-01-23T16:31:05Z")

</div>

Made a PR with a slightly sanitized version of the script above.

---

<div class="post-metadata">

**Author:** ![carlo.castoldi](https://avatars.discourse-cdn.com/v4/letter/c/7ab992/32.png) [@carlo.castoldi](https://brian.discourse.group/u/carlo.castoldi)\
**Post date:** [3 September 2026 14:04 UTC](https://brian.discourse.group/t/valueerror-equations-of-type-parameter-cannot-have-a-flag-linked-only-the-following-flags-are-allowed-constant-shared/1373/6 "2026-09-03T14:04:46Z")

</div>

Necroing this one a bit, but wanted to flag a follow-up gotcha for anyone landing here with the same pattern of having an homeostatic/global factor linked into a `Synapses` object, as OP.

The `add_reference(..., index="0")`/`linked_var()` trick from @mstimberg above does get the link wired up fine. Reading/writing the linked value from within synapse equations works perfectly.  
But if you try to read that linked variable directly from Python through the `Synapses` object itself (`synapses.H`, or anything going through `get_states()`), it blows up as soon as you have more than 1 synapse with `IndexError: index 1 is out of bounds for axis 0 with size 1`

Minimal example:

```python
import brian2 as b2
import numpy as np

gf = b2.NeuronGroup(1, "dH/dt = -H/tau_hom : Hz\ntau_hom : second (constant)", method="exact")
gf.tau_hom = 0.5*b2.second

src = b2.PoissonGroup(3, rates=10*b2.Hz)
dst = b2.PoissonGroup(3, rates=10*b2.Hz)
syn = b2.Synapses(src, dst, model="w:1\nH : Hz (shared, linked)")
syn.connect(i=[0,1,2], j=[0,1,2])
syn.variables.add_reference("H", gf, "H", index="0")
# OR:
# syn.H = b2.linked_var(gf, "H")
syn.H[:] # IndexError

```

Dug into it a bit, with the help of Claude, and indeed `Group`/`Indexing` (used by plain `NeuronGroup`) has a fast path (`if index_var == "0": return 0`) that makes `index="0"` links resolve to a scalar correctly. But `Synapses` uses a different indexing class (`SynapticIndexing`) for resolving slices/arrays, and it completely ignores `index_var` there. For this reason, by default with an empty slice, it always builds one index per synapse (`arange(N_synapses)`) and explodes past position 0.

Subexpressions that use the linked var (like `G` in the OP’s code) don’t hit this because they go through a different, compiled path that checks `.scalar` at the point of use, not through per-synapse index resolution.

For now, my workaround, is to avoid reading/writign the linked variable through the `Synapses` object at all, and go through the real owning group directly.

Do you reckon i should open an issue about this behaviour of `SynapticIndexing`?

---

<div class="post-metadata">

**Author:** ![mstimberg](https://yyz2.discourse-cdn.com/free1/user_avatar/brian.discourse.group/mstimberg/32/11_2.png) [@mstimberg](https://brian.discourse.group/u/mstimberg)\
**Post date:** [3 September 2026 14:16 UTC](https://brian.discourse.group/t/valueerror-equations-of-type-parameter-cannot-have-a-flag-linked-only-the-following-flags-are-allowed-constant-shared/1373/7 "2026-09-03T14:16:53Z")

</div>

Hi @carlo.castoldi, thanks for bringing this up. It has been a while, so I’m not 100% sure, but I think we’ve since fixed the underlying restriction for linked variables (see [Extend linked variables functionality - Pull Request #1584 - brian-team/brian2 - GitHub](https://github.com/brian-team/brian2/pull/1584)) so this workaround shouldn’t be necessary anymore – you can directly use `(linked)` in the synaptic equations and then use `linked_var` to link it to the global factor (which has to be a scalar/“shared” variable) in the `NeuronGroup`. Any Brian version ≥ 2.9 should support this ([Release notes — Brian 2 2.10.1 documentation](https://brian2.readthedocs.io/en/stable/introduction/release_notes.html#id3)).

If this works for you, I’d say it is not worth investigating the issue with the previous workaround further. If it doesn’t please let us know!

---

<div class="post-metadata">

**Author:** ![carlo.castoldi](https://avatars.discourse-cdn.com/v4/letter/c/7ab992/32.png) [@carlo.castoldi](https://brian.discourse.group/u/carlo.castoldi)\
**Post date:** [3 September 2026 16:11 UTC](https://brian.discourse.group/t/valueerror-equations-of-type-parameter-cannot-have-a-flag-linked-only-the-following-flags-are-allowed-constant-shared/1373/8 "2026-09-03T16:11:22Z")

</div>

mmh that PR improved a lot the interface, however I am afraid that the bug still stands, when using `linked_var()` in the above minimal example. I think that at its root, it’s just a matter of how `SynapticIndexing` works in this very unique _sort-of-shared-variable_ scenario.

`gf.H` above can’t be a proper (shared) variable because it **must** be a differential equation. In that case, from my very own understanding, `linked_var()` (or `add_reference(index="0")`) is guessing that `H`, being a lenght-1 source, is _meant_ to be a broadcast/one-shared-value. Hence `SynapticIndexing` will have `index_var == "0"`. However, `SynapticIndexing` doesn’t handle this case and it ends up with a `IndexError`.

I have also tested a quick fix by adding the missing case and that appears to have fixed the error for me.  
May I try to work on my first PR with it?

EDIT: i ended up opening over here [Fix SynapticIndexing when index\_var=="0" - Pull Request #1870 - brian-team/brian2 - GitHub](https://github.com/brian-team/brian2/pull/1870)

---

<div class="post-metadata">

**Author:** ![mstimberg](https://yyz2.discourse-cdn.com/free1/user_avatar/brian.discourse.group/mstimberg/32/11_2.png) [@mstimberg](https://brian.discourse.group/u/mstimberg)\
**Post date:** [7 September 2026 12:42 UTC](https://brian.discourse.group/t/valueerror-equations-of-type-parameter-cannot-have-a-flag-linked-only-the-following-flags-are-allowed-constant-shared/1373/9 "2026-09-07T12:42:46Z")

</div>

Ok thanks for the follow-up, you are probably right that my previous PR only took “real” shared variables, not those from a group of size 1, into account. I will have a look at your PR very soon!
