i3AI logo

Homeostasis leads to cognition and consciousness

The evolutionary development of animal nervous systems can be conceptualized as a progression of increasing complexity in response to the fundamental need for homeostasis. Homeostasis, the process by which biological systems maintain internal stability, serves as the driving force behind the evolution of the nervous system.

Our hypothesis is that the nervous system emerged with the sole purpose of homeostasis and that homeostasis continues to be the “outer loop” in everything that brains do. Roughly speaking, here are the steps we propose animal nervous systems went through during evolution.

Each step is illustrated with pseudocode to show how the concept of homeostasis is implemented in each stage. Note that the pseudocode is highly simplified and does not represent any specific biological system. So, consider the pseudocode as a rough guide only.

Step 1: Direct and Reactive

In the simplest form, single-cell organisms react directly to environmental stimuli. These organisms possess receptors that trigger biochemical processes resulting in immediate motor responses.

We can imply the presence of corresponding homeostatic variables (hvars), but these hvars are not explicitly implemented, nor managed.

Example: Bacteria sensing noxious chemical gradients and adjusting flagellar movement accordingly.

# Represents single-cell organisms with direct reactive behavior
def reactive_organism_main_loop():
    # Only implied hvars here, managed through biochemical processes
    hvars = initialize_implied_hvars()
    # Initialize system state
    system_state = initialize_system_state()

    # Main loop
    while True:
        # Get direct sensory input
        input = get_input()
        # Maintain homeostasis by generating actions to trigger
        actions = homeostasis(input, system_state)
        execute_actions(actions)  # Execute the actions
        # system state gets updated due to the actions

def homeostasis(input, system_state):
    # Simple reaction to sensory input
    # For example, noxious stimulus triggers a biochemical cascade resulting in
    # motor response that moves the organism away from the stimulus
    # Thus, the implied hvar "noxious_stimulus" is managed without ever being
    # explicitly represented
    actions = biochemical_cascade(input, system_state)

    # Note: hvars are not used here
    return actions

# Simplified function to initialize implied hvars
def initialize_implied_hvars():
    return {"noxious_stimulus": 0}  # Example of implied hvar whose target value is 0

# Simplified function to initialize the system state
def initialize_system_state():
    return {}

Step 2: Multi-source and Single Sink

Early multicellular organisms develop specialized sensory cells distributed across their bodies. These sensory inputs are transmitted to motor cells via primitive neuron-like cells, allowing for more coordinated responses across the entire body of the organism.

Example: Sea anemones exhibiting basic neural circuits where sensory inputs lead to direct motor outputs.

# Represents multicellular organisms with specialized sensory cells and simple
# neural communication
def multicellular_organism_main_loop():
    # Only implied hvars here, managed through biochemical processes
    hvars = initialize_implied_hvars()
    # Initialize system state
    system_state = initialize_system_state()

    # Main loop
    while True:
        # Get multisensory inputs from various sensory cells
        inputs = get_multisensory_inputs()
        # Maintain homeostasis by generating actions to trigger
        actions = homeostasis(inputs, system_state)
        execute_actions(actions)  # Execute the actions
        # system state gets updated due to the actions

def homeostasis(inputs, system_state):
    actions = []
    # Process each sensory input to generate corresponding actions
    for input in inputs:
        action = process_sensory_input(input, system_state)
        actions.append(action)
    # Note: hvars are not used here
    return actions

# Simplified function to initialize the system state
def initialize_system_state():
    return {}

# Simplified function to simulate getting multisensory inputs
def get_multisensory_inputs():
    return ["input1", "input2", "input3"]

# Simplified function to process each sensory input
def process_sensory_input(input, system_state):
    # Example of processing input (details would depend on specific organism)
    return f"action_for_{input}"

# Simplified function to execute actions
def execute_actions(actions):
    for action in actions:
        print(f"Executing: {action}")

Step 3: Centralized Processing and Non-linear Functions

The migration of neurons into centralized, protected structures (proto-brains) allows for more complex processing and integration of sensory inputs. Lateral connections among neurons enable non-linear transformations of sensory data. This is where dynamics such as LIF (Leaky Integrate-and-Fire) come into play, allowing for the accumulation of evidence over time, thus extending the time horizon of actions and enabling cooperation and competition among neurons. This is a precursor to planning. Note that these nonlinear computing units themselves start coding for certain homeostatic variables.

