Skip to content

Exporters

Exporters convert EncodedResult objects into framework-specific circuit objects.

All exporters expose:

  • export(encoded) — single sample
  • export_batch(encoded_list) — full batch

QASMExporter

No dependencies. Universal OpenQASM 3.0 output.

quprep.export.qasm_export.QASMExporter(version='3.0')

Export EncodedResult objects to OpenQASM 3.0.

No additional dependencies required.

Parameters:

Name Type Description Default
version str

QASM version. Currently only '3.0' is supported.

'3.0'
Source code in quprep/export/qasm_export.py
def __init__(self, version: str = "3.0"):
    if version != "3.0":
        raise ValueError("Only OpenQASM 3.0 is supported.")
    self.version = version

Functions

export(encoded)

Convert an EncodedResult to an OpenQASM 3.0 string.

Parameters:

Name Type Description Default
encoded EncodedResult

Output from any QuPrep encoder (except amplitude).

required

Returns:

Type Description
str

OpenQASM 3.0 circuit string, compatible with Qiskit, Cirq, and hardware backends.

Source code in quprep/export/qasm_export.py
def export(self, encoded) -> str:
    """
    Convert an EncodedResult to an OpenQASM 3.0 string.

    Parameters
    ----------
    encoded : EncodedResult
        Output from any QuPrep encoder (except amplitude).

    Returns
    -------
    str
        OpenQASM 3.0 circuit string, compatible with Qiskit, Cirq,
        and hardware backends.
    """
    encoding = encoded.metadata.get("encoding", "unknown")
    if encoding == "angle":
        return self._export_angle(encoded)
    if encoding == "entangled_angle":
        return self._export_entangled_angle(encoded)
    if encoding == "basis":
        return self._export_basis(encoded)
    if encoding == "iqp":
        return self._export_iqp(encoded)
    if encoding == "reupload":
        return self._export_reupload(encoded)
    if encoding == "hamiltonian":
        return self._export_hamiltonian(encoded)
    if encoding == "zz_feature_map":
        return self._export_zz_feature_map(encoded)
    if encoding == "pauli_feature_map":
        return self._export_pauli_feature_map(encoded)
    if encoding == "random_fourier":
        # RFF output is angle-encoded; requires minmax_pi normalizer
        return self._export_angle(encoded)
    if encoding == "tensor_product":
        return self._export_tensor_product(encoded)
    if encoding == "qaoa_problem":
        return self._export_qaoa_problem(encoded)
    if encoding == "graph_state":
        return self._export_graph_state(encoded)
    if encoding == "dense_angle":
        return self._export_dense_angle(encoded)
    if encoding == "discretized":
        return self._export_basis(encoded)  # same structure: X gates where bit=1
    if encoding == "amplitude":
        raise NotImplementedError(
            "Amplitude encoding requires exponential-depth state preparation "
            "which cannot be expressed as a simple QASM snippet. "
            "Use QiskitExporter for amplitude encoding."
        )
    if encoded.circuit_fn is not None:
        return encoded.circuit_fn()
    raise ValueError(
        f"Unknown encoding '{encoding}'. "
        "Supported: angle, entangled_angle, basis, iqp, zz_feature_map, "
        "pauli_feature_map, random_fourier, tensor_product, qaoa_problem, "
        "reupload, hamiltonian, graph_state, dense_angle, discretized."
    )

export_batch(encoded_list)

Export a list of EncodedResults to QASM strings.

Parameters:

Name Type Description Default
encoded_list list of EncodedResult
required

Returns:

Type Description
list of str

One OpenQASM 3.0 string per sample.

Source code in quprep/export/qasm_export.py
def export_batch(self, encoded_list: list) -> list[str]:
    """
    Export a list of EncodedResults to QASM strings.

    Parameters
    ----------
    encoded_list : list of EncodedResult

    Returns
    -------
    list of str
        One OpenQASM 3.0 string per sample.
    """
    return [self.export(e) for e in encoded_list]

save(encoded, path)

Export an EncodedResult and write the QASM string to a file.

Parameters:

Name Type Description Default
encoded EncodedResult

Output from any QuPrep encoder.

required
path str or Path

Destination file path (e.g. 'circuit.qasm').

required
Source code in quprep/export/qasm_export.py
def save(self, encoded, path: str | Path) -> None:
    """
    Export an EncodedResult and write the QASM string to a file.

    Parameters
    ----------
    encoded : EncodedResult
        Output from any QuPrep encoder.
    path : str or Path
        Destination file path (e.g. ``'circuit.qasm'``).
    """
    qasm_str = self.export(encoded)
    Path(path).write_text(qasm_str, encoding="utf-8")

save_batch(encoded_list, directory, stem='circuit')

Export a batch of EncodedResults to individual QASM files.

Files are named {stem}_0000.qasm, {stem}_0001.qasm, etc. The output directory is created automatically if it does not exist.

Parameters:

Name Type Description Default
encoded_list list of EncodedResult

Outputs from any QuPrep encoder.

required
directory str or Path

Output directory.

required
stem str

Filename stem (default: 'circuit').

'circuit'

Returns:

Type Description
list of Path

Paths of the written files, in sample order.

Source code in quprep/export/qasm_export.py
def save_batch(
    self,
    encoded_list: list,
    directory: str | Path,
    stem: str = "circuit",
) -> list[Path]:
    """
    Export a batch of EncodedResults to individual QASM files.

    Files are named ``{stem}_0000.qasm``, ``{stem}_0001.qasm``, etc.
    The output directory is created automatically if it does not exist.

    Parameters
    ----------
    encoded_list : list of EncodedResult
        Outputs from any QuPrep encoder.
    directory : str or Path
        Output directory.
    stem : str
        Filename stem (default: ``'circuit'``).

    Returns
    -------
    list of Path
        Paths of the written files, in sample order.
    """
    directory = Path(directory)
    directory.mkdir(parents=True, exist_ok=True)
    paths = []
    for i, encoded in enumerate(encoded_list):
        path = directory / f"{stem}_{i:04d}.qasm"
        self.save(encoded, path)
        paths.append(path)
    return paths

QiskitExporter

Requires pip install quprep[qiskit].

quprep.export.qiskit_export.QiskitExporter(backend=None)

Export EncodedResult objects to Qiskit QuantumCircuit.

Requires: pip install quprep[qiskit]

Parameters:

Name Type Description Default
backend str

IBM backend name (e.g. 'ibm_brisbane'). Reserved for transpilation hints in a future release — currently stored but not applied.

None
Source code in quprep/export/qiskit_export.py
def __init__(self, backend: str | None = None):
    self.backend = backend
    self._check_qiskit()

Functions

export(encoded)

Convert an EncodedResult to a Qiskit QuantumCircuit.

Parameters:

Name Type Description Default
encoded EncodedResult

Output from any QuPrep encoder.

required

Returns:

Type Description
QuantumCircuit

Ready-to-transpile Qiskit circuit.

