Skip to content

Advanced Usage

Running with Jupyter Notebook

classiq SDK automatically identifies whether it runs in jupyter notebook, and adjusts itself. However, in a case where classiq doesn't identify jupyter, one may execute executes the following code snippet.

import classiq

classiq.enable_jupyter_notebook()

Images in Jupyter Notebook

Jupyter notebook automatically handles embeding pictures as outputs, thus, the following code can be useful for viewing circuits:

# Generate the circuit
model_designer = ModelDesigner()
circuit = model_designer.synthesize()

circuit.image

When a Jupyter Notebook block ends, the last return value will be presented. In the case of the code above, circuit.image is of type PIL.Image (from the Pillow package), thus, it will render as an image in the output of that code-block. circuit.image.show() can also be used, in which case, an image will open in the default image-viewer software.

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. Simply 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)
    

The following configuration options are supported:

  • classiq-host - This flag determines the backend host URL. By default, the SDK works against Classiq's public domain, but one might want to reconfigure it 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 using either command line arguments or environment variables, one can configure a different path.
  • classiq-skip-check-host - This flags disables the validation of the SDK's version. By default, the SDK checks that it's compatible with the backend version when the connection between them is established. If this flag is present, this check is suppressed.

Concurrent programming

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

Synchronous functions work like regular python functions, and block the execution until they are finished. Asynchronous functions can be executed concurrently for increased efficiency. For more details, please refer to Python docs - asyncio

Example:

This example generates and executes multiple circuits concurrently, cutting execution time by half. A synchronous code would execute the second circuit only after the first one finished. Asynchronous code runs them in parallel.

import asyncio

from classiq import ModelDesigner
from classiq.builtin_functions import ArithmeticOracle, GroverOperator
from classiq.interface.generator.arith.arithmetic import RegisterUserInput

from classiq import Executor
from classiq.interface.executor.execution_preferences import (
    ExecutionPreferences,
    AmplitudeAmplification,
)


async def execute_circuit(expression, preferences):
    print(f"Setting up circuit: {expression=}")
    oracle_params = ArithmeticOracle(
        expression=expression,
        definitions=dict(
            a=RegisterUserInput(size=4),
            b=RegisterUserInput(size=4, is_signed=True),
        ),
        uncomputation_method="optimized",
        qubit_count=25,
    )
    grover_params = GroverOperator(oracle=oracle_params)

    model_designer = ModelDesigner()
    model_designer.GroverOperator(grover_params)

    circuit = await model_designer.synthesize_async()
    print(f"Circuit generation complete! {expression=}")

    result = await Executor(preferences=preferences).execute_generated_circuit_async(
        generation_result=circuit
    )
    print(f"Circuit execution done! {expression=}")
    print(f"\tResult: {result.result}")


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

    preferences = ExecutionPreferences(
        amplitude_amplification=AmplitudeAmplification(
            growth_rate=2, sample_from_iterations=False
        )
    )

    all_circuit_executors = await asyncio.gather(
        *[execute_circuit(expression, preferences) for expression in expressions]
    )

    print("Done!")


asyncio.run(main())

Possible output:

Setting up circuit: expression='a + b == 7 and a & b == 8'
Setting up circuit: expression='a + b == 5 and a & b == 2'
Circuit generation complete! expression='a + b == 7 and a & b == 8'
Circuit generation complete! expression='a + b == 5 and a & b == 2'
Circuit execution done! expression='a + b == 7 and a & b == 8'
    Result: {'a': 14.0, 'b': -7.0}
Circuit execution done! expression='a + b == 5 and a & b == 2'
    Result: {'a': 2.0, 'b': 3.0}
Done!

Troubleshooting

Debugging logs

The classiq platform produces logs for debugging purposes containing the outcomes of operations (e.g. circuit generation or circuit analysis) and error messages. When using textual model (VS-code extension), the logs can be viewed by opening the command palette (using Ctrl+Shift+P / Command+Shift+P on Windows/Mac, respectively), choosing the "Developer: show logs" option and then choosing the "Extension host" option from the drop down menu, as shown in the figure below. Once a log has been created it can be viewed by choosing the "classiq" option from the drop down menu on the right hand side of the output window. The log will appear in the output window.

alt text

The log of a (successful) generation of a circuit includes the qasm string of the generated circuit and additional data (mainly a long string encoding the graphical representation of the output circuit). An unsuccessful generation attempt of a circuit would produce a log with an error message providing details about the generation failure.

Example - error in generation of a state-preparation circuit.

In this example the model file for generating a state-preparation circuit specifies probabilities which do not sum to one. the generation fails and log specifies the error.

alt text

The log with the error message.

alt text


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