In this below code i am randomly generating the targets for testing and training process in the function 'generate_random_targets' and saving and loading all the necessary data's relating to the testing and training target data and number of target data's with in the training and testing loop. now i need to modify the code as, instead of generating random targets with in the ranges, i need to choose the targets from the .xlsx file (path: 'D:\OPAMP CIRCUITS\RLGNN_LTSpice\Dataset_Predict.xlsx'), where the excel file having four columns with header 'gain', 'bandwidth', 'unitygainfrequency', 'phasemargin', excluding the first row (header), the excel data has 355 rows, each row are the corresponding values of the target data which required for the below training and testing process. so i need you to read all the row data and shuffle it in row wise and select 300 row datas as training target data and 35 row data as testing target data, these training and testing data are need to be keep saved and loaded in the training and testing loop, it datas are need to be fetch from save state while it is in loading, only at the first time it is need to be setch from excel file and seperate it s test and training data (the consistancy should be maintained) no duplicate must be present between testing and trainning data, it should not be fetch from excel on every time loading. while selecting training datas and testing datas (the selection of data is row 'x' column1, row 'x' column2, row 'x' column3, row 'x' column4, 'x' is the row number the column data must be choosen from the same row for the corresponding target data.

# Define Circuit Environment
class CircuitEnvironment:
    PERFORMANCE_METRICS_TARGET_LOW = np.array([45, 10e3, 5e6, 60])
    PERFORMANCE_METRICS_TARGET_HIGH = np.array([55, 30e3, 10e6, 75])

    def __init__(self, bounds_low, bounds_high):
        # Initialization code: setup bounds

    @staticmethod
    def generate_random_targets(num_targets, seed):
        np.random.seed(seed)
        
        gain_targets = np.random.choice(np.arange(45, 56), num_targets)
        bw_targets = np.random.choice(np.arange(10e3, 30.1e3, 1e3), num_targets)
        ugf_targets = np.random.choice(np.arange(5e6, 10.1e6, 1e6), num_targets)
        pm_targets = np.random.choice(np.arange(60, 76), num_targets)
        
        random_targets = np.vstack((gain_targets, bw_targets, ugf_targets, pm_targets)).T
        return random_targets 


# save and load training process 
def save_training_state(agent, episode, rewards_log, losses_log, metrics_log, train_targets, test_targets, filepath='training_state_TrainTest7.pt'):
    state = {
        'episode': episode,
        'actor_state_dict': agent.actor.state_dict(),
        'critic_state_dict': agent.critic.state_dict(),
        'optimizer_actor_state_dict': agent.optimizer_actor.state_dict(),
        'optimizer_critic_state_dict': agent.optimizer_critic.state_dict(),
        'rewards_log': rewards_log,
        'losses_log': losses_log,
        'metrics_log': metrics_log,
        'train_targets': train_targets,
        'test_targets': test_targets
    }
    torch.save(state, filepath)

def load_training_state(filepath='training_state_TrainTest7.pt'):
    if os.path.isfile(filepath):
        state = torch.load(filepath)
        return state
    else:
        return None

# Training Function
def train(env, agent, num_episodes, max_timesteps):
    num_targets = 100
    train_targets = CircuitEnvironment.generate_random_targets(num_targets=num_targets, seed=0)
    test_targets = CircuitEnvironment.generate_random_targets(num_targets=20, seed=1)
    
    # Initialize the episode to start from and log lists
    start_episode = 0    
    rewards_log = []
    losses_log = []
    metrics_log = []
    episode_lengths = []
    
    # Attempt to load the saved state
    saved_state = load_training_state()
    if saved_state:
        start_episode = saved_state['episode'] + 1  # Start from the next episode
        agent.actor.load_state_dict(saved_state['actor_state_dict'])
        agent.critic.load_state_dict(saved_state['critic_state_dict'])
        agent.optimizer_actor.load_state_dict(saved_state['optimizer_actor_state_dict'])
        agent.optimizer_critic.load_state_dict(saved_state['optimizer_critic_state_dict'])
        rewards_log = saved_state['rewards_log']
        losses_log = saved_state['losses_log']
        metrics_log = saved_state['metrics_log']
        train_targets = saved_state['train_targets']
        test_targets = saved_state['test_targets']
        print(f"Resuming from episode {start_episode}")
        
    for episode in range(start_episode, num_episodes):
        if episode >= num_targets:
            break  # Exit the loop if exhausted the number of targets
        
        target = train_targets[episode % len(train_targets)]
        
        node_features_tensor, edge_index, performance_metrics = env.reset(target)
        state = (node_features_tensor, edge_index)
        
        # Initialize storage for episode data
        episode_rewards = []
        states = []
        actions = []
        log_probs = []
        values = []
        masks = []
        perf_metrics_log = []

        for t in range(max_timesteps):            
            action, log_prob, perf_metrics = agent.select_action(state, performance_metrics)
            next_node_features_tensor, next_edge_index, reward, done, previous_metrics = env.step(action, perf_metrics, target)
            
            next_state = (next_node_features_tensor, next_edge_index)
            
        save_training_state(agent, episode, rewards_log, losses_log, metrics_log, train_targets, test_targets)
   
    agent.save_checkpoint('final')        
   
# save and load testing process
def save_test_state(test_targets, rewards_log, metrics_log, current_target_index, filepath='test_state_TrainTest7.pt'):
    state = {
        'test_targets': test_targets,
        'rewards_log': rewards_log,
        'metrics_log': metrics_log,
        'current_target_index': current_target_index
    }
    torch.save(state, filepath)

def load_test_state(filepath='test_state_TrainTest7.pt'):
    if os.path.isfile(filepath):
        state = torch.load(filepath)
        return state
    else:
        return None

# Test Function
def test(env, agent, num_targets, max_timesteps_per_target=300, test_targets=None):
    rewards_log = []
    metrics_log = []

    # Load test state if exists
    saved_test_state = load_test_state()
    if saved_test_state:
        test_targets = saved_test_state['test_targets']
        rewards_log = saved_test_state['rewards_log']
        metrics_log = saved_test_state['metrics_log']
        start_target_index = saved_test_state['current_target_index'] + 1
        print(f"Resuming from target index {start_target_index}")
    else:
        start_target_index = 0
        if not test_targets:
            saved_state = load_training_state()
            if saved_state and 'test_targets' in saved_state:
                test_targets = saved_state['test_targets']
            else:
                test_targets = CircuitEnvironment.generate_random_targets(num_targets=num_targets, seed=1)

    for i in range(start_target_index, num_targets):
        target = test_targets[i]

        node_features_tensor, edge_index, performance_metrics = env.reset(target)
        state = (node_features_tensor, edge_index)
    
        episode_rewards = []
        states = []
        actions = []
        values = []
        masks = []
        perf_metrics_log = []
        
        done = False
        t = 0
        while not done and t < max_timesteps_per_target:
            action, log_prob, perf_metrics = agent.select_action(state, performance_metrics)
            next_node_features_tensor, next_edge_index, reward, done, previous_metrics = env.step(action, perf_metrics, target)
            state = (next_node_features_tensor, next_edge_index)
  
        # Save the test state after each target
        save_test_state(test_targets, rewards_log, metrics_log, i, filepath='test_state_TrainTest7.pt')
    
if __name__ == "__main__":
    # Initialize environment parameters
    # Define the values for bounds, and target metrics

    env = CircuitEnvironment(bounds_low, bounds_high)
    agent = PPOAgent(state_dim, action_space, lr_actor, lr_critic, gamma, gae_lambda, epsilon, policy_clip, epochs, entropy_coef)

    num_episodes = 1000
    max_timesteps = 300

    train(env, agent, num_episodes, max_timesteps)

    trained_state = load_training_state()
    if trained_state:
        agent.actor.load_state_dict(trained_state['actor_state_dict'])
        agent.critic.load_state_dict(trained_state['critic_state_dict'])

    num_test_targets = 20
    test(env, agent, num_test_targets, max_timesteps_per_target=300)