Source code in quprep/export/qiskit_export.py
def export(self, encoded) -> qiskit.QuantumCircuit:
    """
    Convert an EncodedResult to a Qiskit QuantumCircuit.

    Parameters
    ----------
    encoded : EncodedResult
        Output from any QuPrep encoder.

    Returns
    -------
    qiskit.QuantumCircuit
        Ready-to-transpile Qiskit circuit.
    """
    from qiskit import QuantumCircuit

    encoding = encoded.metadata.get("encoding", "unknown")
    n_qubits = encoded.metadata["n_qubits"]
    params = encoded.parameters

    qc = QuantumCircuit(n_qubits)

    if encoding == "angle" or encoding == "random_fourier":
        rotation = encoded.metadata.get("rotation", "ry")
        gate_fn = getattr(qc, rotation)
        for i, angle in enumerate(params):
            gate_fn(float(angle), i)

    elif encoding == "entangled_angle":
        rotation = encoded.metadata.get("rotation", "ry")
        layers = encoded.metadata.get("layers", 1)
        cnot_pairs = encoded.metadata.get("cnot_pairs", [])
        gate_fn = getattr(qc, rotation)
        for _ in range(layers):
            for i, angle in enumerate(params):
                gate_fn(float(angle), i)
            for ctrl, tgt in cnot_pairs:
                qc.cx(ctrl, tgt)

    elif encoding == "basis":
        for i, bit in enumerate(params):
            if bit == 1.0:
                qc.x(i)

    elif encoding == "iqp":
        d = n_qubits
        reps = encoded.metadata.get("reps", 2)
        x = params[:d]
        pair_angles = params[d:]
        for _ in range(reps):
            for i in range(d):
                qc.h(i)
            for i in range(d):
                qc.rz(float(x[i]), i)
            idx = 0
            for i in range(d):
                for j in range(i + 1, d):
                    angle = float(pair_angles[idx])
                    qc.cx(i, j)
                    qc.rz(angle, j)
                    qc.cx(i, j)
                    idx += 1

    elif encoding == "reupload":
        layers = encoded.metadata.get("layers", 3)
        rotation = encoded.metadata.get("rotation", "ry")
        gate_fn = getattr(qc, rotation)
        for _ in range(layers):
            for i, angle in enumerate(params):
                gate_fn(float(angle), i)

    elif encoding == "hamiltonian":
        trotter_steps = encoded.metadata.get("trotter_steps", 4)
        for _ in range(trotter_steps):
            for i, angle in enumerate(params):
                qc.rz(float(angle), i)

    elif encoding == "zz_feature_map":
        reps = encoded.metadata.get("reps", 2)
        single_angles = encoded.metadata["single_angles"]
        pair_angles = encoded.metadata["pair_angles"]
        pairs = encoded.metadata["pairs"]
        for _ in range(reps):
            for i in range(n_qubits):
                qc.h(i)
            for i, angle in enumerate(single_angles):
                qc.rz(float(angle), i)
            for (i, j), angle in zip(pairs, pair_angles):
                qc.cx(i, j)
                qc.rz(float(angle), j)
                qc.cx(i, j)

    elif encoding == "pauli_feature_map":
        reps = encoded.metadata.get("reps", 2)
        single_terms = encoded.metadata.get("single_terms", {})
        pair_terms = encoded.metadata.get("pair_terms", {})
        _gate = {"X": "rx", "Y": "ry", "Z": "rz"}
        _conj_pre = {"XX": "h", "YY": "sdg", "ZZ": None}
        _conj_post = {"XX": "h", "YY": "s", "ZZ": None}
        for _ in range(reps):
            for i in range(n_qubits):
                qc.h(i)
            for pauli, angles in single_terms.items():
                gate_fn = getattr(qc, _gate[pauli])
                for i, angle in enumerate(angles):
                    gate_fn(float(angle), i)
            for pauli, entries in pair_terms.items():
                pre = _conj_pre.get(pauli)
                post = _conj_post.get(pauli)
                for i, j, angle in entries:
                    if pre:
                        getattr(qc, pre)(i)
                        getattr(qc, pre)(j)
                    qc.cx(i, j)
                    qc.rz(float(angle), j)
                    qc.cx(i, j)
                    if post:
                        getattr(qc, post)(i)
                        getattr(qc, post)(j)

    elif encoding == "tensor_product":
        ry_angles = encoded.metadata["ry_angles"]
        rz_angles = encoded.metadata["rz_angles"]
        for k in range(n_qubits):
            qc.ry(float(ry_angles[k]), k)
            qc.rz(float(rz_angles[k]), k)

    elif encoding == "qaoa_problem":
        p = encoded.metadata.get("p", 1)
        beta = encoded.metadata.get("beta", 0.39269908169872414)
        local_angles = encoded.metadata["local_angles"]
        coupling_angles = encoded.metadata["coupling_angles"]
        pairs = encoded.metadata.get("pairs", [])
        for i in range(n_qubits):
            qc.h(i)
        for _ in range(p):
            for i in range(n_qubits):
                qc.rz(2.0 * float(local_angles[i]), i)
            for k, (i, j) in enumerate(pairs):
                angle = 2.0 * float(coupling_angles[k])
                qc.cx(i, j)
                qc.rz(angle, j)
                qc.cx(i, j)
            for i in range(n_qubits):
                qc.rx(2.0 * float(beta), i)

    elif encoding == "amplitude":
        from qiskit.circuit.library import StatePreparation
        qc.append(StatePreparation(params.tolist()), range(n_qubits))

    else:
        raise ValueError(
            f"Unknown encoding '{encoding}'. "
            "Supported: angle, entangled_angle, basis, iqp, reupload, hamiltonian, "
            "zz_feature_map, pauli_feature_map, random_fourier, tensor_product, "
            "qaoa_problem, amplitude."
        )

    return qc

export_batch(encoded_list)

Export a list of EncodedResults to Qiskit QuantumCircuits.

Parameters:

Name Type Description Default
encoded_list list of EncodedResult
required

Returns:

Type Description
list of qiskit.QuantumCircuit

One circuit per sample.

Source code in quprep/export/qiskit_export.py
def export_batch(self, encoded_list: list) -> list:
    """
    Export a list of EncodedResults to Qiskit QuantumCircuits.

    Parameters
    ----------
    encoded_list : list of EncodedResult

    Returns
    -------
    list of qiskit.QuantumCircuit
        One circuit per sample.
    """
    return [self.export(e) for e in encoded_list]

PennyLaneExporter

Requires pip install quprep[pennylane].

quprep.export.pennylane_export.PennyLaneExporter(interface='auto', device='default.qubit')

Export EncodedResult objects to PennyLane QNode circuits.

Returns a callable qml.QNode from :meth:export. Calling the returned QNode executes the circuit on the configured device and returns the quantum state.

Requires: pip install quprep[pennylane]

Parameters:

Name Type Description Default
interface str

Autodiff interface: 'torch', 'jax', 'tf', or 'auto'. Default 'auto'.

'auto'
device str

PennyLane device string. Default 'default.qubit'.

'default.qubit'
Source code in quprep/export/pennylane_export.py
def __init__(self, interface: str = "auto", device: str = "default.qubit"):
    self.interface = interface
    self.device = device
    self._check_pennylane()

Functions

export(encoded)

Return a PennyLane QNode for an EncodedResult.

The returned QNode is immediately callable — invoke it with no arguments to execute the circuit and obtain the quantum state.

Parameters:

Name Type Description Default
encoded EncodedResult

Output from any QuPrep encoder. Supports all 12 encodings: angle, entangled_angle, basis, amplitude, iqp, reupload, hamiltonian, zz_feature_map, pauli_feature_map, random_fourier, tensor_product, qaoa_problem.

required

Returns:

Type Description
QNode

Callable quantum circuit. Invoke with no arguments to execute and obtain the quantum state vector.

