Metadata-Version: 2.4
Name: luna-usecase-template
Version: 0.0.2a2
Summary: Template for optimization use cases.
Keywords: aqarios,luna,quantum computing,quantum optimization,optimization,sdk
Author: Aqarios GmbH
Author-email: Aqarios GmbH <info@aqarios.com>
License-Expression: Apache-2.0
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Classifier: Topic :: Scientific/Engineering
Requires-Dist: luna-model>=0.5.3
Requires-Dist: pydantic>=2.12.5
Maintainer: Maximilian Janetschek, David Bucher, Jonas Blenninger
Maintainer-email: Maximilian Janetschek <maximilian.janetschek@aqarios.com>, David Bucher <david.bucher@aqarios.com>, Jonas Blenninger <jonas.blenninger@aqarios.com>
Requires-Python: >=3.11.0
Description-Content-Type: text/markdown

# Use Case Library

A Python SDK for defining optimization use cases in the [Luna](https://aqarios.com) quantum optimization framework.

## Overview

`usecase-lib` provides a structured template for defining optimization problems with:

- **Data** — Problem input data (`UcData`)
- **Formulation** — How the problem maps to a mathematical model (`UcFormulation`)
- **Solution** — Interpretation of solver output (`UcSolution`)
- **Instance** — A concrete pairing of data + formulation (`UcInstance`)
- **Collection** — Groups of instances (`UcInstanceCollection`)

All types support JSON serialization and polymorphic deserialization via a central `Registry`.

## Requirements

- Python >= 3.13.0

## Quick Start

### Define a use case

```python
from typing import Literal, override

from luna_model import Model, Solution
from usecase_lib import Registry, UcData, UcFormulation, UcInstance, UcSolution


class MyData(UcData):
    name: Literal["my_data"] = "my_data"
    values: list[float]

    @override
    def to_string(self) -> str:
        return str(self.values)


class MySolution(UcSolution):
    name: Literal["my_solution"] = "my_solution"
    result: float

    @override
    def to_string(self) -> str:
        return str(self.result)


class MyFormulation(UcFormulation[MyData, MySolution]):
    name: Literal["my_formulation"] = "my_formulation"

    @override
    @staticmethod
    def to_string(data: MyData) -> str:
        return "minimize sum(values)"

    @override
    @staticmethod
    def formulate(data: MyData) -> Model:
        m = Model("MyProblem")
        # ... build your model ...
        return m

    @override
    @staticmethod
    def interpret(solution: Solution, data: MyData) -> MySolution:
        return MySolution(result=0.0)


class MyInstance(UcInstance):
    data: MyData
    formulation: MyFormulation
```

### Register and serialize

```python
# Register classes (also works as @Registry.add decorator)
Registry.add(MyData)
Registry.add(MySolution)
Registry.add(MyFormulation)
Registry.add(MyInstance)

# Create and serialize
data = MyData(data_name="example", values=[1.0, 2.0, 3.0])
instance = MyInstance(data=data, formulation=MyFormulation())
instance.store("instance.json")

# Deserialize with polymorphic type dispatch
loaded = MyInstance.load("instance.json")
```

## Architecture

Every concrete `UcData`, `UcFormulation`, and `UcSolution` subclass must define a `name` field as a `Literal["unique_string"]`. This enables the `Registry` to distinguish types during deserialization.

Abstract base classes use Pydantic wrap validators to automatically dispatch validation to the correct registered subclass, so you can deserialize from a base type without knowing the concrete type ahead of time.

## Development

```bash
uv sync                # Install dependencies
ruff check . --fix     # Lint with auto-fix
ruff format .          # Format code
uv build               # Build package
```

## License

Apache-2.0
