Motor Evolucionário e Otimização no Simplex 🧬
O otimizador de alocações do Monvix (FinancialGeneticOptimizer) implementa um Algoritmo Genético contínuo projetado especificamente para convergir sobre o simplex unitário de 8 dimensões.
📐 Representação Cromossômica
O cromossomo de cada indivíduo é modelado como um vetor de pesos reais :
A Restrição do Simplex (Simplex Constraint)
Todo indivíduo na população deve estritamente respeitar o simplex canônico :
[!IMPORTANT] Isolamento de Obrigações Fixas: A moradia (
housing) e a pensão alimentícia judicial (alimonyAmount) são avaliadas previamente pela funçãoevaluate_obligations(). O Algoritmo Genético opera exclusivamente sobre o saldo flexível remanescente (flexible_balance). Se a renda do usuário apresentar déficit imediato para cobrir obrigações vitais, o otimizador bypassa a evolução e retorna alocações zeradas com sinalização de déficit.
⚙️ Hiperparâmetros do Algoritmo
Os hiperparâmetros foram calibrados empiricamente em mais de 100 cenários de teste (app/tests/test_optimizer.py):
| Parâmetro | Valor | Justificativa de Engenharia |
|---|---|---|
Tamanho da População (population_size) | 120 | Garante diversidade genética ampla no simplex sem degradar tempo de CPU. |
Gerações (generations) | 60 | Suficiente para convergência assintótica em menos de 15 milissegundos com NumPy. |
Taxa de Crossover (crossover_rate) | 0.85 | Alta recombinação entre indivíduos com bons traços de adaptação orçamentária. |
Taxa de Mutação (mutation_rate) | 0.25 | Impede estagnação prematura em ótimos locais de sub-alocação. |
Tamanho da Elite (elite_size) | 4 | Preservação estrita dos 4 melhores indivíduos sem alteração para a geração seguinte. |
Seleção por Torneio (tournament_size) | 3 | Pressão seletiva equilibrada sem eliminação precoce de diversidade. |
🧬 Operadores Genéticos
1. Inicialização Populacional (Distribuição de Dirichlet)
Para acelerar a convergência sem perder diversidade estocástica, a população inicial não é gerada aleatoriamente de forma uniforme. Em vez disso, é amostrada a partir de uma Distribuição de Dirichlet parametrizada pelo vetor de metas preliminar :
Isso garante que toda a população inicial já nasça dentro do simplex () e concentrada na vizinhança plausível do perfil do usuário.
2. Crossover Aritmético Convexo
Para dois pais e selecionados por torneio de tamanho 3, o cruzamento gera um filho linearmente combinado:
Como é um conjunto convexo, a combinação convexa de dois pontos no simplex permanece garantidamente dentro do simplex.
3. Mutação Gaussiana com Projeção
Quando ocorre mutação, uma perturbação estocástica é aplicada:
Após a perturbação, o vetor é renormalizado para que sua soma retorne a :
🪙 Distribuição Exata de Centavos (Largest Remainder Method)
Ao converter percentuais contínuos em moeda real (Decimal), o arredondamento ingênuo pode gerar discrepâncias de centavos. O Monvix implementa o Método do Maior Resto (Hamilton-Hare Method):
# Trecho de app/ga/optimizer.py
raw = [balance * Decimal(str(weight)) for weight in chromosome]
amounts = [value.quantize(CENT, rounding=ROUND_DOWN) for value in raw]
cents_left = int((balance - sum(amounts, ZERO)) / CENT)
fractions = [raw[index] - amounts[index] for index in range(len(raw))]
order = sorted(range(len(raw)), key=lambda index: fractions[index], reverse=True)
for index in order[:cents_left]:
amounts[index] += CENT
Isso assegura com precisão bancária que a soma das alocações é matematicamente igual a flexible_balance.