import numpy as np
from typing import List, Tuple, Callable
import random

class CoTFunSearch:
    def __init__(self, llm_function: Callable, 
                 num_thoughts: int = 5, 
                 population_size: int = 10, 
                 generations: int = 50,
                 mutation_rate: float = 0.1,
                 crossover_rate: float = 0.7):
        self.llm_function = llm_function
        self.num_thoughts = num_thoughts
        self.population_size = population_size
        self.generations = generations
        self.mutation_rate = mutation_rate
        self.crossover_rate = crossover_rate
        
    def generate_thought(self) -> str:
        # В реальном сценарии здесь бы использовалась LLM для генерации мысли
        return self.llm_function("Generate a thought")
    
    def evaluate_chain(self, chain: List[str]) -> float:
        # Оценка цепочки мыслей. В реальном сценарии здесь могла бы быть 
        # более сложная логика оценки, возможно, с использованием LLM
        coherence = self.llm_function(f"Evaluate coherence of: {' -> '.join(chain)}")
        return float(coherence)  # Предполагаем, что LLM возвращает число от 0 до 1
    
    def mutate(self, chain: List[str]) -> List[str]:
        if random.random() < self.mutation_rate:
            index = random.randint(0, len(chain) - 1)
            chain[index] = self.generate_thought()
        return chain
    
    def crossover(self, parent1: List[str], parent2: List[str]) -> Tuple[List[str], List[str]]:
        if random.random() < self.crossover_rate:
            point = random.randint(1, len(parent1) - 1)
            child1 = parent1[:point] + parent2[point:]
            child2 = parent2[:point] + parent1[point:]
            return child1, child2
        return parent1, parent2
    
    def select_parents(self, population: List[List[str]], fitnesses: List[float]) -> Tuple[List[str], List[str]]:
        total_fitness = sum(fitnesses)
        probabilities = [f / total_fitness for f in fitnesses]
        parent1 = random.choices(population, weights=probabilities)[0]
        parent2 = random.choices(population, weights=probabilities)[0]
        return parent1, parent2
    
    def evolve_chain_of_thought(self, initial_prompt: str) -> List[str]:
        # Инициализация популяции
        population = [[self.generate_thought() for _ in range(self.num_thoughts)] for _ in range(self.population_size)]
        
        for generation in range(self.generations):
            # Оценка популяции
            fitnesses = [self.evaluate_chain(chain) for chain in population]
            
            # Выбор лучшей цепочки
            best_chain = population[np.argmax(fitnesses)]
            best_fitness = max(fitnesses)
            
            print(f"Generation {generation + 1}, Best Fitness: {best_fitness}")
            print("Best Chain:", " -> ".join(best_chain))
            
            # Создание новой популяции
            new_population = [best_chain]  # Элитизм
            
            while len(new_population) < self.population_size:
                parent1, parent2 = self.select_parents(population, fitnesses)
                child1, child2 = self.crossover(parent1, parent2)
                new_population.extend([self.mutate(child1), self.mutate(child2)])
            
            population = new_population[:self.population_size]
        
        return best_chain

# Пример использования
def mock_llm(prompt: str) -> str:
    # Это мок-функция, имитирующая работу LLM
    if "Generate a thought" in prompt:
        return random.choice(["Think deeply", "Analyze context", "Consider alternatives", "Evaluate evidence", "Synthesize ideas"])
    elif "Evaluate coherence" in prompt:
        return str(random.random())  # Возвращаем случайную оценку от 0 до 1
    else:
        return "LLM response"

# Создание и использование CoTFunSearch
cot_funsearch = CoTFunSearch(mock_llm)
initial_prompt = "Solve a complex problem"
best_chain_of_thought = cot_funsearch.evolve_chain_of_thought(initial_prompt)

print("\nFinal Best Chain of Thought:")
print(" -> ".join(best_chain_of_thought)) упрости код сделай его максимально рабочим  предложи и внедри ииновации