Provide me complete code for Custom GNN with GAT for the below given detail requirement and constraints in my needed implementation,
from the environment, i am already having the required node feature tensor, edge feature tensor and edge indices.

node_features_tensor, edge_feature_tensor, edge_index, performance_metrics = env.reset()

in node feature tensor contains the tensor data of all 20 nodes, and its associated 24 node features, where it contains the preprocessed node features of the string data are one hot encoded and scalar datas are normalized between 0 to 1. use it as a state input data in to the model.

the selective tunable 11 component nodes (‘M0’ to ‘M7’, ‘C0’, ‘I0’, ‘V1’) to be identify from the node features we need to identify from its index number respectively, for component ‘M0’ has index number [7] with value '1.0000', ‘M1’ has index number [8] with value '1.0000', ‘M2’ has index number [9] with value '1.0000', ‘M3’ has index number [10] with value '1.0000', ‘M4’ has index number [11] with value '1.0000', ‘M5’ has index number [12] with value '1.0000', ‘M6’ has index number [13] with value '1.0000', ‘M7’ has index number [14] with value '1.0000', ‘C0’ has index number [15] with value '1.0000', ‘I0’ has index number [16] with value '1.0000', ‘V1’ has index number [17] with value '1.0000',

selective features from the selected 11 componentnodes need to be identify from the below selection process,
component nodes ‘M0’ to ‘M7’, has dimensions (width and length) two features for each nodes to be tune and the component nodes 'C0', 'I0', 'V1' has component values (one feature for each node) to be tune.

Among the selected component nodes we need to tune only the selected features, it can be identify by,
for component ‘M0’ has index number [7] with value '1.0000', we need to tune only the values of the features at its indices [18] [19],
for component ‘M1’ has index number [8] with value '1.0000', we need to tune only the values of the features at its indices [18] [19],
for component ‘M2’ has index number [9] with value '1.0000', we need to tune only the values of the features at its indices [18] [19],
for component ‘M3’ has index number [10] with value '1.0000', we need to tune only the values of the features at its indices [18] [19],
for component ‘M4’ has index number [11] with value '1.0000', we need to tune only the values of the features at its indices [18] [19],
for component ‘M5’ has index number [12] with value '1.0000', we need to tune only the values of the features at its indices [18] [19],
for component ‘M6’ has index number [13] with value '1.0000', we need to tune only the values of the features at its indices [18] [19],
for component ‘M7’ has index number [14] with value '1.0000', we need to tune only the values of the features at its indices [18] [19],
for component ‘C0’ has index number [15] with value '1.0000', we need to tune only the values of the features at its index [20],
for component ‘I0’ has index number [16] with value '1.0000', we need to tune only the values of the features at its index  [21],
for component ‘V1’ has index number [17] with value '1.0000', we need to tune only the values of the features at its index  [22],

Among ('M0' to 'M7') We have three set pairs of component nodes (‘M0’ and ‘M1’, ‘M2’ and ‘M3’, ‘M4’ and ‘M7’) which always needs to be tune with synchronus values between each other.

to achive synchronus tuning on,
for component ‘M0’ with index number [7] and for component ‘M1’ with index number [8], we need to tune same values at its indices [18] [19],
for component ‘M2’ with index number [9] and for component ‘M3’ with index number [10], we need to tune same values at its indices [18] [19],
for component ‘M4’ with index number [11] and for component ‘M7’ with index number [14], we need to tune same values at its indices [18] [19].

remaining components 'M5', 'M6', 'C0', 'I0', and 'V1' doesnot have any synchronize constraints it can keep its own tuned values.

### Designing the Custom GNN Model with continuous action space:

1. Dynamic Feature Processing: The GNN(GAT) should be designed to specifically handle dynamic features while leaving static features and net nodes unchanged. This might imply having a custom forward method that selectively processes parts of the input feature tensor. This version specifically processes dynamic features index [18, 19] (and, depending on the specific component node, index [20], [21], [22]) for action space parameters within component nodes.

2. Maintaining Original Features: Ensure that the static parts of the feature tensor are simply passed through the network without any modification. This can be achieved through careful programming in the forward pass or by using no-op (no operation) layers for static features. For both component and net nodes, static features remain unchanged. The entire node features matrix is initialized to hold original features, and only the dynamic features of component nodes are processed through the GAT layer.

3. Component and Net Node Handling & Synchronous Tuning: Component node features are selectively updated based on the action space parameters. Net nodes and static features of component nodes are left unchanged, fulfilling the requirement to keep net nodes and other static component node features static during the training process. For components that need synchronized tuning (M0 with M1, M2 with M3, and M4 with M7), you might encode a custom layer or mechanism that enforces the same updated values for the specified feature indices. This could involve averaging the gradients for these indices across the synchronized components before applying the update, or sharing the same parameters for these specific features during the forward pass.

- Need to Ensure that the node_features tensor passed to the GNN model in the forward method is complete and accounts for all nodes(11 component nodes with dynamic features are alone need to be tune and 9 net nodes with static features need to be keep static) before passing it to the GNN layers.
- Back propogation need only to tune the specific dynamic features among all other features in the 11 component nodes and 9 net nodes features need not get change in the backpropogation which are completely static during training process.
- imput layer with complete node feature tensor of 20 nodes and output layer with the required tuned selected features from the selected 11 component nodes.

### Custom Training Loop:

1. Forward Pass: Run the input through the GNN model. Ensure that the model is designed to accommodate both static and dynamic features appropriately.

***Implementation Procedure:

1. Masking Unmodifiable Features and Nodes
To implement your requirement, you could use a masking approach where you apply a mask to the gradient updates during backpropagation to prevent updates to certain nodes and certain features within nodes. This would effectively make those parts of the data static throughout the training process.
- Node-level Masking: Create a binary mask that identifies which nodes are tunable (1) and which are not (0). This mask can be applied to ensure that gradient updates are only applied to your selected 11 nodes during backpropagation.
- Feature-level Masking: Similarly, for each of the tunable nodes, create a mask for the 24 features indicating which features are tunable (1) and which should remain static (0). These masks ensure that only selected features of the 11 nodes receive gradient updates.