# How to Use GMutable for Dynamic Dependency Management in CGraph

> Learn to use GMutable for dynamic dependency management in CGraph. This specialized group element allows runtime reshaping of graphs via its pure virtual reshape() method for adaptive execution paths based on runtime data.

- Repository: [Chunel/cgraph](https://github.com/chunelfeng/cgraph)
- Tags: how-to-guide
- Published: 2026-02-27

---

**GMutable is a specialized group element in CGraph that enables runtime reshaping of internal dependency graphs through its pure virtual `reshape()` method, allowing execution paths to adapt dynamically based on runtime data.**

The CGraph pipeline framework provides `GMutable` for scenarios where static dependency definitions are insufficient. Unlike standard groups with fixed topologies, `GMutable` lets you redefine node connections during pipeline execution, making it ideal for conditional workflows, adaptive algorithms, and data-driven processing chains.

## Understanding GMutable Architecture

### Inheritance and Core Interface

`GMutable` extends the standard group functionality through a carefully designed inheritance chain. It derives from `GGroup`, which in turn inherits from `GElement`, placing it firmly within CGraph's element hierarchy while adding specialized runtime capabilities.

The base class definition in [`src/GraphCtrl/GraphElement/GGroup/GMutable/GMutable.h`](https://github.com/chunelfeng/cgraph/blob/main/src/GraphCtrl/GraphElement/GGroup/GMutable/GMutable.h) establishes the contract that all mutable groups must fulfill:

```cpp
class GMutable : public GGroup {
protected:
    /** Redefine the internal data structure */
    virtual CStatus reshape(GElementPtrArr& elements) = 0;
};

```

### The reshape Method Hook

The `reshape` method serves as the primary extension point for dynamic dependency management. This pure virtual function receives a reference to the group's current element array (`GElementPtrArr& elements`), allowing you to rewire connections using CGraph's domain-specific language operators.

The method is invoked automatically during pipeline execution. When the scheduler reaches a `GMutable` instance, it calls `GMutable::run()`, which internally triggers your overridden `reshape` implementation before proceeding with the actual node execution.

## Implementing Dynamic Dependencies with GMutable

### Creating a Custom Mutable Class

To implement dynamic dependency management, you must create a subclass of `GMutable` and override the `reshape` method. The implementation in [`tutorial/MyGMutable/MyMutable.h`](https://github.com/chunelfeng/cgraph/blob/main/tutorial/MyGMutable/MyMutable.h) demonstrates how to switch between four distinct execution patterns based on runtime parameters:

```cpp
// tutorial/MyGMutable/MyMutable.h
class MyMutable : public CGraph::GMutable {
public:
    CStatus reshape(CGraph::GElementPtrArr& elements) override {
        // Access runtime parameters to determine dependency pattern
        auto param = CGRAPH_GET_GPARAM_WITH_NO_EMPTY(MyParam, "param1");
        int count = param->iCount % 4;

        if (count == 0) {
            // Pattern 1: Sequential fan-out (a -> [b, c])
            (*elements[0]) --> elements[1] & elements[2];
        } else if (count == 1) {
            // Pattern 2: Repeat and chain (c * 3 -> b -> a)
            (*elements[2]) --*3 > elements[1];
            (*elements[1]) --> elements[0];
        } else if (count == 2) {
            // Pattern 3: Skip intermediate node (a -> c)
            (*elements[0]) --> elements[2];
        } else {
            // Pattern 4: Parallel execution with repetition
            (*elements[0])--;
            (*elements[1]) --*2;
            (*elements[2])--;
        }
        return CStatus();
    }
};

```

### Runtime Dependency Operators

Inside `reshape`, you manipulate dependencies using CGraph's operator DSL defined in the `GElement` base class:

- **`-->`** – Establishes a sequential dependency (source must complete before target starts)
- **`--*n`** – Creates a repeat dependency where the source runs `n` times before triggering the target
- **`&`** – Indicates parallel execution (both targets run concurrently after source completes)
- **`--`** – Marks an element as runnable without dependencies (used for parallel entry points)

These operators allow you to reconstruct the internal DAG dynamically while maintaining CGraph's type safety and scheduling guarantees.

## Registering and Executing Mutable Groups

### Pipeline Integration

Mutable groups integrate seamlessly into standard CGraph pipelines through the `registerGGroup` method. The tutorial file [`tutorial/T26-Mutable.cpp`](https://github.com/chunelfeng/cgraph/blob/main/tutorial/T26-Mutable.cpp) demonstrates the complete setup:

```cpp
// tutorial/T26-Mutable.cpp
void tutorial_mutable() {
    // Initialize pipeline
    GPipelinePtr pipeline = GPipelineFactory::create();

    // Create child nodes for the mutable group
    GElementPtr a, b_mutable, c, d = nullptr;
    b_mutable = pipeline->createGGroup<MyMutable>({
        pipeline->createGNode<MyNode1>(GNodeInfo("nodeB1")),
        pipeline->createGNode<MyNode2>(GNodeInfo("nodeB2")),
        pipeline->createGNode<MyNode1>(GNodeInfo("nodeB3"))
    });

    // Register elements with dependencies
    pipeline->registerGElement<MyNode1>(&a, {}, "nodeA", 1);
    pipeline->registerGGroup(&b_mutable, {a}, "mutableB", 1);  // Depends on nodeA
    pipeline->registerGElement<MyNode2>(&c, {a}, "nodeC", 1);
    pipeline->registerGElement<MyWriteParamNode>(&d, {b_mutable, c}, "nodeD", 1);

    // Execute multiple iterations with dynamic reshaping
    pipeline->process(6);

    // Cleanup
    GPipelineFactory::remove(pipeline);
}

```

### Execution Flow and Output

When `pipeline->process(6)` executes, the mutable group reshapes its internal dependencies six times, potentially producing different execution graphs each iteration. Sample output from the tutorial demonstrates this variability:

```

---- run as a->[b,c]
---- run as c(*3)->b->a
---- run as a->c, skip b
---- run as [a,b(*2),c]

```

Each line represents a distinct dependency topology created inside `reshape` based on the current value of the runtime parameter. The rest of the pipeline (nodes A, C, and D) maintains its static dependencies while the mutable group B adapts internally.

## Summary

- **GMutable** is an abstract group class in CGraph that enables runtime dependency graph modification through the pure virtual `reshape` method defined in [`src/GraphCtrl/GraphElement/GGroup/GMutable/GMutable.h`](https://github.com/chunelfeng/cgraph/blob/main/src/GraphCtrl/GraphElement/GGroup/GMutable/GMutable.h).
- The `reshape` method receives a reference to the group's element array, allowing you to rewire dependencies using CGraph's DSL operators (`-->`, `--*`, `&`, etc.) based on runtime conditions.
- Mutable groups integrate seamlessly into standard pipelines via `registerGGroup` and trigger reshaping automatically during each execution cycle, as demonstrated in [`tutorial/T26-Mutable.cpp`](https://github.com/chunelfeng/cgraph/blob/main/tutorial/T26-Mutable.cpp).
- This architecture supports dynamic pipelines where execution paths adapt to data, parameters, or external signals without requiring static graph reconstruction.

## Frequently Asked Questions

### What is the difference between GMutable and static GGroup?

**GMutable** requires implementation of the `reshape` method and recalculates internal dependencies during every execution cycle, while static **GGroup** subclasses (like `GRegion` or `GCondition`) maintain fixed topologies defined at pipeline construction time. Use `GMutable` when your workflow needs to adapt based on runtime data, and static groups when the execution order remains constant.

### When is the reshape method called during execution?

The `reshape` method is invoked automatically by `GMutable::run()` each time the pipeline scheduler reaches the mutable group during `pipeline->process()`. This occurs before any child elements execute, ensuring the dependency graph is reconstructed fresh for every iteration based on current runtime parameters or state.

### Can GMutable groups be nested inside other groups?

Yes, `GMutable` instances can be nested within other group types (including other `GMutable` groups) because they inherit from `GGroup`, which is a standard `GElement`. When nesting mutables, each level invokes its own `reshape` method independently during execution, allowing for hierarchical dynamic dependency management where parent groups control high-level flow and nested mutables handle fine-grained adaptation.

### How do I pass runtime parameters to reshape logic?

Access runtime parameters inside `reshape` using the `CGRAPH_GET_GPARAM_WITH_NO_EMPTY` macro (or similar parameter accessors) to retrieve shared state objects. As shown in [`tutorial/MyGMutable/MyMutable.h`](https://github.com/chunelfeng/cgraph/blob/main/tutorial/MyGMutable/MyMutable.h), you can read parameter values at the start of `reshape` and use conditional logic to select different dependency wiring patterns based on the current data, enabling truly data-driven dynamic graphs.