def test_expval(self): """Test expectation_value method""" psi = Statevector([1, 0, 0, 1]) / np.sqrt(2) rho = DensityMatrix(psi) for label, target in [('II', 1), ('XX', 1), ('YY', -1), ('ZZ', 1), ('IX', 0), ('YZ', 0), ('ZX', 0), ('YI', 0)]: with self.subTest(msg="<{}>".format(label)): op = Pauli(label) expval = rho.expectation_value(op) self.assertAlmostEqual(expval, target) psi = Statevector([np.sqrt(2), 0, 0, 0, 0, 0, 0, 1 + 1j]) / 2 rho = DensityMatrix(psi) for label, target in [('XXX', np.sqrt(2) / 2), ('YYY', -np.sqrt(2) / 2), ('ZZZ', 0), ('XYZ', 0), ('YIY', 0)]: with self.subTest(msg="<{}>".format(label)): op = Pauli(label) expval = rho.expectation_value(op) self.assertAlmostEqual(expval, target) labels = ['XXX', 'IXI', 'YYY', 'III'] coeffs = [3.0, 5.5, -1j, 23] spp_op = SparsePauliOp.from_list(list(zip(labels, coeffs))) expval = rho.expectation_value(spp_op) target = 25.121320343559642 + 0.7071067811865476j self.assertAlmostEqual(expval, target)
def test_expval_pauli(self, pauli): """Test expectation_value method for Pauli op""" seed = 1020 op = Pauli(pauli) state = random_statevector(2**op.num_qubits, seed=seed) target = state.expectation_value(op.to_matrix()) expval = state.expectation_value(op) self.assertAlmostEqual(expval, target)
def test_expval_pauli_c_contiguous(self, pauli): """Test expectation_value method for Pauli op""" seed = 1020 op = Pauli(pauli) rho = random_density_matrix(2**op.num_qubits, seed=seed) rho._data = np.reshape(rho.data.flatten(order="C"), rho.data.shape, order="C") target = rho.expectation_value(op.to_matrix()) expval = rho.expectation_value(op) self.assertAlmostEqual(expval, target)
def test_hf_bitstring_mapped(self): """Mapped bitstring test for water""" # Original driver config when creating operator that resulted in symmetries coded # below. The sector [1, -1] is the correct ground sector. # PySCFDriver( # atom="O 0.0000 0.0000 0.1173; H 0.0000 0.07572 -0.4692;H 0.0000 -0.07572 -0.4692", # unit=UnitsType.ANGSTROM, # charge=0, # spin=0, # basis='sto-3g', # hf_method=HFMethodType.RHF) num_spin_orbitals = 14 num_particles = (5, 5) converter = QubitConverter(ParityMapper(), two_qubit_reduction=True) z2symmetries = Z2Symmetries( symmetries=[Pauli("IZZIIIIZZIII"), Pauli("ZZIZIIZZIZII")], sq_paulis=[Pauli("IIIIIIIIXIII"), Pauli("IIIIIIIIIXII")], sq_list=[3, 2], tapering_values=[1, -1], ) with self.subTest("Matched bitsring creation"): converter.force_match(num_particles=num_particles, z2symmetries=z2symmetries) bitstr = hartree_fock_bitstring_mapped( num_spin_orbitals=num_spin_orbitals, num_particles=num_particles, qubit_converter=converter, ) ref_matched = [ True, False, True, True, False, True, False, True, False, False ] self.assertListEqual(bitstr, ref_matched) with self.subTest("Bitsring creation with no tapering"): bitstr = hartree_fock_bitstring_mapped( num_spin_orbitals=num_spin_orbitals, num_particles=num_particles, qubit_converter=converter, match_convert=False, ) ref_notaper = [ True, False, True, False, True, True, False, True, False, True, False, False, ] self.assertListEqual(bitstr, ref_notaper)
def test_qubits_6_py_lih(self): """qubits 6 py lih test""" num_particles = (1, 1) converter = QubitConverter(ParityMapper(), two_qubit_reduction=True) z2symmetries = Z2Symmetries( symmetries=[Pauli("ZIZIZIZI"), Pauli("ZZIIZZII")], sq_paulis=[Pauli("IIIIIIXI"), Pauli("IIIIIXII")], sq_list=[2, 3], tapering_values=[1, 1], ) converter.force_match(num_particles=num_particles, z2symmetries=z2symmetries) state = HartreeFock(10, num_particles, converter) ref = QuantumCircuit(6) ref.x([0, 1]) self.assertEqual(state, ref)
def _rowsum_deterministic(table, aux_pauli, row): """Updating an auxilary Pauli aux_pauli in the deterministic rowsum calculation. The StabilizerState itself is not updated.""" row_phase = table.phase[row] accum_phase = aux_pauli.phase accum_pauli = aux_pauli row_pauli = table.pauli[row] row_pauli = Pauli(row_pauli.to_labels()[0]) accum_pauli, accum_phase = StabilizerState._rowsum( accum_pauli, accum_phase, row_pauli, row_phase) aux_pauli = accum_pauli aux_pauli.phase = accum_phase return aux_pauli
def test_expval(self): """Test expectation_value method""" psi = Statevector([1, 0, 0, 1]) / np.sqrt(2) rho = DensityMatrix(psi) for label, target in [ ("II", 1), ("XX", 1), ("YY", -1), ("ZZ", 1), ("IX", 0), ("YZ", 0), ("ZX", 0), ("YI", 0), ]: with self.subTest(msg=f"<{label}>"): op = Pauli(label) expval = rho.expectation_value(op) self.assertAlmostEqual(expval, target) psi = Statevector([np.sqrt(2), 0, 0, 0, 0, 0, 0, 1 + 1j]) / 2 rho = DensityMatrix(psi) for label, target in [ ("XXX", np.sqrt(2) / 2), ("YYY", -np.sqrt(2) / 2), ("ZZZ", 0), ("XYZ", 0), ("YIY", 0), ]: with self.subTest(msg=f"<{label}>"): op = Pauli(label) expval = rho.expectation_value(op) self.assertAlmostEqual(expval, target) labels = ["XXX", "IXI", "YYY", "III"] coeffs = [3.0, 5.5, -1j, 23] spp_op = SparsePauliOp.from_list(list(zip(labels, coeffs))) expval = rho.expectation_value(spp_op) target = 25.121320343559642 + 0.7071067811865476j self.assertAlmostEqual(expval, target)
def _measure_and_update(self, qubit, randbit): """Measure a single qubit and return outcome and post-measure state. Note that this function uses the QuantumStates internal random number generator for sampling the measurement outcome. The RNG seed can be set using the :meth:`seed` method. Note that stabilizer state measurements only have three probabilities: (p0, p1) = (0.5, 0.5), (1, 0), or (0, 1) The random case happens if there is a row anti-commuting with Z[qubit] """ num_qubits = self.clifford.num_qubits table = self.clifford.table stab_x = self.clifford.stabilizer.X # Check if there exists stabilizer anticommuting with Z[qubit] # in this case the measurement outcome is random z_anticommuting = np.any(stab_x[:, qubit]) if z_anticommuting == 0: # Deterministic outcome - measuring it will not change the StabilizerState aux_pauli = Pauli(num_qubits * "I") for i in range(num_qubits): if table.X[i][qubit]: aux_pauli = self._rowsum_deterministic( table, aux_pauli, i + num_qubits) outcome = aux_pauli.phase return outcome else: # Non-deterministic outcome outcome = randbit p_qubit = np.min(np.nonzero(stab_x[:, qubit])) p_qubit += num_qubits # Updating the StabilizerState for i in range(2 * num_qubits): # the last condition is not in the AG paper but we seem to need it if (table.X[i][qubit]) and (i != p_qubit) and ( i != (p_qubit - num_qubits)): self._rowsum_nondeterministic(table, i, p_qubit) table[p_qubit - num_qubits] = table[p_qubit].copy() table.X[p_qubit] = np.zeros(num_qubits) table.Z[p_qubit] = np.zeros(num_qubits) table.Z[p_qubit][qubit] = True table.phase[p_qubit] = outcome return outcome
def expectation_value(self, oper, qargs=None): """Compute the expectation value of an operator. Args: oper (Operator): an operator to evaluate expval. qargs (None or list): subsystems to apply the operator on. Returns: complex: the expectation value. """ if isinstance(oper, Pauli): return self._expectation_value_pauli(oper) if isinstance(oper, SparsePauliOp): return sum([coeff * self._expectation_value_pauli(Pauli((z, x))) for z, x, coeff in zip(oper.table.Z, oper.table.X, oper.coeffs)]) if not isinstance(oper, Operator): oper = Operator(oper) return np.trace(Operator(self).dot(oper, qargs=qargs).data)
def expectation_value(self, oper, qargs=None): """Compute the expectation value of an operator. Args: oper (Operator): an operator to evaluate expval of. qargs (None or list): subsystems to apply operator on. Returns: complex: the expectation value. """ if isinstance(oper, Pauli): return self._expectation_value_pauli(oper) if isinstance(oper, SparsePauliOp): return sum([coeff * self._expectation_value_pauli(Pauli((z, x))) for z, x, coeff in zip(oper.table.Z, oper.table.X, oper.coeffs)]) val = self.evolve(oper, qargs=qargs) conj = self.conjugate() return np.dot(conj.data, val.data)
def _rowsum_nondeterministic(table, accum, row): """Updating StabilizerState Clifford table in the non-deterministic rowsum calculation. row and accum are rows in the StabilizerState Clifford table.""" row_phase = table.phase[row] accum_phase = table.phase[accum] row_pauli = table.pauli[row] accum_pauli = table.pauli[accum] row_pauli = Pauli(row_pauli.to_labels()[0]) accum_pauli = Pauli(accum_pauli.to_labels()[0]) accum_pauli, accum_phase = StabilizerState._rowsum( accum_pauli, accum_phase, row_pauli, row_phase) table.phase[accum] = accum_phase table.X[accum] = accum_pauli.x table.Z[accum] = accum_pauli.z
def expectation_value(self, oper, qargs=None): """Compute the expectation value of a Pauli operator. Args: oper (Pauli): a Pauli operator to evaluate expval. qargs (None or list): subsystems to apply the operator on. Returns: complex: the expectation value (only 0 or 1 or -1 or i or -i). Raises: QiskitError: if oper is not a Pauli operator. """ if not isinstance(oper, Pauli): raise QiskitError( "Operator for expectation value is not a Pauli operator.") num_qubits = self.clifford.num_qubits if qargs is None: qubits = range(num_qubits) else: qubits = qargs # Construct Pauli on num_qubits pauli = Pauli(num_qubits * "I") phase = 0 pauli_phase = (-1j)**oper.phase if oper.phase else 1 for pos, qubit in enumerate(qubits): pauli.x[qubit] = oper.x[pos] pauli.z[qubit] = oper.z[pos] phase += pauli.x[qubit] & pauli.z[qubit] # Check if there is a stabilizer that anti-commutes with an odd number of qubits # If so the expectation value is 0 for p in range(num_qubits): stab = self.clifford.stabilizer num_anti = 0 num_anti += np.count_nonzero(pauli.z & stab.X[p]) num_anti += np.count_nonzero(pauli.x & stab.Z[p]) if num_anti % 2 == 1: return 0 # Otherwise pauli is (-1)^a prod_j S_j^b_j for Clifford stabilizers # If pauli anti-commutes with D_j then b_j = 1. # Multiply pauli by stabilizers with anti-commuting destabilizers pauli_z = (pauli.z).copy() # Make a copy of pauli.z for p in range(num_qubits): # Check if destabilizer anti-commutes destab = self.clifford.destabilizer num_anti = 0 num_anti += np.count_nonzero(pauli.z & destab.X[p]) num_anti += np.count_nonzero(pauli.x & destab.Z[p]) if num_anti % 2 == 0: continue # If anti-commutes multiply Pauli by stabilizer stab = self.clifford.stabilizer phase += 2 * self.clifford.table.phase[p + num_qubits] phase += np.count_nonzero(stab.Z[p] & stab.X[p]) phase += 2 * np.count_nonzero(pauli_z & stab.X[p]) pauli_z = pauli_z ^ stab.Z[p] # For valid stabilizers, `phase` can only be 0 (= 1) or 2 (= -1) at this point. if phase % 4 != 0: return -pauli_phase return pauli_phase
def expectation_value(self, oper, qargs=None): """Compute the expectation value of an operator. Args: oper (BaseOperator): an operator to evaluate expval. qargs (None or list): subsystems to apply the operator on. Returns: complex: the expectation value (only 0 or 1 or -1). """ num_qubits = self.clifford.num_qubits if qargs is None: qubits = range(num_qubits) else: qubits = qargs # Construct Pauli on num_qubits pauli = Pauli(num_qubits * "I") phase = 0 for pos, qubit in enumerate(qubits): pauli_pos = (oper.to_label())[len(oper) - 1 - pos] if pauli_pos == "X": pauli.x[qubit] = 1 elif pauli_pos == "Y": pauli.x[qubit] = 1 pauli.z[qubit] = 1 phase += 1 elif pauli_pos == "Z": pauli.z[qubit] = 1 else: pass # Check if there is a stabilizer that anti-commutes with an odd number of qubits # If so the expectation value is 0 for p in range(num_qubits): stab = self.clifford.stabilizer num_anti = 0 num_anti += np.count_nonzero(pauli.z & stab.X[p]) num_anti += np.count_nonzero(pauli.x & stab.Z[p]) if num_anti % 2 == 1: return 0 # Otherwise pauli is (-1)^a prod_j S_j^b_j for Clifford stabilizers # If pauli anti-commutes with D_j then b_j = 1. # Multiply pauli by stabilizers with anti-commuting destabilizers pauli_z = (pauli.z).copy() # Make a copy of pauli.z for p in range(num_qubits): # Check if destabilizer anti-commutes destab = self.clifford.destabilizer num_anti = 0 num_anti += np.count_nonzero(pauli.z & destab.X[p]) num_anti += np.count_nonzero(pauli.x & destab.Z[p]) if num_anti % 2 == 0: continue # If anti-commutes multiply Pauli by stabilizer stab = self.clifford.stabilizer phase += 2 * self.clifford.table.phase[p + num_qubits] phase += np.count_nonzero(stab.Z[p] & stab.X[p]) phase += 2 * np.count_nonzero(pauli_z & stab.X[p]) pauli_z = pauli_z ^ stab.Z[p] if phase % 4 != 0: return -1 return 1