import numpy as np

# Defining function to convert from polar form to rectangular form
def convert(amplitude, angle):
    real_part = amplitude * np.cos(angle)
    imaginary_part = amplitude * np.sin(angle)
    return real_part, imaginary_part

# Function to retun 0 for square root of -ve terms
def sq_root(u):
    return np.sqrt(u) if u >= 0 else 0

# Compute hybrid vector similarity measure between 2 BCNMs
def Hybrid_Sim(A, B, lamda):
    row, column, _, _ = A.shape
    n = row * column

    Summation1 = 0  # First component 
    Summation2 = 0  # Second component 

    for i in range(row):
        for j in range(column):
            element_a = A[i,j]
            element_b = B[i,j]

            T1p, T2p = element_a[0]
            I1p, I2p = element_a[1]
            F1p, F2p = element_a[2]
            T1n, T2n = element_a[3]
            I1n, I2n = element_a[4]
            F1n, F2n = element_a[5]

            T3p, T4p = element_b[0]
            I3p, I4p = element_b[1]
            F3p, F4p = element_b[2]
            T3n, T4n = element_b[3]
            I3n, I4n = element_b[4]
            F3n, F4n = element_b[5]

            # Convert from polar to rectangular form
            a1p, b1p = convert(T1p, T2p)
            c1p, d1p = convert(I1p, I2p)
            e1p, f1p = convert(F1p, F2p)

            a1n, b1n = convert(T1n, T2n)
            c1n, d1n = convert(I1n, I2n)
            e1n, f1n = convert(F1n, F2n)

            a2p, b2p = convert(T3p, T4p)
            c2p, d2p = convert(I3p, I4p)
            e2p, f2p = convert(F3p, F4p)

            a2n, b2n = convert(T3n, T4n)
            c2n, d2n = convert(I3n, I4n)
            e2n, f2n = convert(F3n, F4n)

            positive_numerator = (sq_root(a1p * b1p * a2p * b2p) +
                                  sq_root(c1p * d1p * c2p * d2p) +
                                  sq_root(e1p * f1p * e2p * f2p))

            negative_numerator = (sq_root(a1n * b1n * a2n * b2n) +
                                  sq_root(c1n * d1n * c2n * d2n) +
                                  sq_root(e1n * f1n * e2n * f2n))

            denominator1 = (a1p * b1p + c1p * d1p + e1p * f1p +
                            a2p * b2p + c2p * d2p + e2p * f2p -
                            a1n * b1n - c1n * d1n - e1n * f1n -
                            a2n * b2n - c2n * d2n - e2n * f2n)

            denominator2 = (sq_root(a1p * b1p + c1p * d1p + e1p * f1p) +
                            sq_root(a2p * b2p + c2p * d2p + e2p * f2p) -
                            sq_root(a1n * b1n + c1n * d1n + e1n * f1n) -
                            sq_root(a2n * b2n + c2n * d2n + e2n * f2n))

            # summation components
            if denominator1 != 0:
                Summation1 += (positive_numerator - negative_numerator) / denominator1
            if denominator2 != 0:
                Summation2 += (positive_numerator - negative_numerator) / denominator2

    answer = lamda * (Summation1 / n) + (1 - lamda) * (Summation2 / n)
    return answer

# Defining function to compute weighted hybrid vector similarity measure
def Weighted_Hybrid_Sim(A, B, elements_weight, lamda):
    row, column, _, _ = A.shape
    n = row * column

    if len(elements_weight) != n:
        print("Error: Length of elements_weight must match number of matrix elements.")

    Summation1 = 0
    Summation2 = 0
    index = 0

    for i in range(row):
        for j in range(column):
            element_a = A[i,j]
            element_b = B[i,j]

            T1p, T2p = element_a[0]
            I1p, I2p = element_a[1]
            F1p, F2p = element_a[2]
            T1n, T2n = element_a[3]
            I1n, I2n = element_a[4]
            F1n, F2n = element_a[5]

            T3p, T4p = element_b[0]
            I3p, I4p = element_b[1]
            F3p, F4p = element_b[2]
            T3n, T4n = element_b[3]
            I3n, I4n = element_b[4]
            F3n, F4n = element_b[5]

            a1p, b1p = convert(T1p, T2p)
            c1p, d1p = convert(I1p, I2p)
            e1p, f1p = convert(F1p, F2p)

            a1n, b1n = convert(T1n, T2n)
            c1n, d1n = convert(I1n, I2n)
            e1n, f1n = convert(F1n, F2n)

            a2p, b2p = convert(T3p, T4p)
            c2p, d2p = convert(I3p, I4p)
            e2p, f2p = convert(F3p, F4p)

            a2n, b2n = convert(T3n, T4n)
            c2n, d2n = convert(I3n, I4n)
            e2n, f2n = convert(F3n, F4n)

            positive_numerator = (sq_root(a1p * b1p * a2p * b2p) +
                                  sq_root(c1p * d1p * c2p * d2p) +
                                  sq_root(e1p * f1p * e2p * f2p))

            negative_numerator = (sq_root(a1n * b1n * a2n * b2n) +
                                  sq_root(c1n * d1n * c2n * d2n) +
                                  sq_root(e1n * f1n * e2n * f2n))

            denominator1 = (a1p * b1p + c1p * d1p + e1p * f1p +
                            a2p * b2p + c2p * d2p + e2p * f2p -
                            a1n * b1n - c1n * d1n - e1n * f1n -
                            a2n * b2n - c2n * d2n - e2n * f2n)

            denominator2 = (sq_root(a1p * b1p + c1p * d1p + e1p * f1p) +
                            sq_root(a2p * b2p + c2p * d2p + e2p * f2p) -
                            sq_root(a1n * b1n + c1n * d1n + e1n * f1n) -
                            sq_root(a2n * b2n + c2n * d2n + e2n * f2n))

            if denominator1 != 0:
                Summation1 += elements_weight[index] * (positive_numerator - negative_numerator) / denominator1
            if denominator2 != 0:
                Summation2 += elements_weight[index] * (positive_numerator - negative_numerator) / denominator2

            index += 1

    answer = lamda * Summation1 + (1 - lamda) * Summation2
    return answer

# Entering example matrices
A = np.array([
    [[(0.1, 0.7), (0.4, 2.0), (0.9, 2.5), (-0.6, -1.5), (-0.2, -1.3), (-0.4, -1.6)],
        [(0.7, 0.6), (0.7, 1.4), (0.5, 1.8), (-0.4, -1.7), (-0.4, -2.2), (-0.3, -1.5)]],
])

B = np.array([
    [ [(0.4, 0.8), (0.2, np.pi/6), (0.4, 0.1), (-0.5, -np.pi/2), (-0.6, -np.pi/4), (-0.4, -0.2)],
        [(0.2, 0.4), (0.3, np.pi/4), (0.4, 0.7), (-0.8, -np.pi/6), (-0.2, -np.pi/4), (-0.2, -0.9)]],
])

elements_weight = np.array([0.5, 0.5])
lamda = 0.6

Hybrid_vector = Hybrid_Sim(A, B, lamda)
print("The hybrid vector similarity measure between the entered BCNMs is\n", Hybrid_vector)

Weighted_hybrid_vector = Weighted_Hybrid_Sim(A, B, elements_weight, lamda)
print("The weighted jaccard similarity measure between the entered BCNMs is\n", Weighted_hybrid_vector)


