ReEvo#
ReEvo (Reflective Evolution) is an LLM-based evolutionary algorithm that designs optimization heuristics through a novel two-stage reflection mechanism. The algorithm combines short-term and long-term reflections to guide the evolutionary process, enabling effective exploration and exploitation of the heuristic search space.
Background#
ReEvo was developed to address the challenge of automatically designing optimization heuristics using Large Language Models. Unlike traditional evolutionary algorithms that rely on random variation operators, ReEvo leverages the reasoning capabilities of LLMs to reflect on past solutions and generate improved heuristics. The key innovation is the introduction of reflective prompts that guide the LLM to analyze differences between solutions and synthesize insights across multiple generations.
The algorithm maintains a population of candidate heuristics and uses genetic operators (crossover and mutation) guided by reflective prompts. Short-term reflections analyze pairs of solutions to generate immediate improvement hints, while long-term reflections aggregate insights from multiple short-term reflections to provide broader guidance for mutation operations.
Algorithm Overview#
ReEvo operates through the following main stages:
Population Initialization: Generate initial heuristics using the template program as a starting point.
Short-term Reflection: For each iteration, select two parent solutions and prompt the LLM to analyze their differences, generating improvement hints.
Crossover: Use the short-term reflection to guide the combination of two parent solutions, creating a new offspring heuristic.
Long-term Reflection: Periodically aggregate recent short-term reflections to synthesize broader insights about successful heuristic patterns.
Mutation: Apply mutation to elite solutions guided by long-term reflection prompts.
Selection: Maintain population size through survival selection based on fitness.
The algorithm uses simulated annealing-inspired acceptance to balance exploration and exploitation, allowing exploration of the search space even when immediate improvements are not apparent.
Pseudocode#
Initialize population with initial heuristics
WHILE total_samples < max_sample_nums:
// Short-term reflection
Select two parent solutions (indivs)
short_term_reflection = LLM.analyze(worse_solution, better_solution)
// Crossover
offspring = LLM.crossover(parents, short_term_reflection)
Evaluate offspring
Register to population
// Long-term reflection (every pop_size generations)
IF generation % pop_size == 0:
long_term_reflection = LLM.synthesize(recent_short_term_reflections)
// Mutation on elite
FOR i in range(mutation_rate * pop_size):
mutated = LLM.mutate(elite, long_term_reflection)
Evaluate mutated
Register to population
Perform population survival
Return best solution
Constructor Parameters#
- class ReEvo#
Parameters
llm (llm4ad.base.LLM): An instance of ‘llm4ad.base.LLM’, which provides the way to query LLM.
evaluation (llm4ad.base.Evaluation): An instance of ‘llm4ad.base.Evaluation’, which defines the way to calculate the score of a generated function.
profiler (llm4ad.method.reevo.ReEvoProfiler | None): An instance of ‘llm4ad.method.reevo.ReEvoProfiler’. If not needed, pass ‘None’.
max_sample_nums (int | None): Terminate after evaluating ‘max_sample_nums’ functions (valid or not). Pass ‘None’ to disable.
pop_size (int | None): Population size. If ‘None’, ReEvo will auto-adjust this parameter. Default is 20.
mutation_rate (float): Rate of mutation applied to elite solutions. Default is 0.5.
num_samplers (int): Number of parallel samplers. Default is 1.
num_evaluators (int): Number of parallel evaluators. Default is 1.
resume_mode (bool): In resume_mode, skips evaluating ‘template_program’ and initialization. Default is False.
debug_mode (bool): If True, detailed information will be printed. Default is False.
multi_thread_or_process_eval (str): Use ‘thread’ (ThreadPoolExecutor) or ‘process’ (ProcessPoolExecutor) for multi-core CPU evaluation. Default is ‘thread’.
kwargs (dict): Additional args passed to ‘llm4ad.base.SecureEvaluator’, such as ‘fork_proc’.
Methods#
- run()#
Starts the evolutionary optimization process. If resume_mode is False, it initializes the population and then proceeds to evolve using the reflective genetic operators.
Private Methods#
- _iteratively_ga_evolve()#
Performs the core evolutionary loop with short-term reflection, crossover, long-term reflection, and mutation operators.
- _iteratively_init_population()#
Initializes the population by repeatedly sampling and evaluating functions using the initialization prompt.
- _sample_evaluate_register(prompt: str)#
Samples a function using the provided prompt, evaluates it, and registers it with the population and profiler. Records timing and performance metrics.
- _continue_loop() bool#
Determines whether the evolutionary process should continue based on termination conditions.
- _multi_threaded_sampling(fn: callable, *args, **kwargs)#
Executes the given function (either initialization or evolution) using multiple threads for parallel sampling.
Attributes#
_template_program_str (str): String representation of the template program to evolve
_task_description_str (str): Description of the optimization task
_function_to_evolve (Function): The base function being evolved
_function_to_evolve_name (str): Name of the function being evolved
_template_program (Program): Parsed template program structure
_population (Population): Manages current population of candidate functions
_sampler (SampleTrimmer): Handles LLM-based function sampling
_evaluator (SecureEvaluator): Evaluates function performance
_profiler (ReEvoProfiler): Optional profiler for tracking evolution metrics
_tot_sample_nums (int): Total number of samples evaluated
_MAX_SHORT_TERM_REFLECTION_PROMPT (int): Maximum short-term reflections to consider for long-term reflection
_evaluation_executor (Executor): Thread/process pool for parallel evaluation
Configuration Parameters#
_max_sample_nums (Optional[int]): Maximum total samples to evaluate
_pop_size (int): Population size
_mutation_rate (float): Rate of mutation applied to elite solutions
_num_samplers (int): Number of parallel samplers
_num_evaluators (int): Number of parallel evaluators
_resume_mode (bool): Whether to resume from existing population
_debug_mode (bool): Enable debug output
_multi_thread_or_process_eval (str): ‘thread’ or ‘process’ for evaluation
Example Usage#
from llm4ad.base import Evaluation, LLM
from llm4ad.method import ReEvo
from llm4ad.tools.llm import OpenAI
# Define your task
task_description = "Design a heuristic for the Traveling Salesman Problem..."
# Define template program
template_program = '''
def tsp_heuristic(dist_matrix, start=0):
"""A heuristic for solving TSP.
Args:
dist_matrix: Distance matrix between cities.
start: Starting city index.
Returns:
Route and total distance.
"""
n = len(dist_matrix)
visited = [False] * n
route = [start]
visited[start] = True
current = start
for _ in range(n - 1):
nearest = min(range(n), key=lambda x: dist_matrix[current][x] if not visited[x] else float('inf'))
route.append(nearest)
visited[nearest] = True
current = nearest
total_distance = sum(dist_matrix[route[i]][route[i+1]] for i in range(n-1))
return route, total_distance
'''
# Create evaluation
evaluation = Evaluation(
task_description=task_description,
template_program=template_program
)
# Create LLM
llm = OpenAI(model='gpt-4')
# Create and run ReEvo
reevo = ReEvo(
llm=llm,
evaluation=evaluation,
max_sample_nums=100,
pop_size=20,
mutation_rate=0.5
)
reevo.run()
References#
Fei Liu, Rui Zhang, Zhuoliang Xie, Rui Sun, Kai Li, Xi Lin, Zhenkun Wang, Zhichao Lu, and Qingfu Zhang. “LLM4AD: A Platform for Algorithm Design with Large Language Model.” arXiv preprint arXiv:2412.17287 (2024).