Source code in quprep/export/pennylane_export.py
def export(self, encoded) -> qml.QNode:
    """Return a PennyLane QNode for an EncodedResult.

    The returned QNode is immediately callable — invoke it with no
    arguments to execute the circuit and obtain the quantum state.

    Parameters
    ----------
    encoded : EncodedResult
        Output from any QuPrep encoder. Supports all 12 encodings:
        ``angle``, ``entangled_angle``, ``basis``, ``amplitude``,
        ``iqp``, ``reupload``, ``hamiltonian``, ``zz_feature_map``,
        ``pauli_feature_map``, ``random_fourier``, ``tensor_product``,
        ``qaoa_problem``.

    Returns
    -------
    qml.QNode
        Callable quantum circuit. Invoke with no arguments to execute
        and obtain the quantum state vector.
    """
    import warnings

    import pennylane as qml

    encoding = encoded.metadata.get("encoding", "unknown")
    n = encoded.metadata["n_qubits"]
    params = encoded.parameters.copy()

    if n > 100:
        warnings.warn(
            f"PennyLane's circuit drawer (qml.draw) uses recursion and will likely "
            f"hit Python's recursion limit for circuits with more than ~100 qubits. "
            f"This circuit has {n} qubits. Call qml.draw(circuit)() at your own risk, "
            f"or use framework='qasm' to visualise the circuit safely.",
            UserWarning,
            stacklevel=2,
        )

    dev = qml.device(self.device, wires=n)

    if encoding == "angle":
        rotation = encoded.metadata.get("rotation", "ry")
        gate = {"ry": qml.RY, "rx": qml.RX, "rz": qml.RZ}.get(rotation)
        if gate is None:
            raise ValueError(f"Unknown rotation '{rotation}'.")

        @qml.qnode(dev, interface=self.interface)
        def circuit():
            for i, angle in enumerate(params):
                gate(float(angle), wires=i)
            return qml.state()

    elif encoding == "entangled_angle":
        rotation = encoded.metadata.get("rotation", "ry")
        layers = encoded.metadata.get("layers", 1)
        cnot_pairs = encoded.metadata.get("cnot_pairs", [])
        gate = {"ry": qml.RY, "rx": qml.RX, "rz": qml.RZ}.get(rotation)
        if gate is None:
            raise ValueError(f"Unknown rotation '{rotation}'.")

        @qml.qnode(dev, interface=self.interface)
        def circuit():
            for _ in range(layers):
                for i, angle in enumerate(params):
                    gate(float(angle), wires=i)
                for ctrl, tgt in cnot_pairs:
                    qml.CNOT(wires=[ctrl, tgt])
            return qml.state()

    elif encoding == "basis":
        @qml.qnode(dev, interface=self.interface)
        def circuit():
            for i, bit in enumerate(params):
                if bit == 1.0:
                    qml.PauliX(wires=i)
            return qml.state()

    elif encoding == "amplitude":
        @qml.qnode(dev, interface=self.interface)
        def circuit():
            qml.AmplitudeEmbedding(params, wires=range(n), normalize=False)
            return qml.state()

    elif encoding == "iqp":
        d = n
        reps = encoded.metadata.get("reps", 2)
        x = params[:d]
        pair_angles = params[d:]

        @qml.qnode(dev, interface=self.interface)
        def circuit():
            for _ in range(reps):
                for i in range(d):
                    qml.Hadamard(wires=i)
                for i in range(d):
                    qml.RZ(float(x[i]), wires=i)
                idx = 0
                for i in range(d):
                    for j in range(i + 1, d):
                        qml.IsingZZ(float(pair_angles[idx]), wires=[i, j])
                        idx += 1
            return qml.state()

    elif encoding == "reupload":
        layers = encoded.metadata.get("layers", 3)
        rotation = encoded.metadata.get("rotation", "ry")
        gate = {"ry": qml.RY, "rx": qml.RX, "rz": qml.RZ}.get(rotation)
        if gate is None:
            raise ValueError(f"Unknown rotation '{rotation}'.")

        @qml.qnode(dev, interface=self.interface)
        def circuit():
            for _ in range(layers):
                for i, angle in enumerate(params):
                    gate(float(angle), wires=i)
            return qml.state()

    elif encoding == "hamiltonian":
        trotter_steps = encoded.metadata.get("trotter_steps", 4)

        @qml.qnode(dev, interface=self.interface)
        def circuit():
            for _ in range(trotter_steps):
                for i, angle in enumerate(params):
                    qml.RZ(float(angle), wires=i)
            return qml.state()

    elif encoding == "zz_feature_map":
        reps = encoded.metadata.get("reps", 2)
        single_angles = encoded.metadata["single_angles"]
        pair_angles = encoded.metadata["pair_angles"]
        pairs = encoded.metadata["pairs"]

        @qml.qnode(dev, interface=self.interface)
        def circuit():
            for _ in range(reps):
                for i in range(n):
                    qml.Hadamard(wires=i)
                for i, angle in enumerate(single_angles):
                    qml.RZ(float(angle), wires=i)
                for (i, j), angle in zip(pairs, pair_angles):
                    qml.CNOT(wires=[i, j])
                    qml.RZ(float(angle), wires=j)
                    qml.CNOT(wires=[i, j])
            return qml.state()

    elif encoding == "pauli_feature_map":
        reps = encoded.metadata.get("reps", 2)
        single_terms = encoded.metadata.get("single_terms", {})
        pair_terms = encoded.metadata.get("pair_terms", {})

        @qml.qnode(dev, interface=self.interface)
        def circuit():
            _pl_gate = {"X": qml.RX, "Y": qml.RY, "Z": qml.RZ}
            for _ in range(reps):
                for i in range(n):
                    qml.Hadamard(wires=i)
                for pauli, angles in single_terms.items():
                    gate = _pl_gate[pauli]
                    for i, angle in enumerate(angles):
                        gate(float(angle), wires=i)
                for pauli, entries in pair_terms.items():
                    for i, j, angle in entries:
                        if pauli == "XX":
                            qml.Hadamard(wires=i)
                            qml.Hadamard(wires=j)
                        elif pauli == "YY":
                            qml.adjoint(qml.S)(wires=i)
                            qml.adjoint(qml.S)(wires=j)
                        qml.CNOT(wires=[i, j])
                        qml.RZ(float(angle), wires=j)
                        qml.CNOT(wires=[i, j])
                        if pauli == "XX":
                            qml.Hadamard(wires=i)
                            qml.Hadamard(wires=j)
                        elif pauli == "YY":
                            qml.S(wires=i)
                            qml.S(wires=j)
            return qml.state()

    elif encoding == "random_fourier":
        rotation = encoded.metadata.get("rotation", "ry")
        gate = {"ry": qml.RY, "rx": qml.RX, "rz": qml.RZ}.get(rotation)
        if gate is None:
            raise ValueError(f"Unknown rotation '{rotation}'.")

        @qml.qnode(dev, interface=self.interface)
        def circuit():
            for i, angle in enumerate(params):
                gate(float(angle), wires=i)
            return qml.state()

    elif encoding == "tensor_product":
        ry_angles = encoded.metadata["ry_angles"]
        rz_angles = encoded.metadata["rz_angles"]

        @qml.qnode(dev, interface=self.interface)
        def circuit():
            for k in range(n):
                qml.RY(float(ry_angles[k]), wires=k)
                qml.RZ(float(rz_angles[k]), wires=k)
            return qml.state()

    elif encoding == "qaoa_problem":
        p = encoded.metadata.get("p", 1)
        beta = encoded.metadata.get("beta", 0.39269908169872414)
        local_angles = encoded.metadata["local_angles"]
        coupling_angles = encoded.metadata["coupling_angles"]
        pairs = encoded.metadata.get("pairs", [])

        @qml.qnode(dev, interface=self.interface)
        def circuit():
            for i in range(n):
                qml.Hadamard(wires=i)
            for _ in range(p):
                for i in range(n):
                    qml.RZ(2.0 * float(local_angles[i]), wires=i)
                for k, (i, j) in enumerate(pairs):
                    qml.CNOT(wires=[i, j])
                    qml.RZ(2.0 * float(coupling_angles[k]), wires=j)
                    qml.CNOT(wires=[i, j])
                for i in range(n):
                    qml.RX(2.0 * float(beta), wires=i)
            return qml.state()

    else:
        raise ValueError(
            f"Unknown encoding '{encoding}'. "
            "Supported: angle, entangled_angle, basis, amplitude, iqp, reupload, "
            "hamiltonian, zz_feature_map, pauli_feature_map, random_fourier, "
            "tensor_product, qaoa_problem."
        )

    return circuit

export_batch(encoded_list)

Export a list of EncodedResults to PennyLane QNodes.

Parameters:

Name Type Description Default
encoded_list list of EncodedResult
required

Returns:

Type Description
list of qml.QNode

One callable QNode per sample.

Source code in quprep/export/pennylane_export.py
def export_batch(self, encoded_list: list) -> list:
    """
    Export a list of EncodedResults to PennyLane QNodes.

    Parameters
    ----------
    encoded_list : list of EncodedResult

    Returns
    -------
    list of qml.QNode
        One callable QNode per sample.
    """
    return [self.export(e) for e in encoded_list]

CirqExporter

Requires pip install quprep[cirq].

quprep.export.cirq_export.CirqExporter()

Export EncodedResult objects to Cirq Circuit.

Requires: pip install quprep[cirq]

Source code in quprep/export/cirq_export.py
def __init__(self):
    self._check_cirq()

