import numpy as np

def dist_matrix_creator(matrix, distance):
    n = len(matrix)
    dist_matrix = np.zeros((n, n))
    for i in range(n):
        for j in range(i+1, n):
            dist_matrix[i][j] = distance(matrix[i], matrix[j])
            dist_matrix[j][i] = dist_matrix[i][j]
    return dist_matrix

def diameter(n, clusters, cluster_number, distance):
    max_distance = 0
    for i in range(n):
        for j in range(i+1, n):
            if clusters[i] == cluster_number and clusters[j] == cluster_number:
                actual_distance = distance[i][j]
                if actual_distance > max_distance:
                    max_distance = actual_distance
                
    return max_distance

def max_diameter(n, clusters, k, distance):
    max_diam = 0
    for cluster_number in range(1,k+1):
        actual_diameter = diameter(n, clusters, cluster_number, distance)
        if actual_diameter > max_diam:
            max_diam = actual_diameter
    return max_diam

def avg_within_cluster(n, clusters, cluster_number, distance):
    total_distance = 0
    count = 0
    for i in range(n):
        for j in range(i+1, n):
            if clusters[i] == cluster_number and clusters[j] == cluster_number:
                total_distance += distance[i][j]
                count += 1
    if count == 0:
        return 0
    return total_distance / count

def max_avg_within_cluster(n, clusters,k, distance):
    max_avg = 0
    for cluster_number in range(1,k+1):
        actual_avg = avg_within_cluster(n, clusters, cluster_number, distance)
        if actual_avg > max_avg:
            max_avg = actual_avg
    return max_avg

def avg_between_cluster(n, clusters, cluster_A, cluster_B, distance):
    total_distance = 0
    count = 0
    for i in range(n):
        if not (clusters[i] == cluster_A):
            continue
        for j in range(n):
            if clusters[j] == cluster_B:
                total_distance += distance[i][j]
                count += 1
    if count == 0:
        return 0
    return total_distance / count

def avg_separation(n, clusters, k, distance):
    total_distance = 0
    count = 0
    for i in range(1,k+1):
        for j in range(i+1,k+1):
            total_distance += avg_between_cluster(n, clusters, i, j, distance)
            count += 1
    if count == 0:
        return 0
    return total_distance / count

def min_separation(n, clusters, k, distance):
    min_sep = float('inf')
    for i in range(1,k+1):
        for j in range(i+1,k+1):
            actual_sep = avg_between_cluster(n, clusters, i, j, distance)
            if actual_sep < min_sep:
                min_sep = actual_sep
    return min_sep

## For now, we will just use the same name as in the article

def max_diam(n, clusters, k, distance):
    return max_diameter(n, clusters, k, distance)

def max_avg(n, clusters, k, distance):
    return max_avg_within_cluster(n, clusters, k, distance)

def sep_avg(n, clusters, k, distance):
    return avg_separation(n, clusters, k, distance)

def sep_min(n, clusters, k, distance):
    return min_separation(n, clusters, k, distance)

def cs_ratio_AV(n, clusters, k, distance):
    return max_avg(n, clusters, k, distance) / sep_min(n, clusters, k, distance)

def cs_ratio_DM(n, clusters, k, distance):
    return max_diam(n, clusters, k, distance) / sep_min(n, clusters, k, distance)
