Skip to main content

Optimization framework using Large Language Models

Project description

Optiverse

Optiverse is a Python library designed for evolving code and algorithms using Large Language Models (LLMs). Inspired by Deepmind's AlphaEvolve, it provides a flexible framework to iteratively improve programs, from code snippets to full files, in any programming language.

With Optiverse, you define a problem and provide an evaluator. The system then generates and evolves candidate solutions over multiple iterations, learning which approaches yield better results.

📖 Read the announcement post: Optiverse: Evolving Code with LLMs

Table of Contents

Why Optiverse?

Optiverse helps developers and researchers automate code improvement by evolving and refining solutions with LLMs. Key capabilities include:

  • Whole-file evolution: Unlike other implementations limited to isolated code blocks, Optiverse evolves entire source files.
  • Modular architecture: Swap out search strategies easily to experiment with different optimization approaches.
  • Multi-language support: As long as you provide an evaluator for your problem, Optiverse can optimize code in any programming language.
  • Flexible LLM integration: Works with any LLM provider compatible with the OpenAI API standard, such as OpenAI, Google Gemini, NVIDIA, and more.

Quick Start

Follow these steps to set up Optiverse and run an example.

1. Set Up Environment

First, create a virtual environment and install dependencies:

make init

Then, activate the virtual environment:

source venv/bin/activate

2. Run the Traveling Salesman Problem example:

This example uses Optiverse to solve the Traveling Salesman Problem (TSP). The code is in the examples/tsp directory.

The example supports multiple LLM providers through environment variables:

  • LLM_API_KEY: Your API key for the chosen provider
  • LLM_MODEL: The model name to use
  • LLM_PROVIDER: The provider name (openai, google, or nvidia)

Example with Google Gemini:

LLM_API_KEY="your-gemini-api-key" LLM_MODEL="gemini-2.0-flash" LLM_PROVIDER="google" make run.tsp

Note: Optiverse uses the OpenAI package under the hood, so it supports any LLM provider that follows the OpenAI API standard.

Sample Output:

When you run it, you'll see output like this:

2025-07-17 09:35:47 - optiverse.optimizer - INFO - Evaluating and saving initial solution...
2025-07-17 09:35:47 - examples.tsp.evaluator - INFO - Score 1: 33800.20318013358
2025-07-17 09:35:47 - examples.tsp.evaluator - INFO - Score 2: 32719.233809839046
2025-07-17 09:35:48 - examples.tsp.evaluator - INFO - Score 3: 35557.94658416552
2025-07-17 09:35:48 - optiverse.optimizer - INFO - Initial solution saved with ID: d3c1a4eb294e469593b52ee805d7028b, score: 34025.79452471271
2025-07-17 09:35:48 - optiverse.optimizer - INFO - Starting iteration 1/100
2025-07-17 09:35:50 - httpx - INFO - HTTP Request: POST https://generativelanguage.googleapis.com/v1beta/openai/chat/completions "HTTP/1.1 200 OK"
2025-07-17 09:35:51 - optiverse.solution_generator - INFO - No code blocks found in LLM response
2025-07-17 09:35:51 - optiverse.optimizer - INFO - No code generated by solution generator
2025-07-17 09:35:51 - optiverse.optimizer - INFO - Starting iteration 2/100
2025-07-17 09:35:52 - httpx - INFO - HTTP Request: POST https://generativelanguage.googleapis.com/v1beta/openai/chat/completions "HTTP/1.1 200 OK"
2025-07-17 09:35:58 - optiverse.optimizer - INFO - Evaluating solution
2025-07-17 09:36:09 - examples.tsp.evaluator - INFO - Score 1: 3149.0239046268334
2025-07-17 09:36:21 - examples.tsp.evaluator - INFO - Score 2: 3200.6735649311436
2025-07-17 09:36:30 - examples.tsp.evaluator - INFO - Score 3: 3089.4221942253616
2025-07-17 09:36:30 - optiverse.optimizer - INFO - Evaluation result: 3146.3732212611126
2025-07-17 09:36:30 - optiverse.optimizer - INFO - Saved solution with ID: 564d577d222a42ba8e1defb0dd2870e3

...

Understanding the Results

During optimization, Optiverse saves results in directories named tmp/YYYYMMDD_HHMM, indicating the date and time of each run.

solutions.csv