Functions

export(encoded)

Convert an EncodedResult to a Cirq Circuit.

Parameters:

Name Type Description Default
encoded EncodedResult

Output from any QuPrep encoder.

required

Returns:

Type Description
Circuit

Circuit using cirq.LineQubit wires.

Source code in quprep/export/cirq_export.py
def export(self, encoded) -> cirq.Circuit:
    """Convert an EncodedResult to a Cirq Circuit.

    Parameters
    ----------
    encoded : EncodedResult
        Output from any QuPrep encoder.

    Returns
    -------
    cirq.Circuit
        Circuit using ``cirq.LineQubit`` wires.
    """
    import cirq

    encoding = encoded.metadata.get("encoding", "unknown")
    n = encoded.metadata["n_qubits"]
    params = encoded.parameters
    qubits = cirq.LineQubit.range(n)
    ops = []

    if encoding == "angle":
        rotation = encoded.metadata.get("rotation", "ry")
        gate_cls = {"ry": cirq.Ry, "rx": cirq.Rx, "rz": cirq.Rz}.get(rotation)
        if gate_cls is None:
            raise ValueError(f"Unknown rotation '{rotation}'.")
        for i, angle in enumerate(params):
            ops.append(gate_cls(rads=float(angle))(qubits[i]))

    elif encoding == "entangled_angle":
        rotation = encoded.metadata.get("rotation", "ry")
        layers = encoded.metadata.get("layers", 1)
        cnot_pairs = encoded.metadata.get("cnot_pairs", [])
        gate_cls = {"ry": cirq.Ry, "rx": cirq.Rx, "rz": cirq.Rz}.get(rotation)
        if gate_cls is None:
            raise ValueError(f"Unknown rotation '{rotation}'.")
        for _ in range(layers):
            for i, angle in enumerate(params):
                ops.append(gate_cls(rads=float(angle))(qubits[i]))
            for ctrl, tgt in cnot_pairs:
                ops.append(cirq.CNOT(qubits[ctrl], qubits[tgt]))

    elif encoding == "basis":
        for i, bit in enumerate(params):
            if bit == 1.0:
                ops.append(cirq.X(qubits[i]))

    elif encoding == "amplitude":
        raise NotImplementedError(
            "Amplitude encoding requires exponential-depth state preparation "
            "which Cirq does not natively support as a simple gate. "
            "Use QiskitExporter for amplitude encoding."
        )

    elif encoding == "iqp":
        d = n
        reps = encoded.metadata.get("reps", 2)
        x = params[:d]
        pair_angles = params[d:]
        for _ in range(reps):
            ops.extend(cirq.H(qubits[i]) for i in range(d))
            ops.extend(cirq.Rz(rads=float(x[i]))(qubits[i]) for i in range(d))
            idx = 0
            for i in range(d):
                for j in range(i + 1, d):
                    angle = float(pair_angles[idx])
                    ops.append(cirq.CNOT(qubits[i], qubits[j]))
                    ops.append(cirq.Rz(rads=angle)(qubits[j]))
                    ops.append(cirq.CNOT(qubits[i], qubits[j]))
                    idx += 1

    elif encoding == "reupload":
        layers = encoded.metadata.get("layers", 3)
        rotation = encoded.metadata.get("rotation", "ry")
        gate_cls = {"ry": cirq.Ry, "rx": cirq.Rx, "rz": cirq.Rz}.get(rotation)
        if gate_cls is None:
            raise ValueError(f"Unknown rotation '{rotation}'.")
        for _ in range(layers):
            for i, angle in enumerate(params):
                ops.append(gate_cls(rads=float(angle))(qubits[i]))

    elif encoding == "hamiltonian":
        trotter_steps = encoded.metadata.get("trotter_steps", 4)
        for _ in range(trotter_steps):
            for i, angle in enumerate(params):
                ops.append(cirq.Rz(rads=float(angle))(qubits[i]))

    elif encoding == "zz_feature_map":
        reps = encoded.metadata.get("reps", 2)
        single_angles = encoded.metadata["single_angles"]
        pair_angles = encoded.metadata["pair_angles"]
        pairs = encoded.metadata["pairs"]
        for _ in range(reps):
            ops.extend(cirq.H(qubits[i]) for i in range(n))
            for i, angle in enumerate(single_angles):
                ops.append(cirq.Rz(rads=float(angle))(qubits[i]))
            for (i, j), angle in zip(pairs, pair_angles):
                ops.append(cirq.CNOT(qubits[i], qubits[j]))
                ops.append(cirq.Rz(rads=float(angle))(qubits[j]))
                ops.append(cirq.CNOT(qubits[i], qubits[j]))

    elif encoding == "pauli_feature_map":
        reps = encoded.metadata.get("reps", 2)
        single_terms = encoded.metadata.get("single_terms", {})
        pair_terms = encoded.metadata.get("pair_terms", {})
        _cirq_gate = {"X": cirq.Rx, "Y": cirq.Ry, "Z": cirq.Rz}
        for _ in range(reps):
            ops.extend(cirq.H(qubits[i]) for i in range(n))
            for pauli, angles in single_terms.items():
                gate_cls = _cirq_gate[pauli]
                for i, angle in enumerate(angles):
                    ops.append(gate_cls(rads=float(angle))(qubits[i]))
            for pauli, entries in pair_terms.items():
                for i, j, angle in entries:
                    if pauli == "XX":
                        ops.append(cirq.H(qubits[i]))
                        ops.append(cirq.H(qubits[j]))
                    elif pauli == "YY":
                        ops.append((cirq.S**-1)(qubits[i]))
                        ops.append((cirq.S**-1)(qubits[j]))
                    ops.append(cirq.CNOT(qubits[i], qubits[j]))
                    ops.append(cirq.Rz(rads=float(angle))(qubits[j]))
                    ops.append(cirq.CNOT(qubits[i], qubits[j]))
                    if pauli == "XX":
                        ops.append(cirq.H(qubits[i]))
                        ops.append(cirq.H(qubits[j]))
                    elif pauli == "YY":
                        ops.append(cirq.S(qubits[i]))
                        ops.append(cirq.S(qubits[j]))

    elif encoding == "random_fourier":
        rotation = encoded.metadata.get("rotation", "ry")
        gate_cls = {"ry": cirq.Ry, "rx": cirq.Rx, "rz": cirq.Rz}.get(rotation)
        if gate_cls is None:
            raise ValueError(f"Unknown rotation '{rotation}'.")
        for i, angle in enumerate(params):
            ops.append(gate_cls(rads=float(angle))(qubits[i]))

    elif encoding == "tensor_product":
        ry_angles = encoded.metadata["ry_angles"]
        rz_angles = encoded.metadata["rz_angles"]
        for k in range(n):
            ops.append(cirq.Ry(rads=float(ry_angles[k]))(qubits[k]))
            ops.append(cirq.Rz(rads=float(rz_angles[k]))(qubits[k]))

    elif encoding == "qaoa_problem":
        p = encoded.metadata.get("p", 1)
        beta = encoded.metadata.get("beta", 0.39269908169872414)
        local_angles = encoded.metadata["local_angles"]
        coupling_angles = encoded.metadata["coupling_angles"]
        pairs = encoded.metadata.get("pairs", [])
        ops.extend(cirq.H(qubits[i]) for i in range(n))
        for _ in range(p):
            for i in range(n):
                ops.append(cirq.Rz(rads=2.0 * float(local_angles[i]))(qubits[i]))
            for k, (i, j) in enumerate(pairs):
                ops.append(cirq.CNOT(qubits[i], qubits[j]))
                ops.append(cirq.Rz(rads=2.0 * float(coupling_angles[k]))(qubits[j]))
                ops.append(cirq.CNOT(qubits[i], qubits[j]))
            for i in range(n):
                ops.append(cirq.Rx(rads=2.0 * float(beta))(qubits[i]))

    else:
        raise ValueError(
            f"Unknown encoding '{encoding}'. "
            "Supported: angle, entangled_angle, basis, iqp, reupload, hamiltonian, "
            "zz_feature_map, pauli_feature_map, random_fourier, tensor_product, qaoa_problem."
        )

    return cirq.Circuit(ops)

