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()
# Make sure the static image is drawn
preferences = Preferences(draw_image=True)
circuit = model_designer.synthesize(preferences=preferences)
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:
Multiple locations are checked1, according to the following order:
classiq-host: "https://myclassiqbackend.com"
/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 inclassiq.config
) and pass it on as an argument to the functionclassiq.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, RegisterUserInput, Executor
from classiq.builtin_functions import ArithmeticOracle, GroverOperator
from classiq.execution 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_async(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.
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.
The log with the error message.
-
The
/etc
folder is commonly used for system-wide configuration,~/.config
is used for user-wide configutaion, andclassiq/config.ini
is relative to the currend working directory. ↩