Skip to content

Quantum Layer

Classiq exports the QLayer object, which inherits from torch.nn.Module (like most objects in the torch.nn namespace), and it acts like one!

The QLayer object is defined as:

class QLayer(nn.Module):
    def __init__(
        self,
        circuit: Circuit,
        execute: ExecuteFunciton,
        post_process: PostProcessFunction,
    ):
        ...

The first parameter, circuit, is the result of model.synthesize(). Note that the parameters are assumed to follow the API stated in qnn.

The second parameter is a callable, taking in a Circuit, and a dictionary, mapping each parameter name to its value, and returning a MultipleExecutionDetails, which is a wrapper to Executor.execute. The third parameter is a callble, taking in an ExecutionDetails, parsing it, and returning a Tensor

An example of such callables is:

import torch

from classiq.applications.qnn.types import (
    MultipleArguments,
    Circuit,
    MultipleExecutionDetails,
)


def execute(circuit: Circuit, arguments: MultipleArguments) -> MultipleExecutionDetails:
    return Executor(prefereces).execute_batch(circuit, arguments)


def post_process(result: ExecutionDetails) -> Tensor:
    # for example, post process can take some value out of `result.counts`, which is a `dict`
    value = _post_process_result(result)
    return torch.tensor(value)

Behind the scenes

behind the scenes, the QLayer does the following

  • handles processing the PQC
  • handles initializing and tracking parameters
  • handles passing the inputs and weights (as multi dimensional tensors) to the execution function
  • handles gradient calculation on the PQC