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 cosine similarity measure between 2 BCNMs
def cos_sim(A, B):
    row, column, _, _ = A.shape
    n = row * column

    summation = 0

    for i in range(row):
        for j in range(column):
            element_a = A[i,j]
            element_b = B[i,j]

            # Membership functions
            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]

            # Polar form 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))

            positive_denominator = sq_root(a1p * b1p + c1p * d1p + e1p * f1p) * sq_root(a2p * b2p + c2p * d2p + e2p * f2p)
            negative_denominator = sq_root(a1n * b1n + c1n * d1n + e1n * f1n) * sq_root(a2n * b2n + c2n * d2n + e2n * f2n)

            final_numerator = positive_numerator - negative_numerator
            final_denominator = 4 * (positive_denominator - negative_denominator)

            if final_denominator != 0:
                similarity_measure = final_numerator / final_denominator
            else:
                similarity_measure = 0

            summation += similarity_measure

    return summation / n

# Defining function to compute weighted cosine similarity measure
def weighted_cos_sim(A, B, elements_weight):
    row, column, _, _ = A.shape
    n = row * column

    if len(elements_weight) != n:
        raise ValueError("Length of the elements_weight should be equal to the total number of elements in the matrix.")

    summation = 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))

            positive_denominator = sq_root(a1p * b1p + c1p * d1p + e1p * f1p) * sq_root(a2p * b2p + c2p * d2p + e2p * f2p)
            negative_denominator = sq_root(a1n * b1n + c1n * d1n + e1n * f1n) * sq_root(a2n * b2n + c2n * d2n + e2n * f2n)

            final_numerator = positive_numerator - negative_numerator
            final_denominator = 4 * (positive_denominator - negative_denominator)

            if final_denominator != 0:
                similarity_measure = final_numerator / final_denominator
            else:
                similarity_measure = 0

            summation += elements_weight[index] * similarity_measure
            index += 1

    return summation

# Entering example matrix
A = np.array([
    [
        [(0.2, 0.6), (0.4, 2.0), (0.8, 2.5), (-0.6, -1.5), (-0.2, -1.3), (-0.4, -1.6)],
        [(0.2, 0.9), (0.7, 1.3), (0.6, 1.8), (-0.5, -0.7), (-0.4, -1.2), (-0.3, -1.5)]
    ],
    [
        [(0.5, 0.8), (0.5, np.pi/4), (0.2, np.pi), (-0.2, -np.pi/3), (-0.9, -np.pi/2), (-0.2, 0)],
        [(0.7, 0.6), (0.6, np.pi/2), (0.6, 0.7), (-0.7, -np.pi/2), (-0.5, -np.pi/3), (-0.4, -0.1)]
    ]
])

B = np.array([
    [
        [(0.5, 0.1), (0.8, np.pi), (0.7, 0.9), (-0.2, -np.pi/2), (-0.2, -3*np.pi/4), (-0.2, -0.9)],
        [(0.8, 0.5), (0.4, np.pi/6), (0.6, 0.4), (-0.8, -np.pi/6), (-0.1, -np.pi/3), (-0.7, 2)]
    ],
    [
        [(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)]
    ]
])
# Giving elements_weight for all the elements 
elements_weight = np.array([0.25, 0.25, 0.25, 0.25])  

Cosine_Similarity = cos_sim(A, B)  # Calling cosine function
print("The cosine similarity measure between the entered BCNMs is\n", Cosine_Similarity)

Weighted_Cos_Similarity = weighted_cos_sim(A, B, elements_weight)  # Calling weighted cosine function
print("The weighted cosine similarity measure between the entered BCNMs is\n", Weighted_Cos_Similarity)
