Source code for ttheom.circuit.pulse_seq

import numpy as np
from qiskit import QuantumCircuit
from qiskit.circuit import Parameter, Delay, Instruction
from qiskit.transpiler import Target, InstructionProperties
from qiskit.quantum_info import Operator
from .transform_circ import transform, scheduling
from ..tt.TTs import TTs

[docs] def setPulseSeq(qc: QuantumCircuit, TTs: TTs, omegaQ: list[float], dtFB: float, idlingTime: float) -> None: """Compile a quantum circuit into pulse sequences and store them in ``TTs``. Parameters ---------- qc : qiskit.QuantumCircuit Quantum circuit to be simulated. TTs : TTs.TTs MPS/MPO object; pulse sequences are written to its attributes. omegaQ : list of float Qubit frequencies in units of the maximum qubit frequency. dtFB : float Time step for HEOM integration in units of ``1/omegaQ[0]``. idlingTime : float Idling time inserted after delayed gates, in units of ``omegaQ[0]``. """ numQubits = qc.num_qubits # create a quantum circuit consisting of elemental gates only qcTransformed = transform(qc, TTs) # permutation matrix matSize = 2**numQubits if qcTransformed.layout is None: permMat = np.eye(matSize, dtype=np.int64) else: qubitMap = qcTransformed.layout.final_index_layout() permMat = np.zeros([matSize, matSize], dtype=np.int64) formatSpec = f'0{numQubits}b' for i in range(matSize): row = format(i, formatSpec) clm = '' for j in range(numQubits-1, -1, -1): clm += row[numQubits-1 - qubitMap[j]] permMat[int(row, 2), int(clm, 2)] = 1 TTs.permMat = permMat # apply virtual-Z-gate schemes qcVZ = QuantumCircuit(numQubits) globalPhase = 0 localPhase = [0] * numQubits for gate in qcTransformed.data: qubitIdx = list(np.sort([q._index for q in gate.qubits])) if gate.name != 'delay': params = list(gate.operation.params) params.append(gate.operation.name) pulseIdx = TTs.map[tuple(qubitIdx)] gateOut, globalPhase, localPhase = \ TTs.pulse[pulseIdx][1].vzTransform( params, globalPhase, localPhase, qubitIdx ) else: gateOut = gate.operation qcVZ.append(gateOut, qubitIdx) qcVZ.global_phase = globalPhase qcZs = QuantumCircuit(numQubits) for i in range(numQubits): qcZs.rz(localPhase[i], i) TTs.matVZ = Operator(qcZs).data # set gate time for each gate and insert idling idlingStep = int(idlingTime / dtFB) qcWithDelay = QuantumCircuit(numQubits) tgt = Target(dt=1) deltaT = Parameter('deltaT') tgt.add_instruction(Delay(deltaT)) for i, gate in enumerate(qcVZ.data): qubitIdx = list(np.sort([q._index for q in gate.qubits])) params = gate.operation.params if gate.name != 'delay': name = f'g{i}' pulseIdx = TTs.map[tuple(qubitIdx)] dur = TTs.pulse[pulseIdx][1].getGateTime(dtFB, params) params = [dur] + params if len(qubitIdx) == 2: gateTmp = Instruction(name, 2, 0, params) else: gateTmp = Instruction(name, 1, 0, params) qcWithDelay.append(gateTmp, qubitIdx) if TTs.pulse[pulseIdx][1].isDelayed(gate.operation.name): qcWithDelay.delay(idlingStep, qubitIdx) prop = {tuple(qubitIdx): InstructionProperties(duration=dur)} tgt.add_instruction(gateTmp, prop) else: qcWithDelay.delay(params[0], qubitIdx) qcScheduled = scheduling(qcWithDelay) totalSize = qcScheduled.estimate_duration(tgt, 'dt') for _, pulse in TTs.pulse: pulse.initSeq(totalSize) TTs.omegaQSeq = [np.ones(totalSize) * omegaQ[i] for i in range(numQubits)] ptr = [0] * numQubits for gate in qcScheduled.data: if gate.operation.num_qubits == 2: qubitIdx = list(np.sort([q._index for q in gate.qubits])) pulseIdx = TTs.map[tuple(qubitIdx)] dur = gate.operation.params[0] st = ptr[qubitIdx[0]] omegaQTmp = [omegaQ[qubitIdx[0]], omegaQ[qubitIdx[1]]] TTs.omegaQSeq[qubitIdx[0]][st:st+dur], \ TTs.omegaQSeq[qubitIdx[1]][st:st+dur] = \ TTs.pulse[pulseIdx][1].setOmegaQ(dur, omegaQTmp) TTs.pulse[pulseIdx][1].setSeq(ptr[qubitIdx[0]], dur, []) ptr[qubitIdx[0]] += dur ptr[qubitIdx[1]] += dur elif gate.operation.name != 'delay': qubitIdx = np.array([gate.qubits[0]._index]) pulseIdx = TTs.map[tuple(qubitIdx)] dur, theta, phi = gate.operation.params[0:3] TTs.pulse[pulseIdx][1].setSeq(ptr[qubitIdx[0]], dur, [theta, phi]) ptr[qubitIdx[0]] += dur else: qubitIdx = gate.qubits[0]._index dur = gate.operation.params[0] ptr[qubitIdx] += dur # crop redundant section at the end of the sequence ptrs = [] for pulse in TTs.pulse: ptrs.append(pulse[1].getEnPtr()) en = max(ptrs) for pulse in TTs.pulse: pulse[1].cropPulse(en) for i in range(numQubits): TTs.omegaQSeq[i] = TTs.omegaQSeq[i][0:en] return qcScheduled