def absorb(self, other: 'qiskitQEngine'): """ Absorb the qubits from the other engine into this one. This is done by tensoring the state at the end. """ # Check whether there is space newNum = self.activeQubits + other.activeQubits if newNum > self.maxQubits: raise quantumError( "Cannot merge: qubits exceed the maximum available.\n") # Check whether there are in fact qubits to tensor up.... if self.activeQubits == 0: self.qRegister = other.qRegister self.cRegister = other.cRegister self.activeQubits = other.activeQubits self.qc = other.qc elif other.activeQubits > 0: # Get the current state of the other engine other_state = run_and_get_results(other.qc) # Allocate qubits in this engine for the new qubits from the other engine qreg = QuantumRegister(other.activeQubits) self.qc.add_register(qreg) self.qc.initialize(other_state, qreg) self.qRegister += qreg self.activeQubits = newNum
def absorb_parts(self, R, I, activeQ): """ Absorb the qubits, given in pieces Arguments: R real part of the qubit state as a list I imaginary part as a list activeQ active number of qubits """ # Check whether there is space newNum = self.activeQubits + activeQ if newNum > self.maxQubits: raise quantumError( "Cannot merge: qubits exceed the maximum available.\n") if activeQ > 0: # Convert the real and imaginary parts to a state state = [re + im * 1j for re, im in zip(R, I)] # Allocate qubits in this engine for the new qubits from the other engine qreg = QuantumRegister(activeQ) self.qc.add_register(qreg) self.qc.initialize(state, qreg) self.qRegister += qreg self.activeQubits = newNum
def absorb_parts(self, R, I, activeQ): """ Absorb the qubits, given in pieces Arguments: R real part of the qubit state as a list I imaginary part as a list activeQ active number of qubits """ # Check whether there is space newNum = self.activeQubits + activeQ if newNum > self.maxQubits: raise quantumError( "Cannot merge: qubits exceed the maximum available.\n") if activeQ > 0: # Convert the real and imaginary parts to a state state = [re + im * 1j for re, im in zip(R, I)] # Allocate qubits in this engine for the new qubits from the other engine qreg = self.eng.allocate_qureg(activeQ) # Put the new qubits in the correct state pQ.ops.StatePreparation(state) | qreg # Add the qubits to the list of qubits self.qubitReg += list(qreg) self.activeQubits = newNum
def absorb(self, other): """ Absorb the qubits from the other engine into this one. This is done by tensoring the state at the end. """ # Check whether there is space newNum = self.activeQubits + other.activeQubits if newNum > self.maxQubits: raise quantumError( "Cannot merge: qubits exceed the maximum available.\n") # Check whether there are in fact qubits to tensor up.... if self.activeQubits == 0: self.eng = other.eng self.qubitReg = list(other.qubitReg) elif other.activeQubits > 0: # Get the current state of the other engine other.eng.flush() other_state = other.eng.backend.cheat()[1] # Allocate qubits in this engine for the new qubits from the other engine qreg = self.eng.allocate_qureg(other.activeQubits) # Put the new qubits in the correct state pQ.ops.StatePreparation(other_state) | qreg # Add the qubits to the list of qubits self.qubitReg += list(qreg) self.activeQubits = newNum
def remove_qubit(self, qubitNum): """ Removes the qubit with the desired number qubitNum """ if (qubitNum + 1) > self.activeQubits: raise quantumError("No such qubit to remove") self.measure_qubit(qubitNum)
def apply_twoqubit_gate(self, gate, qubit1, qubit2): """ Applies a unitary gate to the two specified qubits. Arguments: gate The project Q gate to be applied qubit1 the first qubit qubit2 the second qubit """ if (qubit1 + 1) > self.activeQubits: raise quantumError("No such qubit to act as a control qubit") if (qubit2 + 1) > self.activeQubits: raise quantumError("No such qubit to act as a target qubit") if qubit1 == qubit2: raise quantumError("Control and target are equal") gate | (self.qubitReg[qubit1], self.qubitReg[qubit2])
def absorb(self, other): """ Absorb the qubits from the other engine into this one. This is done by tensoring the state at the end. """ # Check whether there is space newNum = self.activeQubits + other.activeQubits if newNum > self.maxQubits: raise quantumError( "Cannot merge: qubits exceed the maximum available.\n") self.qubitReg = self.qubitReg.tensor_product(other.qubitReg)
def apply_onequbit_gate(self, gate, qubitNum): """ Applies a unitary gate to the specified qubit. Arguments: gate The project Q gate to be applied qubitNum the number of the qubit this gate is applied to """ if (qubitNum + 1) > self.activeQubits: raise quantumError("No such qubit to apply a single qubit gate to") gate | self.qubitReg[qubitNum]
def absorb_parts(self, R, I, activeQ): """ Absorb the qubits, given in pieces Arguments: R The array describing the stabilizer state (from StabilizerState.to_array) I Unused activeQ active number of qubits """ # Check whether there is space newNum = self.activeQubits + activeQ if newNum > self.maxQubits: raise quantumError( "Cannot merge: qubits exceed the maximum available.\n") self.qubitReg = self.qubitReg.tensor_product(StabilizerState(R))
def add_qubit(self, newQubit): """ Add new qubit in the state described by the vector newQubit ([a, b]) """ norm = np.dot(np.array(newQubit), np.array(newQubit).conj()) if not norm <= 1: raise quantumError("State {} is not normalized.".format(newQubit)) # Create a fresh qubit num = self.add_fresh_qubit() # Transform the new qubit into the correct state pQ.ops.StatePreparation(newQubit) | self.qubitReg[num] return num
def measure_qubit_inplace(self, qubitNum): """ Measures the desired qubit in the standard basis. This returns the classical outcome. The quantum register is in the post-measurment state corresponding to the obtained outcome. Arguments: qubitNum qubit to be measured """ # Check we have such a qubit... if (qubitNum + 1) > self.activeQubits: raise quantumError("No such qubit to be measured.") outcome = self.qubitReg.measure(qubitNum, inplace=True) # return measurement outcome return outcome
def absorb(self, other): """ Absorb the qubits from the other engine into this one. This is done by tensoring the state at the end. """ # Check whether there is space newNum = self.activeQubits + other.activeQubits if newNum > self.maxQubits: raise quantumError( "Cannot merge: qubits exceed the maximum available.\n") # Check whether there are in fact qubits to tensor up.... if self.activeQubits == 0: self.qubitReg = other.qubitReg elif other.activeQubits != 0: self.qubitReg = qp.tensor(self.qubitReg, other.qubitReg) self.activeQubits = newNum
def add_qubit(self, newQubit): """ Add new qubit in the state described by the vector newQubit ([a, b]) """ norm = np.dot(np.array(newQubit), np.array(newQubit).conj()) if not norm <= 1: raise quantumError("State {} is not normalized.".format(newQubit)) # Create a fresh qubit num = self.add_fresh_qubit() qubit_register = QuantumRegister(1) init_circuit = QuantumCircuit(qubit_register, name="initializer_circ") init_circuit.initialize(newQubit, qubit_register) self.qc.append(init_circuit, [self.cRegister[num]]) return num
def absorb_parts(self, R, I, activeQ): """ Absorb the qubits, given in pieces Arguments: R real part of the qubit state as a list I imaginary part as a list activeQ active number of qubits """ # Convert the real and imaginary parts given as lists into a qutip object M = I for s in range(len(I)): for t in range(len(I)): M[s][t] = R[s][t] + I[s][t] * 1j qt = qp.Qobj(M) # Check whether there is space newNum = self.activeQubits + activeQ if newNum > self.maxQubits: raise quantumError( "Cannot merge: qubits exceed the maximum available.\n") # Check whether there are in fact qubits to tensor up.... if self.activeQubits == 0: self.qubitReg = qt elif qt.shape[0] != 0: self.qubitReg = qp.tensor(self.qubitReg, qt) self.activeQubits = newNum # Qutip distinguishes between system dimensionality and matrix dimensionality # so we need to make sure it knows we are talking about multiple qubits k = int(math.log2(self.qubitReg.shape[0])) dimL = [] for j in range(k): dimL.append(2) self.qubitReg.dims = [dimL, dimL]
def measure_qubit_inplace(self, qubitNum): """ Measures the desired qubit in the standard basis. This returns the classical outcome. The quantum register is in the post-measurment state corresponding to the obtained outcome. Arguments: qubitNum qubit to be measured """ # Check we have such a qubit... if (qubitNum + 1) > self.activeQubits: raise quantumError("No such qubit to be measured.") # Construct the two measurement operators, and put them at the right position v0 = qp.basis(2, 0) P0 = v0 * v0.dag() M0 = qp.gate_expand_1toN(P0, self.activeQubits, qubitNum) v1 = qp.basis(2, 1) P1 = v1 * v1.dag() M1 = qp.gate_expand_1toN(P1, self.activeQubits, qubitNum) # Compute the success probabilities obj = M0 * self.qubitReg p0 = obj.tr().real obj = M1 * self.qubitReg p1 = obj.tr().real # Sample the measurement outcome from these probabilities outcome = int(np.random.choice([0, 1], 1, p=[p0, p1])) # Compute the post-measurement state, getting rid of the measured qubit if outcome == 0: self.qubitReg = M0 * self.qubitReg * M0.dag() / p0 else: self.qubitReg = M1 * self.qubitReg * M1.dag() / p1 # return measurement outcome return outcome
def remove_qubit(self, qubitNum): """ Removes the qubit with the desired number qubitNum """ if (qubitNum + 1) > self.activeQubits: raise quantumError("No such qubit to remove") # Check if this the only qubit if self.activeQubits == 1: self.activeQubits = 0 self.qubitReg = qp.Qobj() return # Compute the list of qubits to keep keepList = [] for j in range(self.activeQubits): if j != qubitNum: keepList.append(j) # Trace out this qubit by taking the partial trace self.qubitReg = self.qubitReg.ptrace(keepList) # Update the number of qubits self.activeQubits = self.activeQubits - 1