CIRCUIT COMPONENTS

temporal

image

Temporal-associative memory component.

See also: https://creatingintelligence.org/#temporal-associative-memory

Details and properties

  • Learns the association of the previous state with the current input.
  • Predicts the next input based on the current state.
  • Supports temporal integration of signals across evaluation cycles, governed by update rule plugins.
  • Uses the same temporal integration mechanism as delay.
  • The state consists of the temporally integrated signal combined with optional context blocks.
  • Always learns, even when the prediction is correct. This may broaden the base temporal associations.
  • A closed feedback loop enables generative behavior.
  • With the permutation update rule, the temporal order of inputs is preserved.
  • Controls sparsity through stochastic subsampling mechanisms.
  • Represents the integrated state as a multiset.
  • Supports multiple input or output blocks.


Property Default Description
send required [integer,...] representing one or more output slots
receive required one or more input slots with pathway tags
plugin replacement update rule, governing the temporal integration logic
rate_limit unlimited subsample input if population exceeds the rate limit
decay 0 pre-integration decay (leak rate)
capacity 0 relative population carried over from previous state (has no effect with replacement plugin)
decimate 1 proportional stochastic decimation


Use standard style options to customize the component’s appearance in circuit schematics.

Temporal associative memory with replacement update

With the replacement update rule, the current input replaces the internal state, bypassing the capacity setting. This mechanism directly associates each signal to the subsequent signal.

{ "hyperparameters": {"default": [1000, 10]},
  "dataflow": [
    {"component": "input", "send": [1]},
    {"component": "temporal", "plugin": "replacement", 
        "send": [11], "receive": [1]},
    {"component": "output", "receive": [11]}
  ]}

image

Temporal associative memory with state permutation

The temporal component with the permutation update rule accumulates a temporal state by iteratively permuting it at every timestep, encoding the ordering of prior inputs.

{ "hyperparameters": {"default": [1000, 10]},
  "dataflow": [
    {"component": "input", "send": [1]},
    {"component": "temporal", "plugin": "permutation",
        "send": [11], "receive": [1], "capacity": 2},
    {"component": "output", "receive": [11]}
  ]}

image

Temporal associative memory with difference update

The difference update rule replaces the internal state with the symmetric multiset difference of the state and the incoming signal.

{ "hyperparameters": {"default": [1000, 10]},
  "dataflow": [
    {"component": "input", "send": [1]},
    {"component": "temporal", "plugin": "difference", 
        "send": [11], "receive": [1]},
    {"component": "output", "receive": [11]}
  ]}

image

Temporal associative memory with complement plugin

{ "hyperparameters": {"default": [1000, 10]},
  "dataflow": [
    {"component": "input", "send": [1]},
    {"component": "temporal", "plugin": "complement", 
        "send": [11], "receive": [1], "capacity": 2},
    {"component": "output", "receive": [11]}
  ]}

image

Temporal associative memory with state augmentation

The augmentation update rule plugin aggregates an orderless temporal state.

{ "hyperparameters": {"default": [1000, 10]},
  "dataflow": [
    {"component": "input", "send": [1]},
    {"component": "temporal", "plugin": "augmentation", 
        "send": [11], "receive": [1], "capacity": 5},
    {"component": "output", "receive": [11]}
  ]}

image

Source code

def temporal(config):
    """
    Temporal-associative memory component.
    Learns first-order sequences by default (replacement plugin),
    and higher-order sequences with the permutation plugin and capacity > 0.
    A hybrid between auto-associative and hetero-associative architectures.
    Uses the same temporal integration plugins and parameterization as
    "delay". Default plugin: replacement.
    The first input block is the item; further input blocks are context.
    Learns (previous state & previous context) -> current item, and returns
    the prediction for the next item only.
    """
    plugin_factory = config.get("plugin", replacement)

    if isinstance(plugin_factory, str):
        import sys
        plugin_factory = getattr(
            sys.modules[__name__],
            plugin_factory,
            replacement)

    # The update rule acts on the item block only, not on the context blocks.
    plugin = plugin_factory(
        {**config, "receive_blocks": config.get("send_blocks", [])})
        
    receive_blocks = config.get("receive_blocks", [])
    send_blocks = config.get("send_blocks", [])

    # Memory parameters
    paramsA = [sum(b[0] for b in receive_blocks),
               sum(b[1] for b in receive_blocks)]
    paramsB = list(send_blocks[0])
    Nitem, Pitem = paramsB

    contextdims = [b[0] for b in receive_blocks[1:]]
    if contextdims:
        Ncontext = sum(b[0] for b in receive_blocks[1:])
        Pcontext = sum(b[1] for b in receive_blocks[1:])
    else:
        Ncontext, Pcontext = 0, 0

    # Absolute rate limits. Default: unlimited.
    limititem = round(Pitem * config.get("rate_limit", Nitem / Pitem))
    limitcontext = (round(Pcontext * config.get("rate_limit", Ncontext / Pcontext))
                    if Pcontext > 0 else 0)

    # Pre-integration decay (leak rate).
    decay = config.get("decay", 0.0)
    # Temporal capacity, carry over from previous cycle.
    abscapacity = round(Pitem * config.get("capacity", 0.0))
    # Proportional stochastic subsampling for memory query.
    decimation = config.get("decimate", 1.0)

    # Label indicating the number of context blocks.
    label = plugin["label"] + "\u25a1" * len(contextdims)

    # Instantiate the memory.
    m_config = dict(config)
    m_config.update({
        "A_parameters": paramsA,
        "B_parameters": paramsB
    })
    M = Memory(m_config)

    Xstate = []
    Xcontext = []

    def f(item, *blocks):
        nonlocal Xstate, Xcontext

        # Multiset rate limiting of the current item.
        X = item
        if len(X) > limititem:
            X = sorted(rng.choice(X, size=limititem, replace=False).tolist())

        # Pre-integration stochastic decay of previous state.
        if decay > 0.0:
            keep_size = math.floor((1.0 - decay) * len(Xstate))
            Xstate = sorted(
                rng.choice(Xstate, size=keep_size, replace=False).tolist())

        # Always learn (previous state & previous context) -> current item.
        M["store"](resolve_block_join_normal([Xstate, Xcontext], [Nitem, Ncontext]),
                   resolve_normal(X))

        # Multiset rate limiting of the items of the current context.
        Xcontext = multiset_block_join(list(blocks), contextdims)
        if len(Xcontext) > limitcontext:
            Xcontext = sorted(
                rng.choice(Xcontext, size=limitcontext, replace=False).tolist())

        # Multiset subsampling applied to previous state.
        if len(Xstate) > abscapacity:
            Xstate = sorted(
                rng.choice(Xstate, size=abscapacity, replace=False).tolist())

        # Temporal integration via update rules.
        Xstate = plugin["updaterule"](X, Xstate)

        # Proportional multiset subsampling applied to the integrated state,
        # to break symmetry during retrieval.
        Xdec = multiset_block_join([Xstate, Xcontext], [Nitem, Ncontext])
        if decimation < 1.0:
            sample_size = math.floor(decimation * len(Xdec))
            Xdec = sorted(
                rng.choice(Xdec, size=sample_size, replace=False).tolist())

        # Predict next token.
        return (M["retrieve"](resolve_normal(Xdec)),)

    result = dict(plugin)
    result.update({
        "function": f,
        "checks": ["dimfirst", "oneout"],
        "shape": "square", "label": label, "size": 10, "fill": 14
    })
    result.update(M)

    return result