My undirected bipartite miltigraph is having two set of nodes which is formed in two sides of the graph, one side of the nodes are components (11 components) and another side of the nodes are nets (9 nets), totally we have 20 nodes, and the components and the nets of the opposite sides are connected by the edges, we have totally 40 edges between components and nets. among this total edges few of the edges connected from the transistor components are in parallel edge(edge connected between same component and nets).
Structure of my state inputs from graph data for RL GNN architecture model:
State reperesentation:
My implementation for getting the State reperesentation is shown below for your understanding.

node_features_tensor:
device_type = [0] if data.get('device_type') in ['transistor', 'passive', 'current_source', 'voltage_source'] else [1]
        device_map = {'NMOS': [1, 0, 0, 0, 0, 0], 'PMOS': [0, 1, 0, 0, 0, 0], 'C': [0, 0, 1, 0, 0, 0], 
                      'I': [0, 0, 0, 1, 0, 0], 'V': [0, 0, 0, 0, 1, 0], 'net': [0, 0, 0, 0, 0, 1] 
                      }
        component_index_map = {'M0': [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'M1': [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
                               'M2': [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], 'M3': [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
                               'M4': [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], 'M5': [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
                               'M6': [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], 'M7': [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
                               'C0': [0]*8 + [1, 0, 0],  
                               'I0': [0]*9 + [1, 0], 'V1': [0]*10 + [1], 'net': [0]*11}
        
        component_onehot = component_index_map.get(node, [0]*11)  # Defaults to all zeros for unmatched nodes
        device_onehot = device_map.get(data.get('vertex_type', 'net'), [0, 0, 0, 0, 0, 1])  # Defaults to 'net'

        # Construct the feature vector
        feature_vector = device_type + device_onehot + component_onehot + values 
        # values are the scalar values of circuit design parameters 'w_value', 'l_value', 'C_value', 'I_value', 'V_value' 
        node_features.append(feature_vector)
    
    # Convert to Tensor
    node_features_tensor = torch.FloatTensor(node_features)

sample node_features_tensor of one of my total 20 nodes,
node_features_tensor tensor([[0.0000, 1.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
         0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 1.0000, 0.0000, 0.0000, 0.0000,
         0.2150, 0.3015, 0.0000, 0.0000, 0.0000]

Among these total 20 nodes, we have 11 component nodes and 9 net nodes, it can be read from the 'device_type' in feature vector, if it is '0.0000', then it is component node and if it is '1.0000', then it is net node. The 11 component nodes are 'M0', 'M1', 'M2', 'M3', 'M4', 'M5', 'M6', 'M7', 'C0', 'I0', 'V1', which can be recognize with the corresponding one hot representation in the 'component_onehot' in feature vector. Here the ultimate optimization process is to optimaly tune the vlaues of 'w_value', 'l_value', 'C_value', 'I_value', 'V_value' corresponding to the each 'component_onehot'(11 component nodes). normalized scalar 'values' of 'w_value', 'l_value' are belongs to the components 'M0', 'M1', 'M2', 'M3', 'M4', 'M5', 'M6', 'M7'and normalized scalar 'values' of 'C_value', 'I_value', and 'V_value' are belongs to the components 'C0', 'I0', 'V1' respectively. 
Additional constraint requirements to be must follow by the GNN nodes(11 component nodes), 
the values of 'w_value', 'l_value' of component 'M0' and 'M1' must tune with same values as 'w1_value', 'l1_value', 
the values of 'w_value', 'l_value' of component 'M2' and 'M3' must tune with same values as 'w3_value', 'l3_value',
the values of 'w_value', 'l_value' of component 'M4' and 'M7' must tune with same values as 'w5_value', 'l5_value',
the values of 'w_value', 'l_value' of component 'M5', must tune with values as 'w6_value', 'l6_value',
the values of 'w_value', 'l_value' of component 'M5', must tune with values as 'w7_value', 'l7_value',
the values of 'C_value' of component 'C0', must tune with values as 'Cc_value',
the values of 'I_value' of component 'I0', must tune with values as 'Ib_value',
the values of 'V_value' of component 'V1', must tune with values as 'Vc_value',

after tuned the above said values by the GNN model at the output we can get the 13 action space values corresponding to the parameters ['w1_value', 'l1_value', 'w3_value', 'l3_value', 'w5_value', 'l5_value', 'w6_value', 'l6_value', 'w7_value', 'l7_value', 'Cc_value', 'Ib_value', 'Vc_value']

after getting output from the GNN model we need to rearrange the action space of 13 values by ['l1_value', 'l3_value', 'l5_value', 'w6_value', 'l6_value', 'w7_value', 'l7_value', 'w1_value', 'w3_value', 'w5_value', 'Ib_value', 'Cc_value', 'Vc_value']

another State reperesentation:
In my graph structure, where i have parallel edges between two same nodes, for the Mosfet transistor (considered as one component node) having four terminals D, G, S, B, among the four terminal, the terminals D and S are connected to the same nets, which makes the two edges parallel between the same component node and nets (these parallel edge may wrongly considered as self loop by the model)
Edge feature tensor(edge_embeddings):
edge features are having high dimentional values so i used embedding technique to reduce each feature dimensions,
# Mapping dictionaries for categorical variables
device_type_mapping = {'NMOS': 0, 'PMOS': 1, 'R': 2, 'L': 3, 'C': 4, 'I': 5, 'V': 6}
device_mapping = {'M0': 0, 'M1': 1, 'M2': 2, 'M3': 3, 'M4': 4, 'M5': 5, 'M6': 6, 'M7': 7,
                  'C0': 8, 'I0': 9, 'V1': 10}
terminal_mapping = {'D0': 0, 'G0': 1, 'S0': 2, 'B0': 3, 'D1': 4, 'G1': 5, 'S1': 6, 'B1': 7,
                    'D2': 8, 'G2': 9, 'S2': 10, 'B2': 11, 'D3': 12, 'G3': 13, 'S3': 14, 'B3': 15,
                    'D4': 16, 'G4': 17, 'S4': 18, 'B4': 19, 'D5': 20, 'G5': 21, 'S5': 22, 'B5': 23,
                    'D6': 24, 'G6': 25, 'S6': 26, 'B6': 27, 'D7': 28, 'G7': 29, 'S7': 30, 'B7': 31,
                    'C0': 32, 'I0': 33, 'V1': 34}
edge_colors_mapping = {'blue': 0, 'red': 1, 'green': 2, 'grey': 3, 'yellow': 4, 'black': 5}
parallel_edges_mapping = {'T': 0, 'F': 1}
net_mapping = {'net1': 0, 'net2': 1, 'net3': 2, 'IN1': 3, 'IN2': 4, 'VOUT': 5, 'Vbias': 6, '0': 7, 'vdd!': 8}

# Define the embedding dimensions for each edge feature
device_type_embedding_dim = 2
device_embedding_dim = 2
net_embedding_dim = 2
terminal_name_embedding_dim = 3
edge_pairs_embedding_dim = 3
edge_colors_embedding_dim = 2
parallel_edges_embedding_dim = 2

# Create embedding layers for each edge feature
device_type_embedding = nn.Embedding(num_embeddings=7, embedding_dim=device_type_embedding_dim)
device_embedding = nn.Embedding(num_embeddings=15, embedding_dim=device_embedding_dim)
net_embedding = nn.Embedding(num_embeddings=9, embedding_dim=net_embedding_dim)
terminal_name_embedding = nn.Embedding(num_embeddings=39, embedding_dim=terminal_name_embedding_dim)
edge_pairs_embedding = nn.Embedding(num_embeddings=40, embedding_dim=edge_pairs_embedding_dim)
edge_colors_embedding = nn.Embedding(num_embeddings=6, embedding_dim=edge_colors_embedding_dim)
parallel_edges_embedding = nn.Embedding(num_embeddings=2, embedding_dim=parallel_edges_embedding_dim)


# Function to map categorical values to numerical indices
def map_categorical_to_index(feature_value, mapping_dict):
    if feature_value in mapping_dict:
        return mapping_dict[feature_value]
    else:
        return -1  # Handle unknown values

# Function to create embeddings for edge features
def get_edge_embeddings(edge_features):
    embeddings = []
    for edge in edge_features:
        device_type_index = map_categorical_to_index(edge['device_type'], device_type_mapping)

        device_index = map_categorical_to_index(edge['device'], device_mapping)

        terminal_index = map_categorical_to_index(edge['terminal_name'], terminal_mapping)

        net_index = map_categorical_to_index(edge['nets'], net_mapping)

        net_embed = net_embedding(torch.tensor(net_index))        

        edge_colors_index = map_categorical_to_index(edge['edge_colors'], edge_colors_mapping)

        parallel_edges_index = map_categorical_to_index(edge['Parallel edges present'], parallel_edges_mapping)
        
        device_type_embed = device_type_embedding(torch.tensor(device_type_index))
        device_embed = device_embedding(torch.tensor(device_index))
        terminal_name_embed = terminal_name_embedding(torch.tensor(terminal_index))
        edge_colors_embed = edge_colors_embedding(torch.tensor(edge_colors_index))
        parallel_edges_embed = parallel_edges_embedding(torch.tensor(parallel_edges_index))
        edge_pair_embed = torch.cat([device_embed, net_embed], dim=0)
        edge_embed = torch.cat([device_type_embed, device_embed, terminal_name_embed, edge_colors_embed, parallel_edges_embed, edge_pair_embed], dim=0)
        embeddings.append(edge_embed)
    
    return embeddings

sample edge_embeddings of one of my total 38 edges
edge_embeddings [tensor([ 0.7124, -0.1579,  2.0348,  0.4799,  2.0526, -0.9357,  0.2265,  2.0741,
         0.5741,  1.6283, -1.4729,  2.0348,  0.4799, -0.9982, -0.4223]

Here the 'device_embed' in 'edge_embed'(edge features) are belongs to the corresponding 11 components 'M0', 'M1', 'M2', 'M3', 'M4', 'M5', 'M6', 'M7', 'C0', 'I0', 'V1', and the 'edge_pair_embed' are the edge pairs corresponding to the respective edge among total 40 edges connected between the 11 components and 9 nets.