Inside each run directory, solutions.csv provides a high-level overview of all solutions explored:

id score t_group t_move t_parent_id_1 ...
0d8c5789dde24a94901871c18d6d9854 2817.0555492637 1 exploitation 034afd2da8894ab6838efb17bc28f201 ...
a42574709f27484fade7adc76683b2cf 2828.6215589938 6 exploitation 96c7140054154a20a4b67fd986658dd4 ...
883f6de275c14b32822feb5cdaaba55d 2837.3500311898 6 exploitation a42574709f27484fade7adc76683b2cf ...

Individual Solution Directories

Each solution has a dedicated directory named after its ID, containing:

  • prompt.md: The prompt sent to the LLM.
  • solution.txt: The code generated by the LLM.
  • description.txt: The LLM's own explanation of the changes it made.
  • metadata.json: Metadata including ID and score.
  • *_stdout.txt and *_strerr.txt: Program logs for debugging.

Evolved Solutions

Traveling Salesman Problem (TSP)

Problem Summary

The Traveling Salesman Problem (TSP) requires finding the shortest possible route visiting each city exactly once and returning to the start. It’s a standard benchmark for combinatorial optimization algorithms.

The full problem description is in examples/tsp/problem.md.

Initial Solution

The initial solution simply generates a random permutation of cities:

from datetime import timedelta
import random
from context import Context


def solve(context: Context) -> None:
    num_cities = len(context.instance)

    while context.remaining_time() > timedelta():
        # Generate a random solution (permutation of city indices)
        solution = random.sample(range(num_cities), num_cities)
        context.report_new_best_solution(solution)
        break  # since it's pointless to continue in this example

Evolved Algorithm

Through iterative evolution, Optiverse transformed the initial solution into an Iterated Local Search (ILS) variant, including:

  • Intensification (improvement phase): 2-opt local search with delta evaluation for efficient improvements.
  • Diversification (perturbation phase): Perturbation operators such as ruin-and-recreate, block moves, swaps, and double bridge moves.
  • Performance optimizations: Precomputed distance matrix for faster evaluation.

Evolution Setup

  • Iterations: ~300
  • LLM model: Qwen3-235B-A22B

Evaluation Results

On a 280-city instance (3 runs of 30 seconds each), the evolved algorithm achieved an average tour length of 2593, within ~0.5% of the known optimal (2579).

Full Evolved Code

import random
import math
from datetime import timedelta
from typing import List, Tuple
from context import Context

def compute_tour_length(tour: List[int], dist_matrix: List[List[float]]) -> float:
    length = 0.0
    n = len(tour)
    for i in range(n):
        a, b = tour[i], tour[(i+1)%n]
        length += dist_matrix[a][b]
    return length

def nearest_neighbor(instance: List[Tuple[float, float]], start: int, dist_matrix: List[List[float]], nearest_neighbors: List[List[int]]) -> List[int]:
    n = len(instance)
    visited = [False]*n
    tour, current = [start], start
    visited[start] = True
    while len(tour) < n:
        for city in nearest_neighbors[current]:
            if not visited[city]:
                next_city = city
                break
        tour.append(next_city)
        visited[next_city] = True
        current = next_city
    return tour

def two_opt(tour: List[int], dist_matrix: List[List[float]]) -> List[int]:
    tour = tour.copy()
    n = len(tour)
    improved = True
    while improved:
        improved = False
        for i in range(n-1):
            for j in range(i+2, n):
                a, b = tour[i], tour[i+1]
                c, d = tour[j-1], tour[j]
                if dist_matrix[a][b] + dist_matrix[c][d] > dist_matrix[a][c] + dist_matrix[b][d]:
                    tour[i+1:j] = tour[i+1:j][::-1]
                    improved = True
    return tour

