Source code for uniqc.circuit_builder.random_qasm

"""Random OpenQASM 2.0 circuit generator.

This module provides functions for generating random quantum circuits in OpenQASM
2.0 format. It supports random gate selection, measurement generation, and
circuit construction from opcode lists.

Key exports:
    build_qasm_gate: Build a single QASM gate string.
    build_full_measurements: Generate measurement instructions for all qubits.
    build_measurements: Generate measurement instructions for specified qubits.
    random_qasm: Generate a complete random QASM program.
    build_qasm_from_opcodes: Convert a list of opcodes to QASM code.
"""

import random
from typing import List
from .qasm_spec import available_qasm_gates
from uniqc.circuit_builder.qcircuit import OpcodeType

__all__ = [
    "build_qasm_gate",
    "build_full_measurements",
    "build_measurements",
    "random_qasm",
    "build_qasm_from_opcodes",
]


[docs] def build_qasm_gate(gate, qubits, params, qreg_name="q"): """ Build a QASM gate string with the given gate, qubits, and parameters. Args: gate (str): name of the gate qubits (List[int]): list of qubits the gate acts on params (List[float]): list of parameters of the gate Returns: str: a QASM gate string """ if not qubits: raise ValueError("No qubits specified for gate") gate_with_params = f"{gate}" if params: param_strs = [f"{param}" for param in params] gate_with_params += "(" gate_with_params += ",".join(param_strs) gate_with_params += ")" qreg_strs = [f"{qreg_name}[{qubit}]" for qubit in qubits] qreg_str = ",".join(qreg_strs) qasm_gate = f"{gate_with_params} {qreg_str};" return qasm_gate
[docs] def build_full_measurements(n_qubits, qreg_name="q", creg_name="c"): """ Build a QASM string that measures all qubits in the given qreg to the given creg. Args: n_qubits (int): number of qubits to measure qreg_name (str): name of the qreg to measure from creg_name (str): name of the creg to measure to Returns: List[str]: a list of QASM strings that measure all qubits in the given qreg to the given creg. """ measure_instructions = [] for i in range(n_qubits): measure_instructions.append(f"measure {qreg_name}[{i}] -> {creg_name}[{i}];") return measure_instructions
[docs] def build_measurements(measure_qbit_cbit_pairs, qreg_name="q", creg_name="c"): """ Build a QASM string that measures specified qubits to classical bits. Args: measure_qbit_cbit_pairs: Iterable of (qubit_index, cbit_index) tuples. qreg_name (str): name of the quantum register. creg_name (str): name of the classical register. Returns: List[str]: a list of QASM measurement instructions. """ measure_instructions = [] for qbit, cbit in measure_qbit_cbit_pairs: measure_instructions.append(f"measure {qreg_name}[{qbit}] -> {creg_name}[{cbit}];") return measure_instructions
[docs] def random_qasm(n_qubits, n_gates, instruction_set=available_qasm_gates, measurements=True): """ Generate a random QASM code with n_qubits and n_gates from the given instruction set. Args: n_qubits (int): number of qubits in the circuit n_gates (int): number of gates in the circuit instruction_set (Dict): list of valid QASM instructions Returns: str: a random QASM code """ qasm = [ "OPENQASM 2.0;", 'include "qelib1.inc";', f"qreg q[{n_qubits}];", f"creg c[{n_qubits}];", "// auto-generated by uniqc;", ] instructions = list(instruction_set.keys()) for i in range(n_gates): gate = random.choice(instructions) nqubit = instruction_set[gate]["qubit"] nparam = instruction_set[gate]["params"] qubits = random.sample(range(n_qubits), nqubit) params = [random.uniform(0, 2 * 3.14159) for _ in range(nparam)] qasm_gate = build_qasm_gate(gate, qubits, params, "q") qasm.append(qasm_gate) if measurements: qasm.extend(build_full_measurements(n_qubits, "q", "c")) return "\n".join(qasm)
[docs] def build_qasm_from_opcodes(opcode_list: List[OpcodeType], measure_qbit_cbit=None, qreg_name="q", creg_name="c"): """ Generate a QASM code from a list of opcodes. Args: opcode_list (List[Tuple[str, List[int], List[float]]]): a list of tuples containing the gate name, qubits, and parameters measure_qbit_cbit (List[Tuple[int, int]]): a list of tuples containing the qubit and cbit to measure qreg_name (str): name of the qreg to measure from creg_name (str): name of the creg to measure to Returns: str: a QASM code """ # determine the number of qubits in the circuit n_qubits = 0 for opcode in opcode_list: qubits = opcode[1] if isinstance(qubits, int): qubits = [qubits] n_qubits = max(n_qubits, max(qubits) + 1) # build the QASM code qasm = [ "OPENQASM 2.0;", 'include "qelib1.inc";', f"qreg {qreg_name}[{n_qubits}];", f"creg {creg_name}[{n_qubits}];", "// auto-generated by uniqc;", ] for opcode in opcode_list: gate = opcode[0] qubits = opcode[1] cbits = opcode[2] params = opcode[3] dagger_flag = opcode[4] control_qubit_set = opcode[5] # dagger flag and control qubits are not supported yet if dagger_flag or control_qubit_set: raise NotImplementedError("Dagger and control qubits are not supported yet") # build the QASM gate string qasm_gate = build_qasm_gate(gate, qubits, params, qreg_name) qasm.append(qasm_gate) if measure_qbit_cbit is not None: qbit_list, cbit_list = zip(*measure_qbit_cbit) qasm.extend(build_measurements(zip(qbit_list, cbit_list), qreg_name, creg_name)) return "\n".join(qasm)