# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
from typing import Dict
import numpy as np
from braket.circuits import Circuit, circuit
from braket.tasks import QuantumTask
[docs]
def constant_oracle(n_qubits: int) -> Circuit:
"""Constant oracle circuit.
Args:
n_qubits (int): Number of qubits.
Returns:
Circuit: Constant oracle circuit
"""
if n_qubits < 1:
raise ValueError(f"Number of qubits must be greater than 0. Received {n_qubits}")
circ = Circuit().i(range(n_qubits))
rand_output = np.random.randint(0, 2)
if rand_output == 0:
circ.i(n_qubits)
else:
circ.x(n_qubits)
return circ
[docs]
def balanced_oracle(n_qubits: int) -> Circuit:
"""Balanced oracle circuit.
Args:
n_qubits (int): Number of qubits.
Returns:
Circuit: Balanced oracle circuit
"""
if n_qubits < 1:
raise ValueError(f"Number of qubits must be greater than 0. Received {n_qubits}")
# generate a random array of 0s and 1s to figure out where to place x gates
random_num = np.random.randint(2, size=n_qubits)
circ = Circuit()
# place initial x gates
for qubit in range(n_qubits):
if random_num[qubit] == 1:
circ.x(qubit)
# place cnot gates
for qubit in range(n_qubits):
circ.cnot(control=qubit, target=n_qubits)
# place final x gates
for qubit in range(n_qubits):
if random_num[qubit] == 1:
circ.x(qubit)
return circ
[docs]
def deutsch_jozsa_circuit(oracle: Circuit) -> Circuit:
"""Deutsch-Jozsa circuit.
Args:
oracle (Circuit): Constant or balanced oracle circuit.
Returns:
Circuit: The Deutsch-Jozsa circuit and result types.
"""
n_qubits = oracle.qubit_count - 1
circ = Circuit()
circ.deutsch_jozsa(oracle)
circ.probability(range(n_qubits))
return circ
[docs]
@circuit.subroutine(register=True)
def deutsch_jozsa(oracle: Circuit) -> Circuit:
"""Deutsch-Jozsa subroutine.
Args:
oracle (Circuit): Constant or balanced oracle circuit.
Returns:
Circuit: The Deutsch-Jozsa circuit.
"""
n_qubits = oracle.qubit_count - 1
circ = Circuit()
circ.h(range(n_qubits))
circ.x(n_qubits)
circ.h(n_qubits)
circ.add_circuit(oracle)
circ.h(range(n_qubits))
return circ
[docs]
def get_deutsch_jozsa_results(task: QuantumTask) -> Dict[str, float]:
"""Return the probabilities and corresponding bitstrings.
Args:
task (QuantumTask): Quantum task to process.
Returns:
Dict[str, float]: Results as a dictionary of bitstrings
"""
probabilities = task.result().result_types[0].value
probabilities = np.round(probabilities, 10) # round off floating-point errors
num_qubits = int(np.log2(len(probabilities)))
binary_strings = [format(i, "b").zfill(num_qubits) for i in range(2**num_qubits)]
return dict(zip(binary_strings, probabilities))