export_batch(encoded_list)

Export a list of EncodedResults to Cirq Circuits.

Parameters:

Name Type Description Default
encoded_list list of EncodedResult
required

Returns:

Type Description
list of cirq.Circuit

One circuit per sample.

Source code in quprep/export/cirq_export.py
def export_batch(self, encoded_list: list) -> list:
    """
    Export a list of EncodedResults to Cirq Circuits.

    Parameters
    ----------
    encoded_list : list of EncodedResult

    Returns
    -------
    list of cirq.Circuit
        One circuit per sample.
    """
    return [self.export(e) for e in encoded_list]

TKETExporter

Requires pip install quprep[tket].

quprep.export.tket_export.TKETExporter()

Export EncodedResult objects to TKET/pytket Circuit.

pytket rotation gates use half-turns (\(\text{angle} / \pi\)). This exporter converts all radian angles from QuPrep encoders to the pytket convention automatically.

Requires: pip install quprep[tket]

Source code in quprep/export/tket_export.py
def __init__(self):
    self._check_pytket()

Functions

export(encoded)

Convert an EncodedResult to a pytket Circuit.

Parameters:

Name Type Description Default
encoded EncodedResult

Output from any QuPrep encoder.

required

Returns:

Type Description
Circuit

Circuit with angles converted to pytket half-turns.

Source code in quprep/export/tket_export.py
def export(self, encoded) -> pytket.Circuit:
    """Convert an EncodedResult to a pytket Circuit.

    Parameters
    ----------
    encoded : EncodedResult
        Output from any QuPrep encoder.

    Returns
    -------
    pytket.Circuit
        Circuit with angles converted to pytket half-turns.
    """
    from pytket import Circuit

    encoding = encoded.metadata.get("encoding", "unknown")
    n = encoded.metadata["n_qubits"]
    params = encoded.parameters
    circuit = Circuit(n)

    if encoding == "angle":
        rotation = encoded.metadata.get("rotation", "ry")
        gate_fn = {"ry": circuit.Ry, "rx": circuit.Rx, "rz": circuit.Rz}.get(rotation)
        if gate_fn is None:
            raise ValueError(f"Unknown rotation '{rotation}'.")
        for i, angle in enumerate(params):
            gate_fn(float(angle) / math.pi, i)

    elif encoding == "entangled_angle":
        rotation = encoded.metadata.get("rotation", "ry")
        layers = encoded.metadata.get("layers", 1)
        cnot_pairs = encoded.metadata.get("cnot_pairs", [])
        gate_fn = {"ry": circuit.Ry, "rx": circuit.Rx, "rz": circuit.Rz}.get(rotation)
        if gate_fn is None:
            raise ValueError(f"Unknown rotation '{rotation}'.")
        for _ in range(layers):
            for i, angle in enumerate(params):
                gate_fn(float(angle) / math.pi, i)
            for ctrl, tgt in cnot_pairs:
                circuit.CX(ctrl, tgt)

    elif encoding == "basis":
        for i, bit in enumerate(params):
            if bit == 1.0:
                circuit.X(i)

    elif encoding == "amplitude":
        raise NotImplementedError(
            "Amplitude encoding requires exponential-depth state preparation "
            "which pytket does not natively support as a simple gate. "
            "Use QiskitExporter for amplitude encoding."
        )

    elif encoding == "iqp":
        d = n
        reps = encoded.metadata.get("reps", 2)
        x = params[:d]
        pair_angles = params[d:]
        for _ in range(reps):
            for i in range(d):
                circuit.H(i)
            for i in range(d):
                circuit.Rz(float(x[i]) / math.pi, i)
            idx = 0
            for i in range(d):
                for j in range(i + 1, d):
                    angle = float(pair_angles[idx])
                    circuit.CX(i, j)
                    circuit.Rz(angle / math.pi, j)
                    circuit.CX(i, j)
                    idx += 1

    elif encoding == "reupload":
        layers = encoded.metadata.get("layers", 3)
        rotation = encoded.metadata.get("rotation", "ry")
        gate_fn = {"ry": circuit.Ry, "rx": circuit.Rx, "rz": circuit.Rz}.get(rotation)
        if gate_fn is None:
            raise ValueError(f"Unknown rotation '{rotation}'.")
        for _ in range(layers):
            for i, angle in enumerate(params):
                gate_fn(float(angle) / math.pi, i)

    elif encoding == "hamiltonian":
        trotter_steps = encoded.metadata.get("trotter_steps", 4)
        for _ in range(trotter_steps):
            for i, angle in enumerate(params):
                circuit.Rz(float(angle) / math.pi, i)

    elif encoding == "zz_feature_map":
        reps = encoded.metadata.get("reps", 2)
        single_angles = encoded.metadata["single_angles"]
        pair_angles = encoded.metadata["pair_angles"]
        pairs = encoded.metadata["pairs"]
        for _ in range(reps):
            for i in range(n):
                circuit.H(i)
            for i, angle in enumerate(single_angles):
                circuit.Rz(float(angle) / math.pi, i)
            for (i, j), angle in zip(pairs, pair_angles):
                circuit.CX(i, j)
                circuit.Rz(float(angle) / math.pi, j)
                circuit.CX(i, j)

    elif encoding == "pauli_feature_map":
        reps = encoded.metadata.get("reps", 2)
        single_terms = encoded.metadata.get("single_terms", {})
        pair_terms = encoded.metadata.get("pair_terms", {})
        _gate = {"X": circuit.Rx, "Y": circuit.Ry, "Z": circuit.Rz}
        for _ in range(reps):
            for i in range(n):
                circuit.H(i)
            for pauli, angles in single_terms.items():
                gate_fn = _gate[pauli]
                for i, angle in enumerate(angles):
                    gate_fn(float(angle) / math.pi, i)
            for pauli, entries in pair_terms.items():
                for i, j, angle in entries:
                    if pauli == "XX":
                        circuit.H(i)
                        circuit.H(j)
                    elif pauli == "YY":
                        circuit.Sdg(i)
                        circuit.Sdg(j)
                    circuit.CX(i, j)
                    circuit.Rz(float(angle) / math.pi, j)
                    circuit.CX(i, j)
                    if pauli == "XX":
                        circuit.H(i)
                        circuit.H(j)
                    elif pauli == "YY":
                        circuit.S(i)
                        circuit.S(j)

    elif encoding == "random_fourier":
        rotation = encoded.metadata.get("rotation", "ry")
        gate_fn = {"ry": circuit.Ry, "rx": circuit.Rx, "rz": circuit.Rz}.get(rotation)
        if gate_fn is None:
            raise ValueError(f"Unknown rotation '{rotation}'.")
        for i, angle in enumerate(params):
            gate_fn(float(angle) / math.pi, i)

    elif encoding == "tensor_product":
        ry_angles = encoded.metadata["ry_angles"]
        rz_angles = encoded.metadata["rz_angles"]
        for k in range(n):
            circuit.Ry(float(ry_angles[k]) / math.pi, k)
            circuit.Rz(float(rz_angles[k]) / math.pi, k)

    elif encoding == "qaoa_problem":
        p = encoded.metadata.get("p", 1)
        beta = encoded.metadata.get("beta", 0.39269908169872414)
        local_angles = encoded.metadata["local_angles"]
        coupling_angles = encoded.metadata["coupling_angles"]
        pairs = encoded.metadata.get("pairs", [])
        for i in range(n):
            circuit.H(i)
        for _ in range(p):
            for i in range(n):
                circuit.Rz(2.0 * float(local_angles[i]) / math.pi, i)
            for k, (i, j) in enumerate(pairs):
                angle = 2.0 * float(coupling_angles[k])
                circuit.CX(i, j)
                circuit.Rz(angle / math.pi, j)
                circuit.CX(i, j)
            for i in range(n):
                circuit.Rx(2.0 * float(beta) / math.pi, i)

    else:
        raise ValueError(
            f"Unknown encoding '{encoding}'. "
            "Supported: angle, entangled_angle, basis, iqp, reupload, hamiltonian, "
            "zz_feature_map, pauli_feature_map, random_fourier, tensor_product, qaoa_problem."
        )

    return circuit

