Skip to content

Advanced Usage

Running with Jupyter Notebook

The Classiq SDK automatically identifies whether it runs in Jupyter Notebook, and adjusts accordingly. However, if Classiq does not identify Jupyter, you can execute this code snippet:

import classiq

classiq.enable_jupyter_notebook()

Configuration

There are multiple ways to configure the SDK.

  • Configuration file: A file with .ini or .yaml style syntax. For example:
    classiq-host: "https://myclassiqbackend.com"
    
    Multiple locations are checked1 according to the following order:
    • /etc/classiq/config.ini
    • /etc/classiq.conf
    • ~/.config/classiq/config.ini
    • ~/.config/classiq.conf
    • classiq/config.ini
  • Command line argument
  • Environment variables
  • Dynamic configuration: You can configure the SDK within the Python script. Create a Configuration object (defined in classiq.config) and pass it on as an argument to the function classiq.configure, as in the example below.

    import classiq
    
    conf = classiq.Configuration(host="https://myclassiqbackend.com")
    classiq.configure(conf=conf)
    

These configuration options are supported:

  • classiq-host - This flag determines the backend host URL. By default, the SDK works against the Classiq public domain, but you might want to reconfigure it to work against a different URL.
  • classiq-config-file - This flag determines the configuration file used by the SDK. By default, the SDK looks for a configuration file under /classiq/config.ini, but you can configure a different path using either command line arguments or environment variables.
  • classiq-skip-check-host - This flag disables the validation of the SDK version. By default, the SDK checks that it is compatible with the backend version when the connection between them is established. If this flag is present, this check is suppressed.
  • text-only - This flag disables some operations that rely on GUI, such as using the browser for authentication. This flag can also be activated using the CLASSIQ_TEXT_ONLY environment variable.

Concurrent Programming

All the Python SDK functions have both synchronous (sync) and asynchronous (async) versions. The async versions are named function_async. For example, synthesize is the sync version, and synthesize_async is the async version.

Synchronous functions work like typical Python functions, and block the execution until they finish. Asynchronous functions can be executed concurrently for increased efficiency. Refer to Python docs - asyncio.

Example

This example generates and executes multiple quantum programs concurrently, cutting execution time by half:

  • Synchronous code executes the second quantum program only after the first one finishes.
  • Asynchronous code runs them in parallel.

This specific example uses the Grover search algorithm:

import asyncio

from classiq import (
    synthesize_async,
    execute_async,
    construct_grover_model,
    RegisterUserInput,
)
from classiq.execution import ExecutionDetails


async def execute_qprog(expression):
    print(f"Setting up qprog: {expression=}")
    grover_model = construct_grover_model(
        definitions=[
            ("a", RegisterUserInput(size=4)),
            ("b", RegisterUserInput(size=4, is_signed=True)),
        ],
        expression=expression,
        num_reps=4,
    )

    qprog = await synthesize_async(grover_model)
    print(f"qprog synthesis complete! {expression=}")

    job = await execute_async(qprog)
    res = await job.result_async()
    results = res[0].value
    print(f"qprog execution done! {expression=}")
    output_results = dict(
        filter(
            lambda key_value_pair: key_value_pair[1] > 10,
            results.counts_of_multiple_outputs(["a", "b"]).items(),
        )
    )
    print(f"\tResult: {output_results}")


async def main():
    expressions = [
        "a + b == 7 and a & b == 8",
        "a + b == 5 and a & b == 2",
    ]

    all_qprog_executors = await asyncio.gather(
        *[execute_qprog(expression) for expression in expressions]
    )

    print("Done!")


asyncio.run(main())

Possible output:

Setting up qprog: expression='a + b == 7 and a & b == 8'
Setting up qprog: expression='a + b == 5 and a & b == 2'
qprog synthesis complete! expression='a + b == 7 and a & b == 8'
qprog synthesis complete! expression='a + b == 5 and a & b == 2'
qprog execution done! expression='a + b == 7 and a & b == 8'
    Result: {('1101', '0011'): 135, ('0011', '1101'): 115, ('1001', '0111'): 114, ('0111', '1001'): 122, ('1111', '0001'): 134, ('1011', '0101'): 129, ('0101', '1011'): 130, ('0001', '1111'): 121}
qprog execution done! expression='a + b == 5 and a & b == 2'
    Result: {('1100', '0100'): 246, ('0100', '1100'): 261}
Done!

  1. The /etc folder is commonly used for system-wide configuration, ~/.config is for user-wide configuration, and classiq/config.ini is relative to the current working directory.