Source code for c3.qiskit.c3_backend_utils

"""Convenience Module for creating different c3_backend
"""
from typing import Dict, List
import numpy as np
import tensorflow as tf
import math
from .c3_exceptions import C3QiskitError

GATE_MAP = {
    "x": "rxp",
    "y": "ryp",
    "z": "rzp",
    "cx": "crxp",
    "cz": "crzp",
    "I": "id",
    "u0": "id",
    "id": "id",
    "iSwap": "iswap",
}

PARAMETER_MAP = {np.pi / 2: "90p", np.pi: "p", -np.pi / 2: "90m", -np.pi: "m"}


[docs]def get_sequence(instructions: List) -> List[str]: """Return a sequence of c3 gates from Qasm instructions Parameters ---------- instructions : List[dict] Instructions from the qasm experiment, for example:: instructions: [ {"name": "u1", "qubits": [0], "params": [0.4]}, {"name": "u2", "qubits": [0], "params": [0.4,0.2]}, {"name": "u3", "qubits": [0], "params": [0.4,0.2,-0.3]}, {"name": "snapshot", "label": "snapstate1", "snapshot_type": "statevector"}, {"name": "cx", "qubits": [0,1]}, {"name": "barrier", "qubits": [0]}, {"name": "measure", "qubits": [0], "register": [1], "memory": [0]}, {"name": "u2", "qubits": [0], "params": [0.4,0.2], "conditional": 2} ] Returns ------- List[str] List of gates, for example:: sequence = ["rx90p[1]", "cr90[0,1]", "rx90p[0]"] """ sequence = [] for instruction in instructions: # TODO parametric gates iname = instruction.name # Conditional operations are not supported conditional = getattr(instructions, "conditional", None) # noqa if conditional is not None: raise C3QiskitError("C3 Simulator does not support conditional operations") # reset, binary functions is not supported elif iname in ["reset", "bfunc"]: raise C3QiskitError("C3 Simulator does not support {}".format(iname)) # barrier/measure implemented separately elif iname in ["barrier", "measure"]: pass elif iname in ["rx", "ry", "rz"]: param = instruction.params[0] suffix = [ PARAMETER_MAP[i] for i in PARAMETER_MAP.keys() if np.isclose(param, i, rtol=1e-2) ] if len(suffix) == 0: raise C3QiskitError("Only pi and pi/2 rotation gates are available") gate_name = iname + suffix[0] sequence.append(make_gate_str(instruction, gate_name)) elif iname == "rzx": param = instruction.params[0] if np.isclose(param, (np.pi / 2), rtol=1e-2): gate_name = "cr90" sequence.append(make_gate_str(instruction, gate_name)) elif np.isclose(param, (np.pi), rtol=1e-2): gate_name = "cr" sequence.append(make_gate_str(instruction, gate_name)) else: raise C3QiskitError("Only pi and pi/2 ZX gates are available") elif iname in GATE_MAP.keys(): gate_name = GATE_MAP[iname] sequence.append(make_gate_str(instruction, gate_name)) # raise C3QiskitError if unknown instruction else: raise C3QiskitError("Encountered unknown operation {}".format(iname)) return sequence
[docs]def make_gate_str(instruction: dict, gate_name: str) -> str: """Make C3 style gate name string Parameters ---------- instruction : Dict[str, Any] A dict in OpenQasm instruction format :: {"name": "rx", "qubits": [0], "params": [1.57]} gate_name : str C3 style gate names Returns ------- str C3 style gate name + qubit string :: {"name": "rx", "qubits": [0], "params": [1.57]} -> rx90p[0] """ qubits = instruction.qubits # type: ignore gate_str = gate_name + str(qubits) return gate_str
[docs]def get_init_ground_state(n_qubits: int, n_levels: int) -> tf.Tensor: """Return a perfect ground state Parameters ---------- n_qubits : int Number of qubits in the system n_levels : int Number of levels for each qubit Returns ------- tf.Tensor Tensor array of ground state shape(m^n, 1), dtype=complex128 m = no of qubit levels n = no of qubits """ psi_init = [[0] * (int)(math.pow(n_levels, n_qubits))] psi_init[0][0] = 1 init_state = tf.transpose(tf.constant(psi_init, tf.complex128)) return init_state
[docs]def flip_labels(counts: Dict[str, int]) -> Dict[str, int]: """Flip C3 qubit labels to match Qiskit qubit indexing Parameters ---------- counts : Dict[str, int] OpenQasm 2.0 result counts with original C3 style qubit indices Returns ------- Dict[str, int] OpenQasm 2.0 result counts with Qiskit style labels Note ---- Basis vector ordering in Qiskit Qiskit uses a slightly different ordering of the qubits compared to what is seen in Physics textbooks. In qiskit, the qubits are represented from the most significant bit (MSB) on the left to the least significant bit (LSB) on the right (big-endian). This is similar to bitstring representation on classical computers, and enables easy conversion from bitstrings to integers after measurements are performed. More details: https://qiskit.org/documentation/tutorials/circuits/3_summary_of_quantum_operations.html#Basis-vector-ordering-in-Qiskit """ # TODO: https://github.com/q-optimize/c3/issues/58 labels_flipped_counts = {} for key, value in counts.items(): key_bin = bin(int(key, 0)) key_bin_rev = "0b" + key_bin[:1:-1] key_rev = hex(int(key_bin_rev, 0)) labels_flipped_counts[key_rev] = value return labels_flipped_counts