export_batch(encoded_list)

Export a list of EncodedResults to pytket Circuits.

Parameters:

Name Type Description Default
encoded_list list of EncodedResult
required

Returns:

Type Description
list of pytket.Circuit

One circuit per sample.

Source code in quprep/export/tket_export.py
def export_batch(self, encoded_list: list) -> list:
    """
    Export a list of EncodedResults to pytket Circuits.

    Parameters
    ----------
    encoded_list : list of EncodedResult

    Returns
    -------
    list of pytket.Circuit
        One circuit per sample.
    """
    return [self.export(e) for e in encoded_list]

BraketExporter

Requires pip install quprep[braket].

quprep.export.braket_export.BraketExporter()

Export EncodedResult objects to Amazon Braket Circuit objects.

Requires: pip install quprep[braket]

Source code in quprep/export/braket_export.py
def __init__(self):
    self._check_braket()

Functions

export(encoded)

Convert an EncodedResult to a Braket Circuit.

Parameters:

Name Type Description Default
encoded EncodedResult

Output from any QuPrep encoder (except amplitude).

required

Returns:

Type Description
Circuit
Source code in quprep/export/braket_export.py
def export(self, encoded) -> Circuit:
    """
    Convert an EncodedResult to a Braket Circuit.

    Parameters
    ----------
    encoded : EncodedResult
        Output from any QuPrep encoder (except amplitude).

    Returns
    -------
    braket.circuits.Circuit
    """
    from braket.circuits import Circuit, Instruction, gates

    encoding = encoded.metadata.get("encoding", "unknown")
    params = encoded.parameters

    if encoding == "angle":
        n = encoded.metadata["n_qubits"]
        circ = Circuit()
        rotation = encoded.metadata.get("rotation", "ry")
        gate_fn = {"ry": gates.Ry, "rx": gates.Rx, "rz": gates.Rz}.get(rotation)
        if gate_fn is None:
            raise ValueError(f"Unknown rotation '{rotation}'.")
        for i, angle in enumerate(params):
            circ.add_instruction(Instruction(gate_fn(float(angle)), i))
        return circ

    if encoding == "entangled_angle":
        n = encoded.metadata["n_qubits"]
        rotation = encoded.metadata.get("rotation", "ry")
        layers = encoded.metadata.get("layers", 1)
        cnot_pairs = encoded.metadata.get("cnot_pairs", [])
        circ = Circuit()
        gate_fn = {"ry": gates.Ry, "rx": gates.Rx, "rz": gates.Rz}.get(rotation)
        if gate_fn is None:
            raise ValueError(f"Unknown rotation '{rotation}'.")
        for _ in range(layers):
            for i, angle in enumerate(params):
                circ.add_instruction(Instruction(gate_fn(float(angle)), i))
            for ctrl, tgt in cnot_pairs:
                circ.cnot(ctrl, tgt)
        return circ

    if encoding == "basis":
        n = len(params)
        circ = Circuit()
        for i, bit in enumerate(params):
            if bit == 1.0:
                circ.x(i)
        return circ

    if encoding == "iqp":
        d = encoded.metadata["n_qubits"]
        reps = encoded.metadata.get("reps", 2)
        x = params[:d]
        pair_angles = params[d:]
        circ = Circuit()
        for _ in range(reps):
            for i in range(d):
                circ.h(i)
            for i in range(d):
                circ.add_instruction(Instruction(gates.Rz(float(x[i])), i))
            idx = 0
            for i in range(d):
                for j in range(i + 1, d):
                    angle = float(pair_angles[idx])
                    circ.cnot(i, j)
                    circ.add_instruction(Instruction(gates.Rz(angle), j))
                    circ.cnot(i, j)
                    idx += 1
        return circ

    if encoding == "zz_feature_map":
        d = encoded.metadata["n_qubits"]
        reps = encoded.metadata.get("reps", 2)
        single_angles = encoded.metadata["single_angles"]
        pair_angles = encoded.metadata["pair_angles"]
        pairs = encoded.metadata["pairs"]
        circ = Circuit()
        for _ in range(reps):
            for i in range(d):
                circ.h(i)
            for i, angle in enumerate(single_angles):
                circ.add_instruction(Instruction(gates.Rz(float(angle)), i))
            for (i, j), angle in zip(pairs, pair_angles):
                circ.cnot(i, j)
                circ.add_instruction(Instruction(gates.Rz(float(angle)), j))
                circ.cnot(i, j)
        return circ

    if encoding == "tensor_product":
        n = encoded.metadata["n_qubits"]
        ry_angles = encoded.metadata["ry_angles"]
        rz_angles = encoded.metadata["rz_angles"]
        circ = Circuit()
        for k in range(n):
            circ.add_instruction(Instruction(gates.Ry(float(ry_angles[k])), k))
            circ.add_instruction(Instruction(gates.Rz(float(rz_angles[k])), k))
        return circ

    if encoding == "reupload":
        n = len(params)
        layers = encoded.metadata.get("layers", 3)
        rotation = encoded.metadata.get("rotation", "ry")
        circ = Circuit()
        gate_fn = {"ry": gates.Ry, "rx": gates.Rx, "rz": gates.Rz}.get(rotation)
        if gate_fn is None:
            raise ValueError(f"Unknown rotation '{rotation}'.")
        for _ in range(layers):
            for i, angle in enumerate(params):
                circ.add_instruction(Instruction(gate_fn(float(angle)), i))
        return circ

    if encoding == "hamiltonian":
        n = len(params)
        trotter_steps = encoded.metadata.get("trotter_steps", 4)
        circ = Circuit()
        for _ in range(trotter_steps):
            for i, angle in enumerate(params):
                circ.add_instruction(Instruction(gates.Rz(float(angle)), i))
        return circ

    if encoding == "qaoa_problem":
        d = encoded.metadata["n_qubits"]
        p = encoded.metadata.get("p", 1)
        beta = encoded.metadata.get("beta", 0.39269908169872414)
        local_angles = encoded.metadata["local_angles"]
        coupling_angles = encoded.metadata["coupling_angles"]
        pairs = encoded.metadata.get("pairs", [])
        circ = Circuit()
        for i in range(d):
            circ.h(i)
        for _ in range(p):
            for i in range(d):
                circ.add_instruction(Instruction(gates.Rz(2.0 * float(local_angles[i])), i))
            for k, (i, j) in enumerate(pairs):
                angle = 2.0 * float(coupling_angles[k])
                circ.cnot(i, j)
                circ.add_instruction(Instruction(gates.Rz(angle), j))
                circ.cnot(i, j)
            for i in range(d):
                circ.add_instruction(Instruction(gates.Rx(2.0 * float(beta)), i))
        return circ

    if encoding == "pauli_feature_map":
        d = encoded.metadata["n_qubits"]
        reps = encoded.metadata.get("reps", 2)
        single_terms = encoded.metadata.get("single_terms", {})
        pair_terms = encoded.metadata.get("pair_terms", {})
        circ = Circuit()
        _gate = {"X": gates.Rx, "Y": gates.Ry, "Z": gates.Rz}
        for _ in range(reps):
            for i in range(d):
                circ.h(i)
            for pauli, angles in single_terms.items():
                gate_fn = _gate[pauli]
                for i, angle in enumerate(angles):
                    circ.add_instruction(Instruction(gate_fn(float(angle)), i))
            for pauli, entries in pair_terms.items():
                for i, j, angle in entries:
                    if pauli == "XX":
                        circ.h(i)
                        circ.h(j)
                    elif pauli == "YY":
                        circ.add_instruction(Instruction(gates.Si(), i))
                        circ.add_instruction(Instruction(gates.Si(), j))
                    circ.cnot(i, j)
                    circ.add_instruction(Instruction(gates.Rz(float(angle)), j))
                    circ.cnot(i, j)
                    if pauli == "XX":
                        circ.h(i)
                        circ.h(j)
                    elif pauli == "YY":
                        circ.add_instruction(Instruction(gates.S(), i))
                        circ.add_instruction(Instruction(gates.S(), j))
        return circ

    if encoding == "random_fourier":
        n = encoded.metadata["n_qubits"]
        circ = Circuit()
        rotation = encoded.metadata.get("rotation", "ry")
        gate_fn = {"ry": gates.Ry, "rx": gates.Rx, "rz": gates.Rz}.get(rotation)
        if gate_fn is None:
            raise ValueError(f"Unknown rotation '{rotation}'.")
        for i, angle in enumerate(params):
            circ.add_instruction(Instruction(gate_fn(float(angle)), i))
        return circ

    if encoding == "amplitude":
        raise NotImplementedError(
            "Amplitude encoding requires exponential-depth state preparation. "
            "Use QiskitExporter for amplitude encoding."
        )

    raise ValueError(
        f"Unknown encoding '{encoding}'. "
        "Supported: angle, entangled_angle, basis, iqp, zz_feature_map, "
        "pauli_feature_map, random_fourier, tensor_product, qaoa_problem, "
        "reupload, hamiltonian."
    )

