Algorithms
Algorithms are the optimization process that Luna Bench runs against your optimization models. Each algorithm
takes a Model as input and produces a Solution. Luna Bench provides two base classes to
accommodate different execution paradigms: synchronous algorithms that return results immediately,
and asynchronous algorithms designed for cloud or quantum backends where computation happens
remotely and results must be fetched later.
Overview
An algorithm in Luna Bench is a configurable, serializable unit of computation registered via the
@algorithm decorator. The decorator registers the class with the internal component registry so
benchmarks can discover and instantiate algorithms by name.
Luna Bench ships with a small set of built-in algorithms for testing and common use cases, but the real power comes from writing your own custom algorithms that wrap any solver, API, or service you need to benchmark.
| Aspect | Synchronous | Asynchronous |
|---|---|---|
| Base class | BaseAlgorithmSync |
BaseAlgorithmAsync[T] |
| Return style | Blocks until solution is ready | Submits work, then polls for results |
| Use case | Local solvers (SCIP, Gurobi, etc.) | Cloud APIs, quantum backends |
| Key method(s) | run() |
run_async() + fetch_result() |
Synchronous Algorithms
When to use
Use a synchronous algorithm when the solver runs locally or returns results in a single blocking call.
Base class: luna_bench.custom.BaseAlgorithmSync
Synchronous algorithms implement a single abstract method:
The method receives a Model instance and must return a Solution. Luna Bench handles timing,
error capture, and result storage around this call.
Registration
All algorithms — synchronous and asynchronous — are registered with the @algorithm decorator
from luna_bench.custom:
The decorator makes the class available in the component registry so that benchmarks can reference it by name in configuration files and programmatic setups.
Asynchronous Algorithms
When to use
Use an asynchronous algorithm when computation is submitted to a remote service and results become available after a delay — for example, cloud optimization platforms or quantum hardware queues.
Base class: luna_bench.custom.BaseAlgorithmAsync[T]
The generic type parameter T represents the retrieval data — a serializable object (typically
a Pydantic BaseModel) that holds whatever reference is needed to fetch results later (such as a
job ID or request token).
Asynchronous algorithms require three abstract members:
| Member | Signature | Purpose |
|---|---|---|
model_type |
@property -> type[T] |
Returns the concrete type of the retrieval data for deserialization |
run_async |
(model: Model) -> T |
Submits the model for solving and returns retrieval data |
fetch_result |
(model: Model, retrieval_data: T) -> Result[Solution, str] |
Polls the remote service and returns the solution or an error message |
The return type of fetch_result uses the Result monad from the
returns library. Return Success(solution) when results are
ready, or Failure("reason") when they are not yet available or an error occurred.
Background Processing with Huey
Asynchronous algorithms are executed through a Huey job queue. Luna Bench submits the
run_async call as a background task, then periodically invokes fetch_result to check whether
the computation has completed. This keeps the main benchmark loop non-blocking and allows multiple
asynchronous jobs to run in parallel.
Built-in Algorithms
Luna Bench includes several algorithms out of the box:
ScipAlgorithm
Wraps the SCIP mixed-integer programming solver. This is a fully-featured open-source solver suitable for benchmarking linear and mixed-integer programs.
FakeAlgorithm
A test algorithm that sleeps for a random duration before returning a dummy solution. Useful for validating benchmark pipelines, testing timeout behavior, and developing new features without waiting for real solvers.
Writing Custom Algorithms
Custom Synchronous Algorithm
The following example shows a minimal synchronous algorithm with a configurable parameter. Because algorithms are Pydantic models under the hood, you can declare typed fields with defaults and they become part of the algorithm's serializable configuration.
from luna_bench.custom import BaseAlgorithmSync, algorithm
from luna_quantum import Model, Solution
@algorithm
class MyAlgorithm(BaseAlgorithmSync):
max_iterations: int = 1000
def run(self, model: Model) -> Solution:
# Implement your solving logic here.
# Access configuration via self.max_iterations, etc.
...
return solution
Key points:
- Subclass
BaseAlgorithmSync. - Apply the
@algorithmdecorator. - Implement the
runmethod. - Declare any solver-specific parameters as class-level fields with type annotations.
Custom Asynchronous Algorithm
The following example shows an asynchronous algorithm that submits work to a remote service and later fetches results using a job ID.
from luna_bench.custom import BaseAlgorithmAsync, algorithm
from luna_quantum import Model, Solution
from returns.result import Result, Success, Failure
from pydantic import BaseModel
class JobId(BaseModel):
id: str
@algorithm
class MyCloudAlgorithm(BaseAlgorithmAsync[JobId]):
@property
def model_type(self) -> type[JobId]:
return JobId
def run_async(self, model: Model) -> JobId:
# Submit the model to your cloud service.
# Return a reference object that can be used to retrieve results.
return JobId(id="job-123")
def fetch_result(self, model: Model, retrieval_data: JobId) -> Result[Solution, str]:
# Poll the remote service for results.
# Return Success(solution) when ready, or Failure("not ready") to retry later.
return Success(solution)
Key points:
- Subclass
BaseAlgorithmAsync[T]whereTis your retrieval data type (a PydanticBaseModel). - Apply the
@algorithmdecorator. - Implement the
model_typeproperty to return the concrete class ofT. - Implement
run_asyncto submit work and return the retrieval reference. - Implement
fetch_resultto check for and return results using theResulttype.
Luna Quantum Integration
Any algorithm from the luna-quantum can be
added directly to a Luna Bench benchmark without any additional wrapping on your part. Internally,
Luna Bench uses LunaAlgorithmWrapper to adapt the luna-quantum algorithm interface to the
benchmark execution framework.
This means you can mix and match native Luna Bench algorithms with existing luna-quantum solvers in the same benchmark run.
Adding Algorithms to a Benchmark
Once you have an algorithm instance — whether built-in, custom, or from luna-quantum — add it to
your benchmark with the add_algorithm method:
from luna_bench.algorithms import ScipAlgorithm
# Add a built-in algorithm
bench.add_algorithm("scip", ScipAlgorithm())
# Add a custom algorithm with configuration
bench.add_algorithm("my-algo", MyAlgorithm(max_iterations=500))
# Add multiple algorithms to compare them
bench.add_algorithm("cloud-solver", MyCloudAlgorithm())
The first argument is a name that identifies the algorithm in benchmark results, reports, and logs. Choose short, descriptive names — they will appear in tables and charts. The second argument is the algorithm instance with any desired configuration applied.
You can add as many algorithms as you like. Luna Bench will run every registered algorithm against every registered model, collecting results for comparison.