Example: Early vertebrates with centralized nervous systems capable of integrating and processing sensory information.

# Represents organisms with centralized nervous systems allowing complex
# processing
def centralized_nervous_system_main_loop():
    # Only implied hvars here, managed through biochemical processes
    hvars = initialize_implied_hvars()
    # Initialize system state
    system_state = initialize_system_state()

    # Main loop
    while True:
        # Get multisensory inputs from various sensory cells
        inputs = get_multisensory_inputs()
        # Maintain homeostasis by generating actions to trigger
        actions = homeostasis(inputs, system_state)
        execute_actions(actions)  # Execute the actions
        # system state gets updated due to the actions

def homeostasis(inputs, system_state):
    # Apply non-linear processing to input
    actions = non_linear_processing(input, system_state)
    return actions

# Non-linear processing of integrated inputs
def non_linear_processing(input, system_state):
    # Non-linear transformation
    # For example, Leaky Integrate-and-Fire (LIF) model can accumulate
    # evidence for a particular input over time, and trigger an action
    # when enough evidence is accumulated in a short period of time
    actions = LeakyIntegrateFire(input, THRESHOLD)
    return actions

# Simplified function to initialize the system state
def initialize_system_state():
    return {}

# Simplified function to simulate getting multisensory inputs
def get_multisensory_inputs():
    return [1, 2, 3]  # Example inputs

# Simplified function to execute actions
def execute_actions(actions):
    for action in actions:
        print(f"Executing: {action}")

Step 4: Predictive Mechanisms and Homeostatic Variables (Hvars)

As we saw in step 3, neurons start accumulating evidence for certain conditions and firing when sufficient evidence is available. Now, if another layer of neurons are added that get intput from the above neurons, they start representing complex spatiotemporal sequences, some of which may predict a future event.

