i need you to alter the implemented 'calculate_reward' function based on the new criteria's as given below,
first need to check 'transistor_regions', 
here i have total 8 transistor regions, 'transistor_regions' is present transistor region result and 'previous_transistor_regions' is previous transistor region result.
if 'all_in_saturation = all(region == 2 for region in transistor_regions.values())' is satisfied then give reward 100.
else check 'current_region_count = count_regions(transistor_regions, 2)', '(len(transistor_regions)' and 'previous_region_count = count_regions(previous_transistor_regions, 2)', 
    if current_region_count = previous_region_count AND 'all_in_saturation' is NOT satisfied, then give penalty based on (len(transistor_regions) - current_region_count),
    if current_region_count > previous_region_count, then give reward based on how much 'current_region_count' is increased than 'previous_region_count',
    if current_region_count < previous_region_count, then give penalty based on the cumulative computation of how much 'current_region_count' is decreased than 'previous_region_count' and (len(transistor_regions) - current_region_count),

next we need to check the 'performance_metrics' (c_metrics, p_metrics),
Here i have 7 performance metrics values for variables ['Area', 'PowerDissipation', 'SlewRate', 'Gain', 'Bandwidth3dB', 'UnityGainFreq', 'PhaseMargin'], where 'c_metrics' is the result of present performance metrics and 'p_metrics' is the result of previous performance metrics.
each performance metrics variables has its own target bounds 'PERFORMANCE_METRICS_TARGET_LOW', 'PERFORMANCE_METRICS_TARGET_HIGH'

for the performance metrics 'Area', 'PowerDissipation',
check if 'c_metrics' < 'p_metrics',    
    if the 'c_metrics' is lesser than the 'PERFORMANCE_METRICS_TARGET_LOW', then give large reward,
    if the 'c_metrics' is lesser than the 'PERFORMANCE_METRICS_TARGET_HIGH' , then give reward,
else check if the 'p_metrics' greater than 'PERFORMANCE_METRICS_TARGET_HIGH' AND 'c_metrics' is less than the 'PERFORMANCE_METRICS_TARGET_HIGH', then give very large reward,
else check if 'c_metrics' > 'PERFORMANCE_METRICS_TARGET_HIGH', then give large penalty,

for the performance metrics 'SlewRate', 'Gain', 'Bandwidth3dB', 'UnityGainFreq',
check if 'c_metrics' > 'p_metrics',    
    if the 'c_metrics' is greater than the 'PERFORMANCE_METRICS_TARGET_HIGH', then give large reward,
    if the 'c_metrics' is greater than the 'PERFORMANCE_METRICS_TARGET_LOW' , then give reward,
else check if the 'p_metrics' lesser than 'PERFORMANCE_METRICS_TARGET_LOW' AND 'c_metrics' is greater than the 'PERFORMANCE_METRICS_TARGET_LOW', then give very large reward,
else check if 'c_metrics' < 'PERFORMANCE_METRICS_TARGET_LOW', then give large penalty,
    
for the performance metrics 'PhaseMargin',
check if ('PERFORMANCE_METRICS_TARGET_LOW' <= 'c_metrics' <= 'PERFORMANCE_METRICS_TARGET_HIGH') AND (('p_metrics' < 'PERFORMANCE_METRICS_TARGET_LOW') OR ('p_metrics' > 'PERFORMANCE_METRICS_TARGET_HIGH')), then give very large reward,
if 'PERFORMANCE_METRICS_TARGET_LOW' <= 'c_metrics' <= 'PERFORMANCE_METRICS_TARGET_HIGH' AND 'PERFORMANCE_METRICS_TARGET_LOW' <= 'p_metrics' <= 'PERFORMANCE_METRICS_TARGET_HIGH', then give large reward,
if ('c_metrics' < 'p_metrics' AND 'c_metrics' < 'PERFORMANCE_METRICS_TARGET_LOW') OR ('c_metrics' > 'p_metrics' AND 'c_metrics' > 'PERFORMANCE_METRICS_TARGET_HIGH'), then give very large penalty, else ('PERFORMANCE_METRICS_TARGET_LOW' is NOT less than or equal to 'c_metrics' is NOT less than or equal to 'PERFORMANCE_METRICS_TARGET_HIGH'), then give large penalty.

if performance metrics 'Gain' < 0, then give penalty = 100


CircuitEnvironment.PERFORMANCE_METRICS_TARGET_LOW = np.array([1e-12, 0.005, 10, 48, 30e3, 30e6, 60])
CircuitEnvironment.PERFORMANCE_METRICS_TARGET_HIGH = np.array([1e-10, 0.25, 60, 100, 100e3, 100e6, 75])


    def is_performance_metrics_in_target(self, metrics):
        return np.all(metrics >= self.PERFORMANCE_METRICS_TARGET_LOW) and np.all(metrics <= self.PERFORMANCE_METRICS_TARGET_HIGH)      


    def calculate_reward(self, c_metrics, p_metrics, transistor_regions, previous_transistor_regions):
            metrics_order = ['Area', 'PowerDissipation', 'SlewRate', 'Gain', 'Bandwidth3dB', 'UnityGainFreq', 'PhaseMargin']
            
            reward = 0
        
            all_in_saturation = all(region == 2 for region in transistor_regions.values())
            print("all_in_saturation:", all_in_saturation)
            print("transistor regions:", transistor_regions)
            if all_in_saturation:
                reward += 200
                
            
            def count_regions(region_dict, target):
                return sum(1 for region in region_dict.values() if region == target)
            
            current_region_count = count_regions(transistor_regions, 2)
            previous_region_count = count_regions(previous_transistor_regions, 2)
            
            if current_region_count > previous_region_count:
                reward += 10 * (current_region_count - previous_region_count)
            elif current_region_count < previous_region_count:
                reward -= 10 * (previous_region_count - current_region_count) + self.LARGE_PENALTY * (len(transistor_regions) - current_region_count)
            
            current_metrics = np.array([c_metrics[k] for k in metrics_order])
            
            performance_metrics_in_target = self.is_performance_metrics_in_target(current_metrics)
            
            if performance_metrics_in_target:
                reward += 200
                return reward    
           
            for idx, metric_name in enumerate(metrics_order):
                current_value = c_metrics[metric_name]
                previous_value = p_metrics[metric_name]
                target_low = self.PERFORMANCE_METRICS_TARGET_LOW[idx]
                target_high = self.PERFORMANCE_METRICS_TARGET_HIGH[idx]
                
                if metric_name in ['Area', 'PowerDissipation']:
                    if current_value < previous_value:
                        reward += self.SMALL_REWARD
                        if current_value < target_low:
                            reward += self.LARGE_REWARD
                    elif current_value > target_high:
                        reward -= self.LARGE_PENALTY
                
                elif metric_name in ['SlewRate', 'Gain', 'Bandwidth3dB', 'UnityGainFreq']:
                    if current_value > previous_value:
                        reward += self.SMALL_REWARD
                        if current_value > target_high:
                            reward += self.LARGE_REWARD
                    elif current_value < target_low:
                        reward -= self.LARGE_PENALTY
                
                elif metric_name == 'PhaseMargin':
                    if target_low <= current_value <= target_high:
                        reward += self.LARGE_REWARD
                    else:
                        reward -= self.LARGE_PENALTY
                        
                if metric_name == 'Gain' and current_value < 0:
                    reward -= 200
            
            return reward