Files
2026-07-06 03:32:12 +08:00

169 lines
6.6 KiB
Python

import random
import math
from typing import List, Dict, Any, Tuple
from itertools import product
class SmartSearch:
def __init__(self, ea_config):
self.ea_config = ea_config
self.total_combinations = ea_config.get_total_combinations()
def select_strategy(self) -> str:
if self.ea_config.search_strategy != 'auto':
return self.ea_config.search_strategy
if self.total_combinations <= 10000:
return 'grid'
elif self.total_combinations <= 500000:
return 'latin'
else:
return 'genetic'
def generate_combinations(self, max_samples: int = 2000) -> List[Dict]:
strategy = self.select_strategy()
print('Selected strategy: ' + strategy + ' for ' + str(self.total_combinations) + ' combinations')
if strategy == 'grid':
return self._grid_search()
elif strategy == 'random':
return self._random_search(max_samples)
elif strategy == 'latin':
return self._latin_hypercube(max_samples)
elif strategy == 'genetic':
return self._genetic_search(max_samples)
return []
def _grid_search(self) -> List[Dict]:
param_names = list(self.ea_config.parameters.keys())
param_values = [p.expand_values() for p in self.ea_config.parameters.values()]
combinations = list(product(*param_values))
return [dict(zip(param_names, combo)) for combo in combinations]
def _random_search(self, max_samples: int) -> List[Dict]:
all_values = {name: p.expand_values() for name, p in self.ea_config.parameters.items()}
samples = []
for _ in range(min(max_samples, self.total_combinations)):
sample = {name: random.choice(values) for name, values in all_values.items()}
if sample not in samples:
samples.append(sample)
return samples
def _latin_hypercube(self, max_samples: int) -> List[Dict]:
all_values = {name: p.expand_values() for name, p in self.ea_config.parameters.items()}
n_params = len(all_values)
samples = []
for i in range(min(max_samples, self.total_combinations)):
sample = {}
for j, (name, values) in enumerate(all_values.items()):
idx = int((i / max_samples) * len(values)) % len(values)
sample[name] = values[idx]
if sample not in samples:
samples.append(sample)
return samples
def _genetic_search(self, max_samples: int) -> List[Dict]:
pop_size = min(50, max_samples)
n_generations = max_samples // pop_size
all_values = {name: p.expand_values() for name, p in self.ea_config.parameters.items()}
population = []
for _ in range(pop_size):
individual = {name: random.choice(values) for name, values in all_values.items()}
population.append(individual)
for gen in range(n_generations):
population = self._evolve(population, all_values)
return population[:max_samples]
def _evolve(self, population: List[Dict], all_values: Dict) -> List[Dict]:
crossover_rate = 0.8
mutation_rate = 0.15
offspring = []
for _ in range(len(population)):
parent1, parent2 = random.sample(population, 2)
if random.random() < crossover_rate:
child = self._crossover(parent1, parent2)
else:
child = parent1.copy()
if random.random() < mutation_rate:
child = self._mutate(child, all_values)
offspring.append(child)
return population[:5] + offspring[:len(population)-5]
def _crossover(self, parent1: Dict, parent2: Dict) -> Dict:
child = {}
for key in parent1.keys():
if random.random() < 0.5:
child[key] = parent1[key]
else:
child[key] = parent2[key]
return child
def _mutate(self, individual: Dict, all_values: Dict) -> Dict:
key = random.choice(list(all_values.keys()))
individual[key] = random.choice(all_values[key])
return individual
class GeneticOptimizer:
def __init__(self, ea_config, population_size: int = 50, generations: int = 30):
self.ea_config = ea_config
self.population_size = population_size
self.generations = generations
self.all_values = {name: p.expand_values() for name, p in ea_config.parameters.items()}
def create_individual(self) -> Dict:
return {name: random.choice(values) for name, values in self.all_values.items()}
def evaluate(self, individual: Dict) -> float:
return random.random() * 10
def tournament_select(self, population: List[Dict], k: int = 3) -> Dict:
tournament = random.sample(population, k)
return max(tournament, key=self.evaluate)
def crossover(self, parent1: Dict, parent2: Dict) -> Tuple[Dict, Dict]:
child1, child2 = {}, {}
for key in parent1.keys():
if random.random() < 0.5:
child1[key] = parent1[key]
child2[key] = parent2[key]
else:
child1[key] = parent2[key]
child2[key] = parent1[key]
return child1, child2
def mutate(self, individual: Dict, rate: float = 0.15) -> Dict:
for key in individual.keys():
if random.random() < rate:
individual[key] = random.choice(self.all_values[key])
return individual
def run(self) -> List[Dict]:
population = [self.create_individual() for _ in range(self.population_size)]
best_individuals = []
for gen in range(self.generations):
fitness_scores = [(ind, self.evaluate(ind)) for ind in population]
fitness_scores.sort(key=lambda x: x[1], reverse=True)
elite = [ind for ind, _ in fitness_scores[:5]]
best_individuals.extend(elite)
new_population = elite.copy()
while len(new_population) < self.population_size:
parent1 = self.tournament_select(population)
parent2 = self.tournament_select(population)
child1, child2 = self.crossover(parent1, parent2)
child1 = self.mutate(child1)
child2 = self.mutate(child2)
new_population.extend([child1, child2])
population = new_population[:self.population_size]
return best_individuals