[docs]classAdapter(network_gym_client.adapter.Adapter):"""network_slicing environment adapter. Args: Adapter (network_gym_client.adapter.Adapter): the base class """def__init__(self,config_json):"""Initialize the adapter. Args: config_json (json): the configuration file """super().__init__(config_json)self.env=Path(__file__).resolve().parent.nameself.size_per_feature=int(self.config_json['env_config']['num_slices'])self.num_features=3num_users=0foriteminself.config_json['env_config']['per_slice_config']['num_users']:num_users+=itemself.config_json['env_config']['num_users']=num_usersrbg_size=self.get_rbg_size(self.config_json['env_config']['lte']['resource_block_num'])self.rbg_num=self.config_json['env_config']['lte']['resource_block_num']/rbg_sizeifconfig_json['env_config']['env']!=self.env:sys.exit("[ERROR] wrong environment Adapter. Configured environment: "+str(config_json['env_config']['env'])+" != Launched environment: "+str(self.env))defget_action_space(self):"""Get action space for network_slicing env. Returns: spaces: action spaces """returnspaces.Box(low=0,high=1,shape=(self.size_per_feature,),dtype=np.float32)#consistent with the get_observation function.defget_observation_space(self):"""Get observation space for network_slicing env. Returns: spaces: observation spaces """# for network slicing, the user number is configured using the slice list. Cannot use the argument parser!returnspaces.Box(low=0,high=1000,shape=(self.num_features,self.size_per_feature),dtype=np.float32)defget_observation(self,df):"""Prepare observation for network_slicing env. This function should return the same number of features defined in the :meth:`get_observation_space`. Args: df (pd.DataFrame): the network stats measurements Returns: spaces: observation spaces """print(df)dl_cell_rb_usage=Nonedl_network_tx_rate=Nonedl_network_rate=Nonedl_network_qos_rate=Nonedl_network_delay_violation=Noneforindex,rowindf.iterrows():ifrow['source']=='lte':ifrow['name']=='dl::cell::max_rate':self.action_data_format=rowelifrow['name']=='dl::cell::rb_usage':dl_cell_rb_usage=rowelifrow['source']=='gma':ifrow['name']=='dl::network::tx_rate':dl_network_tx_rate=rowelifrow['name']=='dl::network::rate':dl_network_rate=rowelifrow['name']=='dl::network::qos_rate':dl_network_qos_rate=rowelifrow['name']=='dl::network::delay_violation':dl_network_delay_violation=rowself.wandb_log_buffer_append(self.slice_df_to_dict(dl_cell_rb_usage))self.wandb_log_buffer_append(self.slice_df_to_dict(dl_network_tx_rate))self.wandb_log_buffer_append(self.slice_df_to_dict(dl_network_rate))self.wandb_log_buffer_append(self.slice_df_to_dict(dl_network_qos_rate))self.wandb_log_buffer_append(self.slice_df_to_dict(dl_network_delay_violation))#warning, need to modify the following if use more than one base stations.observation=np.vstack([pd.json_normalize(dl_network_rate["value"])["value"].to_list(),pd.json_normalize(dl_cell_rb_usage["value"])["value"].to_list(),pd.json_normalize(dl_network_delay_violation["value"])["value"].to_list()])# print('Observation --> ' + str(observation))returnobservationdefget_policy(self,action):"""Prepare the network policy for network_slicing env. Args: action (spaces): the action from RL agent Returns: json: the network policy """# you may also check other constraints for action... e.g., min, max.# TODO: the sum of action should be smaller than 1!!!! Therefore the sum of scaled_action is smaller than the rbg_numscaled_action=np.interp(action,(0,1),(0,self.rbg_num/self.size_per_feature))scaled_action=np.round(scaled_action).astype(int)# force it to be an integer.# this function will convert the action to a nested json formatpolicy1=json.loads(self.action_data_format.to_json())policy1["name"]="drb_allocation"foriteminpolicy1["value"]:item["value"]=np.zeros(len(scaled_action)).tolist()policy2=json.loads(self.action_data_format.to_json())policy2["name"]="prb_allocation"foriteminpolicy2["value"]:item["value"]=scaled_action.tolist()policy3=json.loads(self.action_data_format.to_json())policy3["name"]="srb_allocation"foriteminpolicy3["value"]:item["value"]=list(np.ones(len(scaled_action))*self.rbg_num)policy=[policy1,policy2,policy3]# print('Action --> ' + str(policy))returnpolicydefget_reward(self,df):"""Prepare reward for the network_slicing env. Args: df (pd.DataFrame): network stats measurements Returns: spaces: reward spaces """#TODO: add a reward function for you customized envreward=0# send info to wandbself.wandb_log_buffer_append({"reward":reward})returnrewarddefslice_df_to_dict(self,df,id_name='id'):"""Transform datatype from pandas.dataframe to dictionary. Args: df (pandas.dataframe): a pandas.dataframe object description (string): a descritption for the data Returns: dict : converted data with dictionary format """ifdfisNone:return{}description=df['source']+"::"+df['name']get_key=lambdau,v:description+"::"+id_name+f'={u}'+"::slice"+f'={v}'id_list=[]slice_list=[]value_list=[]fori,iteminenumerate(df['id']):forj,subinenumerate(df['value'][i]['slice']):id_list.append(item)slice_list.append(sub)value_list.append(df['value'][i]['value'][j])#print(id_list)#print(slice_list)#print(value_list)dict_key=list(map(get_key,id_list,slice_list))#print(dict_key)#print(value_list)data=dict(zip(dict_key,value_list))#print(data)returndatadefget_rbg_size(self,bandwidth):"""Compute the resource block group size based on the bandwith (RB number). This code is coppied from ns3. PF type 0 allocation RBG Args: bandwidth (int): the resouce block number Returns: int: the resouce block group size """# PF type 0 allocation RBGPfType0AllocationRbg=[10,26,63,110]# see table 7.1.6.1-1 of 36.213foriinrange(len(PfType0AllocationRbg)):if(bandwidth<PfType0AllocationRbg[i]):return(i+1)return(-1)