Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update: restricting parameter names to not collide with ones we use for OpenQASM generation. #675

Merged
merged 14 commits into from
Aug 21, 2023
6 changes: 3 additions & 3 deletions src/braket/circuits/circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1212,7 +1212,7 @@ def _to_openqasm(
)
for idx, qubit in enumerate(qubits):
qubit_target = serialization_properties.format_target(int(qubit))
ir_instructions.append(f"b[{idx}] = measure {qubit_target};")
ir_instructions.append(f"__bits__[{idx}] = measure {qubit_target};")

return OpenQasmProgram.construct(source="\n".join(ir_instructions), inputs={})

Expand All @@ -1225,11 +1225,11 @@ def _create_openqasm_header(
for parameter in self.parameters:
ir_instructions.append(f"input float {parameter};")
if not self.result_types:
ir_instructions.append(f"bit[{self.qubit_count}] b;")
ir_instructions.append(f"bit[{self.qubit_count}] __bits__;")

if serialization_properties.qubit_reference_type == QubitReferenceType.VIRTUAL:
total_qubits = max(self.qubits).real + 1
ir_instructions.append(f"qubit[{total_qubits}] q;")
ir_instructions.append(f"qubit[{total_qubits}] __qubits__;")
elif serialization_properties.qubit_reference_type != QubitReferenceType.PHYSICAL:
raise ValueError(
f"Invalid qubit_reference_type "
Expand Down
4 changes: 2 additions & 2 deletions src/braket/circuits/serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class OpenQASMSerializationProperties:
Properties for serializing a circuit to OpenQASM.

qubit_reference_type (QubitReferenceType): determines whether to use
logical qubits or physical qubits (q[i] vs $i).
logical qubits or physical qubits (__qubits__[i] vs $i).
"""

qubit_reference_type: QubitReferenceType = QubitReferenceType.VIRTUAL
Expand All @@ -53,7 +53,7 @@ def format_target(self, target: int) -> str:
str: The OpenQASM representation of the target qubit.
"""
qubit_reference_format = (
"q[{}]" if self.qubit_reference_type == QubitReferenceType.VIRTUAL else "${}"
"__qubits__[{}]" if self.qubit_reference_type == QubitReferenceType.VIRTUAL else "${}"
)
return qubit_reference_format.format(target)

Expand Down
16 changes: 15 additions & 1 deletion src/braket/parametric/free_parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,13 @@ def __init__(self, name: str):

Args:
name (str): Name of the :class:'FreeParameter'. Can be a unicode value.
Must not start with '__'.

Examples:
>>> param1 = FreeParameter("theta")
>>> param1 = FreeParameter("\u03B8")
"""
self._name = Symbol(name)
self._set_name(name)
super().__init__(expression=self._name)

@property
Expand Down Expand Up @@ -99,6 +100,19 @@ def to_dict(self) -> dict:
"name": self.name,
}

def _set_name(self, name: str) -> None:
FreeParameter._validate_name(name)
self._name = Symbol(name)

@staticmethod
def _validate_name(name: str) -> None:
AbeCoull marked this conversation as resolved.
Show resolved Hide resolved
if not name:
raise ValueError("FreeParameter names must be non empty")
if not isinstance(name, str):
raise TypeError("FreeParameter names must be strings")
if name.startswith("__"):
raise ValueError("FreeParameter names must not start with two underscores '__'")

@classmethod
def from_dict(cls, parameter: dict) -> FreeParameter:
return FreeParameter(parameter["name"])
4 changes: 2 additions & 2 deletions src/braket/pulse/ast/qasm_transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ def visit_ExpressionStatement(self, expression_statement: ast.ExpressionStatemen
):
# For capture_v0 nodes, it replaces it with classical assignment statements
# of the form:
# b[0] = capture_v0(...)
# b[1] = capture_v0(...)
# __bits__[0] = capture_v0(...)
# __bits__[1] = capture_v0(...)
new_val = ast.ClassicalAssignment(
# Ideally should use IndexedIdentifier here, but this works since it is just
# for printing.
Expand Down
32 changes: 17 additions & 15 deletions test/integ_tests/test_adjoint_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ def test_adjoint_gradient_quantum_task_with_nested_targets(
expected_openqasm = (
"OPENQASM 3.0;\n"
"input float theta;\n"
"qubit[4] q;\n"
"rx(theta) q[0];\n"
"#pragma braket result adjoint_gradient expectation(-6 * y(q[0]) @ i(q[1]) + 0.75 * "
"y(q[2]) @ z(q[3])) theta"
"qubit[4] __qubits__;\n"
"rx(theta) __qubits__[0];\n"
"#pragma braket result adjoint_gradient expectation(-6 * "
"y(__qubits__[0]) @ i(__qubits__[1]) + 0.75 * y(__qubits__[2]) @ z(__qubits__[3])) theta"
)

gradient_task = AwsQuantumTask.create(
Expand Down Expand Up @@ -83,10 +83,10 @@ def test_adjoint_gradient_with_standard_observable_terms(
expected_openqasm = (
"OPENQASM 3.0;\n"
"input float theta;\n"
"qubit[3] q;\n"
"rx(theta) q[0];\n"
"#pragma braket result adjoint_gradient expectation(2 * x(q[0]) + 3 * y(q[1]) "
"- 1 * z(q[2])) theta"
"qubit[3] __qubits__;\n"
"rx(theta) __qubits__[0];\n"
"#pragma braket result adjoint_gradient expectation(2 * "
"x(__qubits__[0]) + 3 * y(__qubits__[1]) - 1 * z(__qubits__[2])) theta"
)

gradient_task = AwsQuantumTask.create(
Expand Down Expand Up @@ -132,17 +132,19 @@ def test_adjoint_gradient_with_batch_circuits(aws_session, s3_destination_folder
(
"OPENQASM 3.0;\n"
"input float theta;\n"
"qubit[2] q;\n"
"rx(theta) q[0];\n"
"#pragma braket result adjoint_gradient expectation(6 * y(q[0]) @ i(q[1])) theta"
"qubit[2] __qubits__;\n"
"rx(theta) __qubits__[0];\n"
"#pragma braket result adjoint_gradient expectation(6 *"
" y(__qubits__[0]) @ i(__qubits__[1])) theta"
),
(
"OPENQASM 3.0;\n"
"input float theta;\n"
"qubit[2] q;\n"
"rx(theta) q[0];\n"
"#pragma braket result adjoint_gradient expectation(-6 * y(q[0]) @ i(q[1]) + 0.75 * "
"y(q[0]) @ z(q[1])) theta"
"qubit[2] __qubits__;\n"
"rx(theta) __qubits__[0];\n"
"#pragma braket result adjoint_gradient expectation(-6 *"
" y(__qubits__[0]) @ i(__qubits__[1]) + 0.75 *"
" y(__qubits__[0]) @ z(__qubits__[1])) theta"
),
]

Expand Down
6 changes: 3 additions & 3 deletions test/unit_tests/braket/aws/test_aws_quantum_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -573,12 +573,12 @@ def test_create_pulse_gate_circuit(
expected_openqasm = "\n".join(
(
"OPENQASM 3.0;",
"bit[2] b;",
"bit[2] __bits__;",
"cal {",
" set_frequency(predefined_frame_1, 6000000.0);",
"}",
"b[0] = measure $0;",
"b[1] = measure $1;",
"__bits__[0] = measure $0;",
"__bits__[1] = measure $1;",
)
)

Expand Down
Loading