Skip to content

Getting started with quantum program synthesis

The first steps in quantum program synthesis are defining the algorithms, its constraints, and your preferences. These are described in detail in the following sections.

Once your model is fully defined, it's time to synthesize it.

In the IDE, describe the model in the synthesis page. After writing down the model (or uploading a .qmod file), hit the synthesize button on the bottom right of the page. After the synthesis is done, you will automatically be redirected to the Circuit page.

In the Classiq's Python SDK, the quantum program is described by using the Model object.

The synthesis process is then initiated by performing the synthesize method on a SerializedModel. The serialized model is received using the method get_model() of Model or from the content of .qmod file. Alternatively, the async method synthesize_async can be used as part of an async code (see Advanced Usage).

from classiq import Model, synthesize

model = Model()
qprog = synthesize(model.get_model())

Synthesis Results

Once the synthesis process is done, the synthesized quantum program is returned. The quantum program is available in different output formats, according to the provided preferences. In addition, a static visualization of the quantum program is returned.

The returned quantum program maintains information about its functional structure. However, it is not fully optimized for execution. For example, gates that are part of the implementations of different functions could be canceled in some cases. Such optimizations are performed during transpilation and the resulting quantum program is returned separately.

The visualization and code of the synthesized quantum program appear after synthesis. If multiple output formats are requested, the first is used for code display. The rest of the data, including all output formats, the transpiled quantum program and metadata, is saved in the classiq subdirectory.

The synthesize method of Model returns an instance of GeneratedCircuit. The instance contains the quantum program in all requested formats, under the outputs field. This field is a dictionary, mapping each format to the code. Alternatively, you can access the different formats using properties, namely, qasm, qsharp, ionq etc. To see the quantum program, one may use the show method. The transpiled quantum program and its properties are available as attributes of the transpiled_circuit field.

Full Example - Option Pricing

Some methods of option pricing [1] begin with loading multiple quantum states onto separate registers. This is typically the first stage of the algorithm. Below we show an example of loading multiple two-qubit states. Each state preparation function uses four qubits, three for the state and an auxiliary qubit. The synthesis process selects a different auxiliary reuse strategy depending on the constraints.

{
    "functions": [
      {
        "name": "main",
        "body": [{
            "function": "StatePreparation",
            "function_params": {
                "probabilities": [0.05, 0.11, 0.13, 0.23, 0.27, 0.12, 0.03, 0.06],
                "error_metric": {"KL": {"upper_bound": 0.01}}
            },
            "name": "state_preparation_0"
        },
        {
            "function": "StatePreparation",
            "function_params": {
                "probabilities": [0.11, 0.13, 0.23, 0.27, 0.12, 0.03, 0.06, 0.05],
                "error_metric": {"KL": {"upper_bound": 0.01}}
            },
            "name": "state_preparation_1"
        },
        {
            "function": "StatePreparation",
            "function_params": {
                "probabilities": [0.05, 0.11, 0.13, 0.23, 0.27, 0.12, 0.03, 0.06],
                "error_metric": {"KL": {"upper_bound": 0.01}}
            },
            "name": "state_preparation_2"
        }]
      }
    ],
    "constraints": {
      "max_width": 12,
      "max_depth": 200
    }
}
from classiq import Model, synthesize, show
from classiq.builtin_functions import StatePreparation
from classiq.builtin_functions.state_preparation import Metrics
from classiq.builtin_functions.range_types import NonNegativeFloatRange
from classiq.model import Constraints

STATE_PREPARATION_COUNT = 3
MAX_WIDTH = 12
MAX_DEPTH = 200

constraints = Constraints(max_width=MAX_WIDTH, max_depth=MAX_DEPTH)
model = Model(constraints=constraints)

probabilities = (0.05, 0.11, 0.13, 0.23, 0.27, 0.12, 0.03, 0.06)
error = {Metrics.KL: NonNegativeFloatRange(upper_bound=0.01)}
sp_params = StatePreparation(
    probabilities=probabilities,
    error_metric={"KL": {"upper_bound": 0.01}},
)

for n in range(STATE_PREPARATION_COUNT):
    model.StatePreparation(sp_params, call_name=f"state_preparation_{n}")

qprog = synthesize(model.get_model())
show(qprog)

As shown in the image below, auxiliary reuse is not necessary in the case where the max_width constraint is 9 or more, where in the case of max_width=7, auxiliary reuse is required.

 Option pricing example

In this example, three states were prepared. This is a simple case, and checking all possible options can be done manually. However, if the use-case requires preparing 20 states the task becomes much harder.

When each state preparation has flexibility in the error, and different states are prepared on registers of different sizes, the problem becomes impossible to handle manually.

This is one very simple example of where describing the quantum program at the functional level can help optimize over a huge amount of options, giving solutions many orders of magnitude better than can be done manually. Additional examples include functions with multiple implementation options, uncompute strategies, ordering commutative functions and sub-functions, optimizing functions for specific hardware constraints, and more.

[1] S. Chakrabarti et al, A Threshold for Quantum Advantage in Derivative Pricing, https://quantum-journal.org/papers/q-2021-06-01-463/ (2021) [2] Stephane Beauregard. 2003. Circuit for Shor's algorithm using 2n+3 qubits. Quantum Info. Comput. 3, 2 (March 2003), 175–185.