import numpy as np


M = 5  
p = 10  


local_gradients = [np.random.rand(p) for _ in range(M)]  
global_gradient = np.mean(local_gradients, axis=0)  


def gradient_square_sum(gradients):
    return sum([np.linalg.norm(g)**2 for g in gradients]) / M


def global_gradient_square(global_grad):
    return np.linalg.norm(global_grad)**2

def calculate_H2(local_grads, global_grad, B_squared):
    H_squared = 0
    for grad in local_grads:
        H_squared += (np.linalg.norm(grad)**2 - B_squared * np.linalg.norm(global_grad)**2)
    return H_squared / M

def calculate_B_and_H(local_grads, global_grad):

    local_grad_square_sum = gradient_square_sum(local_grads)


    global_grad_square_sum = global_gradient_square(global_grad)

    B_squared = local_grad_square_sum / global_grad_square_sum


    H_squared = calculate_H2(local_grads, global_grad, B_squared)


    return np.sqrt(B_squared), np.sqrt(H_squared)

B, H = calculate_B_and_H(local_gradients, global_gradient)
print(local_gradients, global_gradient)

print(f"B: {B}, H: {H}")