Thus, a certain group of neurons started predicting future sensory (extero, intero, proprioceptive) inputs based on current sensory inputs. Now actions could be fired to prevent the system getting into undesirable future states. This is where homeostatic variables (“hvar"s) come into picture. They represent computed quantities that, when kept within certain ranges, results in meeting certain physical objectives of the organism. e.g. ion concentrations, CO2 levels, core body temperature, etc. Deviations in these hvars trigger hardcoded and learned mitigation action cascades. All relevant quantities to be regulated become encoded as hvars.

Predictions now enable anticipatory actions that maintain homeostasis proactively. Now homeostatic variables become more concrete in the form of the predictions. For instance, if a neuron fires when it predicts that the temperature will rise, it is now coding for the homeostatic variable "temperature” moving away from its steady state. Actions can now be triggered to prevent the temperature from rising.

Note that actions are generated only using hvars that are away from steady state. This implies that there is no agency other than maintaining homeostasis. No “free will” yet.

Example: The hypothalamus in mammals regulating variables like hunger, thirst, and temperature.

# Represents organisms that predict future states to maintain homeostasis
def predictive_nervous_system_main_loop():
    # Initialize physiological homeostatic variables that are represented
    # by certain neurons
    hvars = initialize_physiological_hvars()
    # Initialize system state
    system_state = initialize_system_state()

    # Main loop
    while True:
        # Get multisensory inputs from various sensory cells
        inputs = get_multisensory_inputs()
        # Maintain homeostasis by generating actions to trigger
        actions = homeostasis(inputs, system_state, hvars)
        execute_actions(actions)  # Execute the actions
        # System state gets updated due to the actions

def homeostasis(inputs, system_state, hvars):
    # Predict the homeostatic state of the system
    predicted_homeostatic_state = predict_future_homeostatic_state(system_state, hvars, previous_actions)

    # Compute which hvars are at steady state or away from steady state,
    # resulting in current valence
    current_valence = compute_valence(hvars, predicted_homeostatic_state)

    actions = []
    # current_valence is a dictionary with hvars as keys and their
    # valence as values
    if !current_valence.all_neutral:
        # Generate actions to move hvars to steady state
        # Note that actions are generated only using hvars that are
        # away from steady state
        # There is no agency other than maintaining homeostasis!
        actions = generate_actions(hvars, current_valence)
    return actions

# Predict future sensory input based on current inputs (simplified)
def predict_future_homeostatic_state(system_state, hvars, previous_actions):
    # Example predicted future state
    future_state = {"temperature": 39, "oxygen_level": 90}

    return future_state

# Compute the state of the homeostatic variables
def get_homeostatic_state(predicted_state, hvars):
    homeostatic_state = {}
    for i, hvar in enumerate(hvars):
        homeostatic_state[hvar] = predicted_state[i]
    return homeostatic_state

# Compute current valence based on deviation from steady state
def compute_valence(hvars, predicted_homeostatic_state):
    valence = {}
    for hvar in hvars:
        valence[hvar] = hvars[hvar]['steady_state'] - predicted_homeostatic_state[hvar]
    return valence

# Generate actions to maintain homeostatic balance
def generate_actions(hvars, current_valence):
    actions = []
    for hvar in hvars:
        if current_valence[hvar] != 0:
            if current_valence[hvar] > 0:
                actions.append(increase_activity(hvar))
            else:
                actions.append(decrease_activity(hvar))
    return actions

# Increase activity (simplified action)
def increase_activity(hvar):
    return f"increase_activity_for_{hvar}"

# Decrease activity (simplified action)
def decrease_activity(hvar):
    return f"decrease_activity_for_{hvar}"

# Simplified function to initialize physiological homeostatic variables
def initialize_physiological_hvars():
    return {
        'temperature': {'threshold': 37, 'steady_state': 37},
        'oxygen_level': {'threshold': 95, 'steady_state': 95}
    }

# Simplified function to initialize the system state
def initialize_system_state():
    return {}

# Simplified function to simulate getting multisensory inputs
def get_multisensory_inputs():
    return [36, 94]  # Example inputs for temperature and oxygen level

# Simplified function to execute actions
def execute_actions(actions):
    for action in actions:
        print(f"Executing: {action}")

Step 5: Attention Mechanisms

Given current state of the set of hvars that the brain needs to manage (the homeostatic state, a lower dimensional subspace of the whole system state, mapped onto a homeostatic energy landscape), cascades of activities to manage all deviations get fired. This may result in conflicts, e.g. being hungry in the presence of a predator - explore find food or hide to stay safe. Considering the relative importance and deviation of each variable, brains developed mechanisms to attend to the most important (as of that moment) subset of hvars. This attention mechanism reused the same neural machinery available, i.e. higher level homeostatic variables were set up, e.g. being comfortable (satiated and safe). The predicted deviations in the higher level hvars selectively attend to (or otherwise suppress) lower level hvars.

There must be a cost to suppressing lower level hvars because otherwise certain hvars may be starved of attention and result in harm in the long run. This is probably driven again by higher level hvars that sounds alarm on extreme neglect of the lower level hvar.

The mechanism of building out this hierarchy (more appropriately, heterarchy) must be such that higher level hvars must get wired up to ensure management of all lower level hvars eventually.

Evolving attention mechanisms allow organisms to prioritize among multiple homeostatic deviations, enabling more complex behaviors. The importance of each hvar and the magnitude of its deviation from steady state determine the priority of each input. The hvars that are based in physiological needs have importance derived from their relevance to homeostasis, likely coded genetically.

Note that the importance of hvars can be updated based on the current state of the organism. For example, if an organism is in a state of starvation, the importance of the hvar “hunger” may increase, leading to a higher priority for actions that address this hvar.

This prioritization over multiple hvars is itself driven by a higher order homeostatic variable that represents the whole organism. This higher order hvar is coded by the brain and is the precursor to the concept of self.

Example: The hypothalamus in mammals prioritizing hvar deviations.

# Represents organisms with the ability to prioritize among
# multiple homeostatic deviations
def attention_mechanism_main_loop():
    # Initialize physiological homeostatic variables
    hvars = initialize_physiological_hvars()
    # Initialize system state
    system_state = initialize_system_state()

    # Main loop
    while True:
        # Get multisensory inputs from various sensory cells
        inputs = get_multisensory_inputs()
        # Maintain homeostasis by generating actions to trigger
        actions = homeostasis(inputs, system_state, hvars)
        execute_actions(actions)  # Execute the actions
        # System state gets updated due to the actions
        # Update attention mechanisms
        update_attention_mechanisms(hvars)

def homeostasis(inputs, system_state, hvars):
    # Predict the homeostatic state of the system
    predicted_homeostatic_state = predict_future_homeostatic_state(system_state, hvars)

    # Compute which hvars are at steady state or away from steady
    # state, resulting in current valence
    current_valence = compute_valence(hvars, predicted_homeostatic_state)

    # Generate actions for the top priority hvars that are away
    # from steady state
    # Note that prioritization of hvars would happen during the
    # homeostasis of the "self" hvar.
    actions = generate_actions(prioritized_hvars, current_valence)
    return actions

# Predict future homeostatic state based on current inputs and previous actions
def predict_future_homeostatic_state(system_state, hvars):
    # Example predicted future state (simplified)
    future_state = {"temperature": 39, "oxygen_level": 90, "self_health": 45}
    return future_state

# Compute current valence based on deviation from steady state
def compute_valence(hvars, predicted_homeostatic_state):
    valence = {}
    for hvar in hvars:
        valence[hvar] = hvars[hvar]['steady_state'] - predicted_homeostatic_state[hvar]
    return valence

# Prioritize hvars based on their importance and current valence
def self_health_action(hvars, current_valence):
    prioritized_hvars = sorted(hvars, key=lambda hvar: abs(current_valence[hvar]) * hvars[hvar]['importance'], reverse=True)
    return prioritized_hvars

# Generate actions to maintain homeostatic balance
def generate_actions(prioritized_hvars, current_valence):
    actions = []
    for hvar in prioritized_hvars:
        if hvar == "self_health":
            actions.append(self_health_action)
        if current_valence[hvar] != 0:
            if current_valence[hvar] > 0:
                actions.append(increase_activity(hvar))
            else:
                actions.append(decrease_activity(hvar))
    return actions

# Increase activity (simplified action)
def increase_activity(hvar):
    return f"increase_activity_for_{hvar}"

# Decrease activity (simplified action)
def decrease_activity(hvar):
    return f"decrease_activity_for_{hvar}"

# Update attention mechanisms (simplified example)
def update_attention_mechanisms(hvars):
    # Example of updating the importance of a cognitive goal
    if 'temperature' in hvars:
        hvars['temperature']['importance'] *= 1.1

# Simplified function to initialize physiological homeostatic variables
def initialize_physiological_hvars():
    return {
        'temperature': {'steady_state': 37, 'importance': 0.5},
        'oxygen_level': {'steady_state': 95, 'importance': 0.8},
        'self_health': {'steady_state': 100, 'importance': 1.0}
    }

# Simplified function to initialize the system state
def initialize_system_state():
    return {}

# Simplified function to simulate getting multisensory inputs
def get_multisensory_inputs():
    return [36, 94]  # Example inputs for temperature and oxygen level

# Simplified function to execute actions
def execute_actions(actions):
    for action in actions:
        print(f"Executing: {action}")

Step 6: Cognitive Homeostatic Variables

Once the brain had the ability to establish homeostatic variables, a mechanism to dynamically set up arbitrary hvars came about. This was to facilitate longer term goals. For instance, going back to food source by revisiting known waypoints, while avoiding predators and other distractions. Once established, these “cognitive hvars” would become part of all the hvars the system needs to manage, and get managed alongside physiological hvars.

Now, given that the cognitive hvars are “made up”, they can be abused. For instance, someone may set a goal for an unachievably low body weight as a goal, i.e. a cognitive hvar, and configure it to have an unusually high “value”. Then the homeostatic control system would be forced to keep this hvar in attention, the person would starve and become anorexic, leading to severe health issues.

Somewhere during this evolutionary phase, we probably developed a model of the self-preservation as the highest level cognitive hvar, which resulted in the “self” model and qualia that the self cannot escape (not just spikes coming from somewhere, but “felt experience” that is binding).

The brain develops the capability to set and manage cognitive goals (cognitive hvars) alongside physiological needs. This ability supports complex behaviors like planning and long-term goal pursuit.

Example: Human cognitive processes involving goal-setting and planning in the dorsolateral prefrontal cortex.

# Represents organisms with the ability to set and manage cognitive
# homeostatic variables (hvars)
def cognitive_hvars_main_loop():
    # Initialize physiological homeostatic variables
    hvars = initialize_physiological_hvars()
    # Initialize system state
    system_state = initialize_system_state()

    # Main loop
    while True:
        # Get multisensory inputs from various sensory cells
        inputs = get_multisensory_inputs()
        # Maintain homeostasis by generating actions to trigger
        actions = homeostasis(inputs, system_state, hvars)
        execute_actions(actions)  # Execute the actions
        # System state gets updated due to the actions
        # Update cognitive homeostatic variables
        update_cognitive_hvars(hvars)

def homeostasis(inputs, system_state, hvars):
    # Predict the homeostatic state of the system
    predicted_homeostatic_state = predict_future_homeostatic_state(system_state, hvars)

    # Compute which hvars are at steady state or away from steady
    # state, resulting in current valence
    current_valence = compute_valence(hvars, predicted_homeostatic_state)

    # Generate actions for the top priority hvars that are away
    # from steady state
    prioritized_hvars = prioritize_hvars(hvars, current_valence)
    actions = generate_actions(prioritized_hvars, current_valence)
    return actions

# Predict future homeostatic state based on current inputs and
# previous actions
def predict_future_homeostatic_state(system_state, hvars):
    # Example predicted future state (simplified)
    future_state = {
        "temperature": 39,
        "oxygen_level": 90,
        "self_health": 45,
        "cognitive_goal": 70
    }
    return future_state

# Compute current valence based on deviation from steady state
def compute_valence(hvars, predicted_homeostatic_state):
    valence = {}
    for hvar in hvars:
        valence[hvar] = hvars[hvar]['steady_state'] - predicted_homeostatic_state[hvar]
    return valence

# Prioritize hvars based on their importance and current valence
def prioritize_hvars(hvars, current_valence):
    prioritized_hvars = sorted(
        hvars, key=lambda hvar: abs(current_valence[hvar]) * hvars[hvar]['importance'], reverse=True)
    return prioritized_hvars

# Generate actions to maintain homeostatic balance
def generate_actions(prioritized_hvars, current_valence):
    actions = []
    for hvar in prioritized_hvars:
        if current_valence[hvar] != 0:
            if current_valence[hvar] > 0:
                actions.append(increase_activity(hvar))
            else:
                actions.append(decrease_activity(hvar))
    return actions

# Increase activity (simplified action)
def increase_activity(hvar):
    return f"increase_activity_for_{hvar}"

# Decrease activity (simplified action)
def decrease_activity(hvar):
    return f"decrease_activity_for_{hvar}"

# Update cognitive homeostatic variables (add, reconfigure, or discard)
def update_cognitive_hvars(hvars):
    # Example of adding a new cognitive goal
    hvars['cognitive_goal'] = {'steady_state': 80, 'importance': 1.2}
    # Example of reconfiguring an existing cognitive goal
    if 'cognitive_goal' in hvars:
        hvars['cognitive_goal']['steady_state'] = 75
    # Example of discarding a cognitive goal
    if 'discard_goal' in hvars:
        del hvars['discard_goal']

# Simplified function to initialize physiological homeostatic variables
def initialize_physiological_hvars():
    return {
        'temperature': {'steady_state': 37, 'importance': 0.5},
        'oxygen_level': {'steady_state': 95, 'importance': 0.8},
        'self_health': {'steady_state': 100, 'importance': 1.0},
        'cognitive_goal': {'steady_state': 80, 'importance': 1.0}
    }

# Simplified function to initialize the system state
def initialize_system_state():
    return {}

# Simplified function to simulate getting multisensory inputs
def get_multisensory_inputs():
    return [36, 94]  # Example inputs for temperature and oxygen level

# Simplified function to execute actions
def execute_actions(actions):
    for action in actions:
        print(f"Executing: {action}")