export_batch(encoded_list)

Export a list of EncodedResults to Braket Circuits.

Parameters:

Name Type Description Default
encoded_list list of EncodedResult
required

Returns:

Type Description
list of braket.circuits.Circuit
Source code in quprep/export/braket_export.py
def export_batch(self, encoded_list: list) -> list:
    """
    Export a list of EncodedResults to Braket Circuits.

    Parameters
    ----------
    encoded_list : list of EncodedResult

    Returns
    -------
    list of braket.circuits.Circuit
    """
    return [self.export(e) for e in encoded_list]

QSharpExporter

No dependencies for string generation. Requires pip install quprep[qsharp] for Azure Quantum submission.

quprep.export.qsharp_export.QSharpExporter(namespace='QuPrepCircuit', operation_name='Encode')

Export EncodedResult objects to Q# 1.0 program strings.

No additional dependencies required to generate Q# source. To run locally install the qsharp Python package: pip install quprep[qsharp]

Parameters:

Name Type Description Default
namespace str

Q# namespace for the generated operation. Default "QuPrepCircuit".

'QuPrepCircuit'
operation_name str

Name of the generated Q# operation. Default "Encode".

'Encode'
Source code in quprep/export/qsharp_export.py
def __init__(
    self,
    namespace: str = "QuPrepCircuit",
    operation_name: str = "Encode",
):
    self.namespace = namespace
    self.operation_name = operation_name

Functions

export(encoded)

Convert an EncodedResult to a Q# program string.

Parameters:

Name Type Description Default
encoded EncodedResult

Output from any QuPrep encoder (except amplitude).

required

Returns:

Type Description
str

Complete Q# 1.0 source file contents.

Source code in quprep/export/qsharp_export.py
def export(self, encoded) -> str:
    """
    Convert an EncodedResult to a Q# program string.

    Parameters
    ----------
    encoded : EncodedResult
        Output from any QuPrep encoder (except amplitude).

    Returns
    -------
    str
        Complete Q# 1.0 source file contents.
    """
    encoding = encoded.metadata.get("encoding", "unknown")
    n = encoded.metadata.get("n_qubits", len(encoded.parameters))
    params = encoded.parameters

    body_lines = self._build_body(encoding, n, params, encoded.metadata)

    lines = [
        f"namespace {self.namespace} {{",
        "    open Microsoft.Quantum.Intrinsic;",
        "    open Microsoft.Quantum.Math;",
        "",
        f"    operation {self.operation_name}() : Unit {{",
        f"        use q = Qubit[{n}];",
    ]
    lines.extend(body_lines)
    lines += [
        "        ResetAll(q);",
        "    }",
        "}",
        "",
    ]
    return "\n".join(lines)

export_batch(encoded_list)

Export a list of EncodedResults to Q# program strings.

Parameters:

Name Type Description Default
encoded_list list of EncodedResult
required

Returns:

Type Description
list of str
Source code in quprep/export/qsharp_export.py
def export_batch(self, encoded_list: list) -> list[str]:
    """
    Export a list of EncodedResults to Q# program strings.

    Parameters
    ----------
    encoded_list : list of EncodedResult

    Returns
    -------
    list of str
    """
    return [self.export(e) for e in encoded_list]

IQMExporter

No dependencies for dict generation. Requires pip install quprep[iqm] for hardware submission.

quprep.export.iqm_export.IQMExporter(circuit_name='quprep_circuit', qubit_prefix='QB')

Export EncodedResult objects to IQM native circuit format (dict).

Returns a Python dict matching the IQM circuit JSON schema. No SDK dependencies required — install quprep[iqm] only when you need to submit directly to IQM hardware via iqm-client.

Parameters:

Name Type Description Default
circuit_name str

Name field in the output circuit dict. Default "quprep_circuit".

'quprep_circuit'
qubit_prefix str

Prefix for qubit labels. Default "QB""QB1", "QB2", ...

'QB'
Source code in quprep/export/iqm_export.py
def __init__(self, circuit_name: str = "quprep_circuit", qubit_prefix: str = "QB"):
    self.circuit_name = circuit_name
    self.qubit_prefix = qubit_prefix

Functions

export(encoded)

Convert an EncodedResult to an IQM circuit dict.

Parameters:

Name Type Description Default
encoded EncodedResult

Output from any QuPrep encoder (except amplitude).

required

Returns:

Type Description
dict

IQM circuit in JSON-serialisable dict form.

Source code in quprep/export/iqm_export.py
def export(self, encoded) -> dict:
    """
    Convert an EncodedResult to an IQM circuit dict.

    Parameters
    ----------
    encoded : EncodedResult
        Output from any QuPrep encoder (except amplitude).

    Returns
    -------
    dict
        IQM circuit in JSON-serialisable dict form.
    """
    encoding = encoded.metadata.get("encoding", "unknown")
    params = encoded.parameters
    n = encoded.metadata.get("n_qubits", len(params))
    qubits = [self._qname(i) for i in range(n)]

    instructions = self._build_instructions(encoding, params, n, qubits, encoded.metadata)

    return {
        "name": self.circuit_name,
        "instructions": instructions,
    }

export_batch(encoded_list)

Export a list of EncodedResults to IQM circuit dicts.

Parameters:

Name Type Description Default
encoded_list list of EncodedResult
required

Returns:

Type Description
list of dict
Source code in quprep/export/iqm_export.py
def export_batch(self, encoded_list: list) -> list[dict]:
    """
    Export a list of EncodedResults to IQM circuit dicts.

    Parameters
    ----------
    encoded_list : list of EncodedResult

    Returns
    -------
    list of dict
    """
    return [self.export(e) for e in encoded_list]

Plugin registry

Register custom encoders and exporters for use with prepare().

quprep.plugins.register_encoder(name)

Register a custom encoder class under name.

Can be used as a class decorator or called directly:

.. code-block:: python

@register_encoder("my_enc")
class MyEncoder(BaseEncoder): ...

# or:
register_encoder("my_enc")(MyEncoder)

Parameters:

Name Type Description Default
name str

Encoding name used in :func:quprep.prepare and CLI.

required

Returns:

Type Description
Callable

A decorator that registers and returns the class unchanged.

Raises:

Type Description
ValueError

If name is already registered (use :func:unregister_encoder first).

Source code in quprep/plugins.py
def register_encoder(name: str) -> Callable[[type[_T]], type[_T]]:
    """
    Register a custom encoder class under ``name``.

    Can be used as a class decorator or called directly:

    .. code-block:: python

        @register_encoder("my_enc")
        class MyEncoder(BaseEncoder): ...

        # or:
        register_encoder("my_enc")(MyEncoder)

    Parameters
    ----------
    name : str
        Encoding name used in :func:`quprep.prepare` and CLI.

    Returns
    -------
    Callable
        A decorator that registers and returns the class unchanged.

    Raises
    ------
    ValueError
        If ``name`` is already registered (use :func:`unregister_encoder` first).
    """
    def decorator(cls: type[_T]) -> type[_T]:
        if name in _encoder_registry:
            raise ValueError(
                f"Encoder '{name}' is already registered. "
                "Call unregister_encoder('{name}') first."
            )
        _encoder_registry[name] = cls  # type: ignore[assignment]
        return cls

    return decorator