def solve(context: Context) -> None:
    instance = context.instance
    n = len(instance)
    if n <= 1:
        context.report_new_best_solution(list(range(n)))
        return

    dist_matrix = [[math.hypot(x1-x2, y1-y2) for x2, y2 in instance] for x1, y1 in instance]

    nearest_neighbors = []
    for u in range(n):
        sorted_cities = sorted(range(n), key=lambda c: dist_matrix[u][c])
        nearest_neighbors.append(sorted_cities)

    best_solution, best_length = None, float('inf')
    start_points = [0, n//4, n//2, (3*n)//4, n-1]
    if n >= 8:
        start_points += random.sample(range(n), 3)

    for start in start_points:
        if context.remaining_time() <= timedelta(seconds=1):
            break
        tour = nearest_neighbor(instance, start, dist_matrix, nearest_neighbors)
        optimized = two_opt(tour, dist_matrix)
        current_length = compute_tour_length(optimized, dist_matrix)
        if current_length < best_length:
            best_solution, best_length = optimized, current_length
            context.report_new_best_solution(best_solution)

    while context.remaining_time() > timedelta(seconds=0.1) and best_solution:
        new_solution = best_solution.copy()
        move = random.random()
        n_cities = len(best_solution)

        if move < 0.2:  # Ruin and Recreate
            remove_count = max(2, int(n_cities * 0.2))
            removed = random.sample(best_solution, remove_count)
            current_tour = [city for city in best_solution if city not in removed]
            for city in removed:
                best_pos, best_delta = 0, float('inf')
                for i in range(len(current_tour)):
                    a = current_tour[i]
                    b = current_tour[(i+1) % len(current_tour)]
                    delta = dist_matrix[a][city] + dist_matrix[city][b] - dist_matrix[a][b]
                    if delta < best_delta:
                        best_delta, best_pos = delta, i
                current_tour.insert(best_pos + 1, city)
            new_solution = current_tour

        elif move < 0.4:  # Block move
            i = random.randint(0, n_cities-3)
            j = random.randint(i+1, n_cities-1)
            block = new_solution[i+1:j+1]
            if random.random() < 0.5:
                block = block[::-1]
            new_solution = new_solution[:i+1] + new_solution[j+1:]
            k = random.randint(0, len(new_solution)-1)
            new_solution = new_solution[:k+1] + block + new_solution[k+1:]

        elif move < 0.6:  # Swap
            i, j = random.sample(range(n_cities), 2)
            new_solution[i], new_solution[j] = new_solution[j], new_solution[i]

        else:  # Double bridge
            if n_cities < 4:
                i, j = random.sample(range(n_cities), 2)
                new_solution[i], new_solution[j] = new_solution[j], new_solution[i]
            else:
                a, b, c, d = sorted(random.sample(range(n_cities), 4))
                new_solution = (new_solution[:a+1] +
                               new_solution[c+1:d+1] +
                               new_solution[a+1:b+1][::-1] +
                               new_solution[b+1:c+1] +
                               new_solution[d+1:])

        optimized = two_opt(new_solution, dist_matrix)
        new_length = compute_tour_length(optimized, dist_matrix)
        if new_length < best_length:
            best_solution, best_length = optimized, new_length
            context.report_new_best_solution(best_solution)

    if best_solution is None:
        solution = list(range(n))
        random.shuffle(solution)
        context.report_new_best_solution(solution)
    else:
        final_tour = two_opt(best_solution, dist_matrix)
        context.report_new_best_solution(final_tour)

License

Optiverse is open source and licensed under the GNU General Public License v3.0 (GPLv3).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

optiverse-0.0.2.tar.gz (16.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

optiverse-0.0.2-py3-none-any.whl (13.6 kB view details)

Uploaded Python 3

File details

Details for the file optiverse-0.0.2.tar.gz.

File metadata

  • Download URL: optiverse-0.0.2.tar.gz
  • Upload date:
  • Size: 16.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.3

File hashes

Hashes for optiverse-0.0.2.tar.gz
Algorithm Hash digest
SHA256 4375f7bc22fe86304829fd38eb98e655f6c1ed24b766c57b7b208ffb7c634a3a
MD5 2d210bff49af896f77eb375f970c1a9d
BLAKE2b-256 fcc2ca391452f413ffb750b7c7012b07ecd04bbec6e3dd090e88e1404039fe89

See more details on using hashes here.

File details

Details for the file optiverse-0.0.2-py3-none-any.whl.

File metadata

  • Download URL: optiverse-0.0.2-py3-none-any.whl
  • Upload date:
  • Size: 13.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.3

File hashes

Hashes for optiverse-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 cf6fd11155ec0f1932959933bee933ff2bcb9655cd9d9b6b99c4b97320a73b3d
MD5 ce96e4c33b27f0ee2ec574a3752f50d3
BLAKE2b-256 5b80b50d3ff915afaa2830943b8900fa661dbe69cdfc3c7686b669f0e79d5745

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page