"""Amazon Braket made the choice to directly support a subset of OpenQASM 3.0
for gate-based devices and simulators. In fact, Braket supports a set of data
types, statements and pragmas (specific to Braket) for OpenQASM 3.0, sometimes
with a different syntax.
Braket Circuit parser does not support for the moment the OpenQASM 3.0 native
operations (``U`` and ``gphase``) but allows to define custom gates using a
combination of supported standard gates (``rx``, ``ry``, ``rz``, ``cnot``,
``phaseshift`` for instance). Besides, the inclusion of files is not yet handled
by Braket library meaning we use a mechanism of *hard* includes (see
:func:`open_qasm_hard_includes<mpqp.qasm.qasm_to_myqlm.hard-open_qasm_hard_includes>`)
directly in the OpenQASM 3.0 code, to be sure the parser and interpreter have
all definitions in there. We also hard-include all included files in the
OpenQASM 3.0 code inputted for conversion.
.. note::
In the custom hard-imported file for native and standard gate redefinitions,
we use ``ggphase`` to define the global phase, instead of the OpenQASM 3.0
keyword ``gphase``, which is already used and protected by Braket.
Braket ``Circuit``s are created using :func:`qasm3_to_braket_Circuit`. If
needed, you can also generate a Braket ``Program`` from an OpenQASM 3.0 input
string using the :func:`qasm3_to_braket_Program`. However, in this case, the
program parser does not need to redefine the native gates, and thus only
performing a hard import of standard gates and other included file is
sufficient. However, note that a ``Program`` cannot be used to retrieve the
statevector and expectation value in Braket.
"""
import io
import warnings
from logging import StreamHandler, getLogger
from typing import TYPE_CHECKING
from typeguard import typechecked
if TYPE_CHECKING:
from braket.ir.openqasm import Program
from braket.circuits import Circuit
from mpqp.qasm.open_qasm_2_and_3 import open_qasm_hard_includes
from mpqp.tools.errors import UnsupportedBraketFeaturesWarning
[docs]@typechecked
def qasm3_to_braket_Program(qasm3_str: str) -> "Program":
"""Converting a OpenQASM 3.0 code into a Braket Program.
Args:
qasm3_str: A string representing the OpenQASM 3.0 code.
Returns:
A Program equivalent to the QASM code in parameter.
"""
from braket.ir.openqasm import Program
# PROBLEM: import and standard gates are not supported by Braket
# NOTE: however custom OpenQASM 3 gates declaration is supported by Braket,
# the idea is then to hard import the standard lib and other files into the qasm string's header before
# giving it to the Program.
after_stdgates_included = open_qasm_hard_includes(qasm3_str, set())
program = Program(source=after_stdgates_included, inputs=None)
return program
[docs]@typechecked
def qasm3_to_braket_Circuit(qasm3_str: str) -> "Circuit":
"""Converting a OpenQASM 3.0 code into a Braket Circuit.
Args:
qasm3_str: A string representing the OpenQASM 3.0 code.
Returns:
A Circuit equivalent to the QASM code in parameter.
"""
# PROBLEM: import and standard gates are not supported by Braket
# NOTE: however custom OpenQASM 3 gates declaration is supported by Braket,
# SOLUTION: the idea is then to hard import the standard lib and other files into the qasm string's header before
# giving it to the Circuit.
# PROBLEM2: Braket doesn't support NATIVE freaking gates U and gphase, so the trick may not work for the moment
# for circuit, only for program
# SOLUTION: import a specific qasm file with U and gphase redefined with the supported Braket SDK gates, and by
# removing from this import file the already handled gates
from braket.circuits import Circuit
qasm3_str = qasm3_str.replace("stdgates.inc", "braket_custom_include.inc")
after_stdgates_included = open_qasm_hard_includes(qasm3_str, set())
braket_warning_message = (
"This program uses OpenQASM language features that may not be supported"
" on QPUs or on-demand simulators."
)
braket_logger = getLogger()
logger_output_stream = io.StringIO()
stream_handler = StreamHandler(logger_output_stream)
braket_logger.addHandler(stream_handler)
circuit = Circuit.from_ir(after_stdgates_included)
braket_logger.removeHandler(stream_handler)
log_lines = logger_output_stream.getvalue().split("\n")
for message in log_lines:
if message == braket_warning_message:
warnings.warn(
"\n" + braket_warning_message, UnsupportedBraketFeaturesWarning
)
else:
braket_logger.warning(message)
return circuit