quprep.plugins.register_exporter(name)

Register a custom exporter class under name.

Parameters:

Name Type Description Default
name str

Framework name used in :func:quprep.prepare.

required

Returns:

Type Description
Callable

A decorator that registers and returns the class unchanged.

Raises:

Type Description
ValueError

If name is already registered.

Source code in quprep/plugins.py
def register_exporter(name: str) -> Callable[[type[_T]], type[_T]]:
    """
    Register a custom exporter class under ``name``.

    Parameters
    ----------
    name : str
        Framework name used in :func:`quprep.prepare`.

    Returns
    -------
    Callable
        A decorator that registers and returns the class unchanged.

    Raises
    ------
    ValueError
        If ``name`` is already registered.
    """
    def decorator(cls: type[_T]) -> type[_T]:
        if name in _exporter_registry:
            raise ValueError(
                f"Exporter '{name}' is already registered. "
                "Call unregister_exporter('{name}') first."
            )
        _exporter_registry[name] = cls  # type: ignore[assignment]
        return cls

    return decorator

quprep.plugins.list_encoders()

Return names of all registered plugin encoders.

Source code in quprep/plugins.py
def list_encoders() -> list[str]:
    """Return names of all registered plugin encoders."""
    return sorted(_encoder_registry)

quprep.plugins.list_exporters()

Return names of all registered plugin exporters.

Source code in quprep/plugins.py
def list_exporters() -> list[str]:
    """Return names of all registered plugin exporters."""
    return sorted(_exporter_registry)

quprep.plugins.get_encoder_class(name)

Return the encoder class registered under name, or None.

Source code in quprep/plugins.py
def get_encoder_class(name: str) -> type | None:
    """Return the encoder class registered under ``name``, or ``None``."""
    return _encoder_registry.get(name)

quprep.plugins.get_exporter_class(name)

Return the exporter class registered under name, or None.

Source code in quprep/plugins.py
def get_exporter_class(name: str) -> type | None:
    """Return the exporter class registered under ``name``, or ``None``."""
    return _exporter_registry.get(name)

quprep.plugins.unregister_encoder(name)

Remove an encoder from the registry (useful for testing).

Source code in quprep/plugins.py
def unregister_encoder(name: str) -> None:
    """Remove an encoder from the registry (useful for testing)."""
    _encoder_registry.pop(name, None)

quprep.plugins.unregister_exporter(name)

Remove an exporter from the registry (useful for testing).

Source code in quprep/plugins.py
def unregister_exporter(name: str) -> None:
    """Remove an exporter from the registry (useful for testing)."""
    _exporter_registry.pop(name, None)

Visualization

No dependencies for draw_ascii. Requires pip install quprep[viz] for draw_matplotlib.

quprep.export.visualize.draw_ascii(encoded, width=80)

Return an ASCII circuit diagram for an EncodedResult.

No additional dependencies required.

Parameters:

Name Type Description Default
encoded EncodedResult
required
width int

Reserved for future use (target line width hint). Default 80.

80

Returns:

Type Description
str

Multi-line ASCII string. Print with print(draw_ascii(encoded)).

Source code in quprep/export/visualize.py
def draw_ascii(encoded, width: int = 80) -> str:  # noqa: ARG001
    """
    Return an ASCII circuit diagram for an EncodedResult.

    No additional dependencies required.

    Parameters
    ----------
    encoded : EncodedResult
    width : int
        Reserved for future use (target line width hint). Default 80.

    Returns
    -------
    str
        Multi-line ASCII string. Print with ``print(draw_ascii(encoded))``.
    """
    m = encoded.metadata
    n = m.get("n_qubits", 1)
    columns = _build_columns(encoded)

    num_rows = 2 * n - 1
    rows = [""] * num_rows

    # Qubit label prefix — right-aligned to widest label
    prefix_len = len(f"q[{n - 1}]") + 1
    for i in range(n):
        rows[2 * i] = f"q[{i}]".ljust(prefix_len)
    for i in range(n - 1):
        rows[2 * i + 1] = " " * prefix_len

    for col in columns:
        if col["type"] == "layer":
            col_rows = _render_layer(col["gates"], n)
        elif col["type"] == "cnot":
            col_rows = _render_two_qubit(col["ctrl"], col["tgt"], n, "●", "⊕")
        elif col["type"] == "zz":
            col_rows = _render_two_qubit(col["ctrl"], col["tgt"], n, "Z", "Z")
        else:
            col_rows = ["─" * _CNOT_W] * num_rows

        for r in range(num_rows):
            rows[r] += col_rows[r]

    # Trailing wire segment
    for i in range(n):
        rows[2 * i] += "──"

    enc = m.get("encoding", "unknown")
    depth = m.get("depth", "?")
    header = f"── {enc} | {n} qubits | depth {depth} ──"
    return header + "\n" + "\n".join(rows) + "\n"

quprep.export.visualize.draw_matplotlib(encoded, filename=None)

Draw a matplotlib circuit diagram.

Requires: pip install quprep[viz]

Parameters:

Name Type Description Default
encoded EncodedResult
required
filename str or Path

Save to file if provided (PNG, PDF, SVG). Returns None. If None, returns the matplotlib Figure object.

None

Returns:

Type Description
Figure or None

Figure object if filename is None; None after saving to file.

Source code in quprep/export/visualize.py
def draw_matplotlib(encoded, filename: str | Path | None = None):
    """
    Draw a matplotlib circuit diagram.

    Requires: pip install quprep[viz]

    Parameters
    ----------
    encoded : EncodedResult
    filename : str or Path, optional
        Save to file if provided (PNG, PDF, SVG). Returns None.
        If None, returns the matplotlib Figure object.

    Returns
    -------
    matplotlib.figure.Figure or None
        Figure object if filename is None; None after saving to file.
    """
    try:
        import matplotlib.pyplot as plt
    except ImportError:
        raise ImportError(
            "matplotlib is not installed. Run: pip install quprep[viz]"
        ) from None

    m = encoded.metadata
    n = m.get("n_qubits", 1)
    enc = m.get("encoding", "unknown")
    depth = m.get("depth", "?")
    columns = _build_columns(encoded)

    # Assign x-positions to columns
    col_x: list[float] = []
    x = 1.5
    for col in columns:
        col_x.append(x)
        x += 1.3 if col["type"] == "layer" else 0.85
    wire_end = x + 0.2

    # Figure sizing
    fig_w = max(wire_end + 0.6, 4.0)
    fig_h = max(n * 0.85 + 0.7, 2.0)

    fig, ax = plt.subplots(figsize=(fig_w, fig_h))
    ax.set_xlim(0.1, wire_end + 0.4)
    ax.set_ylim(-0.7, n - 0.3)
    ax.axis("off")

    wire_start = 1.0

    # y position: qubit 0 at top
    def yw(i: int) -> float:
        return float(n - 1 - i)

    # Qubit labels and horizontal wires
    for i in range(n):
        ax.text(
            0.85, yw(i), f"q[{i}]",
            ha="right", va="center", fontsize=9, fontfamily="monospace",
        )
        ax.plot([wire_start, wire_end], [yw(i), yw(i)], color="black", lw=1.5, zorder=1)

    # Draw each column
    for col, xc in zip(columns, col_x):
        if col["type"] == "layer":
            for qi, label in col["gates"].items():
                _mpl_draw_gate(ax, xc, yw(qi), label)
        elif col["type"] == "cnot":
            _mpl_draw_cnot(ax, xc, yw(col["ctrl"]), yw(col["tgt"]))
        elif col["type"] == "zz":
            _mpl_draw_zz(ax, xc, yw(col["ctrl"]), yw(col["tgt"]))

    ax.set_title(
        f"{enc} encoding  ·  {n} qubits  ·  depth {depth}",
        fontsize=10, pad=8,
    )

    if filename is not None:
        fig.savefig(Path(filename), bbox_inches="tight", dpi=150)
        plt.close(fig)
        return None
    return fig