# fitness.py
# This file handles interfacing the fitness calculations for a chromosome in the genetic embedding


# Internal Imports
from src.genetic_embedding.utils.fitness import regression_based, analogy_based

# External Imports
from itertools import combinations


'''
----------compute_fitness----------
- This function will compute a fitness value for the supplied chromosome
-----Inputs-----
- chromosome - The chromosome to evaluate
- fitness_scheme - The method to use to compute the fitness
-----Output-----
- fitness - A number detailing how 'fit' the chromosome is
'''
def compute_fitness(chromosome, vocab, cooccurrence={}, fitness_scheme = "", filepath = ""):
    # Decode the chromosome
    #embedding = chromosome.decode(vocab)

    # Calculate fitness based on the scheme specified
    fitness = 0.0
    award = 0.0
    penalty = 0.0
    if fitness_scheme == "regression_based":
        fitness = regression_based.calculate_fitness(chromosome, vocab, cooccurrence)
    elif fitness_scheme == "analogy_based":
        fitness = analogy_based.calculate_correctness_fitness(chromosome, vocab)
    elif fitness_scheme == "analogy_bitcount_based":
        fitness = analogy_based.calculate_bitcount_fitness(chromosome, vocab, filepath)
    else:
        embedding = chromosome.decode(vocab)
        # Default fitness calculation
        word_pairs = list(combinations(sorted(vocab), 2))
        for (word1, word2) in word_pairs:
            if word1 in cooccurrence and word2 in cooccurrence[word1]:
                #temp = bin(embedding[word1] ^ embedding[word2])[2:].count("0") # XOR 0-count
                temp = bin(int(embedding[word1], 2) ^ int(embedding[word2], 2))[2:].count("0") # XOR 0-count
                award += temp * cooccurrence[word1][word2]
        
        fitness = award - penalty

    # Return the calculated fitness
    return fitness