def generate_ising(n_spins, coup, field): ''' Args: n_spins (integer) coup (float) field (float) Returns: Hamiltonian of Ising model with ZZ interaction a X transverse field ''' int_list = [] field_list = [] for i in range(n_spins - 1): int_list.append(generate_pauli([], [i, i + 1], n_spins)) for i in range(n_spins): field_list.append(generate_pauli([i], [], n_spins)) int_coeff = [coup] * len(int_list) field_coeff = [field] * len(field_list) H = PauliOp(int_list[0], int_coeff[0]) for i in range(1, len(int_list)): H = H + PauliOp(int_list[i], int_coeff[i]) for i in range(len(field_list)): H = H + PauliOp(field_list[i], field_coeff[i]) return H
def test_to_matrix(self): """to matrix text""" np.testing.assert_array_equal(X.to_matrix(), Operator.from_label("X").data) np.testing.assert_array_equal(Y.to_matrix(), Operator.from_label("Y").data) np.testing.assert_array_equal(Z.to_matrix(), Operator.from_label("Z").data) op1 = Y + H np.testing.assert_array_almost_equal(op1.to_matrix(), Y.to_matrix() + H.to_matrix()) op2 = op1 * 0.5 np.testing.assert_array_almost_equal(op2.to_matrix(), op1.to_matrix() * 0.5) op3 = (4 - 0.6j) * op2 np.testing.assert_array_almost_equal(op3.to_matrix(), op2.to_matrix() * (4 - 0.6j)) op4 = op3.tensor(X) np.testing.assert_array_almost_equal( op4.to_matrix(), np.kron(op3.to_matrix(), X.to_matrix())) op5 = op4.compose(H ^ I) np.testing.assert_array_almost_equal( op5.to_matrix(), np.dot(op4.to_matrix(), (H ^ I).to_matrix())) op6 = op5 + PrimitiveOp(Operator.from_label("+r").data) np.testing.assert_array_almost_equal( op6.to_matrix(), op5.to_matrix() + Operator.from_label("+r").data) param = Parameter("α") m = np.array([[0, -1j], [1j, 0]]) op7 = MatrixOp(m, param) np.testing.assert_array_equal(op7.to_matrix(), m * param) param = Parameter("β") op8 = PauliOp(primitive=Pauli("Y"), coeff=param) np.testing.assert_array_equal(op8.to_matrix(), m * param) param = Parameter("γ") qc = QuantumCircuit(1) qc.h(0) op9 = CircuitOp(qc, coeff=param) m = np.array([[1, 1], [1, -1]]) / np.sqrt(2) np.testing.assert_array_equal(op9.to_matrix(), m * param)
def generate_XYZ(J_x, J_y, J_z, field, n_spins=3, pbc=True): ''' Args: n_spins (integer) J_x, J_y, J_z: coeff of the spin-spin interaction h: h field (float) pbc: periodic boundary condition Returns: Hamiltonian of XYZ model with XX, YY, ZZ interactions and a Z transverse field ''' int_x_list = [] int_y_list = [] int_z_list = [] field_list = [] if pbc: int_z_list.append(generate_pauli([], [0, n_spins - 1], n_spins)) int_x_list.append(generate_pauli([0, n_spins - 1], [], n_spins)) int_y_list.append( generate_pauli([0, n_spins - 1], [0, n_spins - 1], n_spins)) for i in range(n_spins - 1): int_z_list.append(generate_pauli([], [i, i + 1], n_spins)) for i in range(n_spins - 1): int_x_list.append(generate_pauli([i, i + 1], [], n_spins)) for i in range(n_spins - 1): int_y_list.append(generate_pauli([i, i + 1], [i, i + 1], n_spins)) for i in range(n_spins): field_list.append(generate_pauli([], [i], n_spins)) int_x_coeff = [J_x] * len(int_x_list) int_y_coeff = [J_x] * len(int_y_list) int_z_coeff = [J_x] * len(int_z_list) field_coeff = [field] * len(field_list) H = PauliOp(int_x_list[0], int_x_coeff[0]) for i in range(1, len(int_x_list)): H = H + PauliOp(int_x_list[i], int_x_coeff[i]) for i in range(0, len(int_y_list)): H = H + PauliOp(int_y_list[i], int_y_coeff[i]) for i in range(0, len(int_z_list)): H = H + PauliOp(int_z_list[i], int_z_coeff[i]) for i in range(len(field_list)): H = H + PauliOp(field_list[i], field_coeff[i]) return -0.5 * H
def _compress_pauli_op( num_qubits: int, total_hamiltonian: Union[PauliSumOp, PauliOp, OperatorBase], unused_qubits: List[int], ) -> Union[PauliOp, OperatorBase]: table_z = total_hamiltonian.primitive.z table_x = total_hamiltonian.primitive.x new_table_z, new_table_x = _calc_reduced_pauli_tables( num_qubits, table_x, table_z, unused_qubits) total_hamiltonian_compressed = PauliOp(Pauli((new_table_z, new_table_x))) return total_hamiltonian_compressed
def test_coder_operators(self): """Test runtime encoder and decoder for operators.""" x = Parameter("x") y = x + 1 qc = QuantumCircuit(1) qc.h(0) coeffs = np.array([1, 2, 3, 4, 5, 6]) table = PauliTable.from_labels( ["III", "IXI", "IYY", "YIZ", "XYZ", "III"]) op = (2.0 * I ^ I) z2_symmetries = Z2Symmetries( [Pauli("IIZI"), Pauli("ZIII")], [Pauli("IIXI"), Pauli("XIII")], [1, 3], [-1, 1]) isqrt2 = 1 / np.sqrt(2) sparse = scipy.sparse.csr_matrix([[0, isqrt2, 0, isqrt2]]) subtests = ( PauliSumOp(SparsePauliOp(Pauli("XYZX"), coeffs=[2]), coeff=3), PauliSumOp(SparsePauliOp(Pauli("XYZX"), coeffs=[1]), coeff=y), PauliSumOp(SparsePauliOp(Pauli("XYZX"), coeffs=[1 + 2j]), coeff=3 - 2j), PauliSumOp.from_list([("II", -1.052373245772859), ("IZ", 0.39793742484318045)]), PauliSumOp(SparsePauliOp(table, coeffs), coeff=10), MatrixOp(primitive=np.array([[0, -1j], [1j, 0]]), coeff=x), PauliOp(primitive=Pauli("Y"), coeff=x), CircuitOp(qc, coeff=x), EvolvedOp(op, coeff=x), TaperedPauliSumOp(SparsePauliOp(Pauli("XYZX"), coeffs=[2]), z2_symmetries), StateFn(qc, coeff=x), CircuitStateFn(qc, is_measurement=True), DictStateFn("1" * 3, is_measurement=True), VectorStateFn(np.ones(2**3, dtype=complex)), OperatorStateFn(CircuitOp(QuantumCircuit(1))), SparseVectorStateFn(sparse), Statevector([1, 0]), CVaRMeasurement(Z, 0.2), ComposedOp([(X ^ Y ^ Z), (Z ^ X ^ Y ^ Z).to_matrix_op()]), SummedOp([X ^ X * 2, Y ^ Y], 2), TensoredOp([(X ^ Y), (Z ^ I)]), (Z ^ Z) ^ (I ^ 2), ) for op in subtests: with self.subTest(op=op): encoded = json.dumps(op, cls=RuntimeEncoder) self.assertIsInstance(encoded, str) decoded = json.loads(encoded, cls=RuntimeDecoder) self.assertEqual(op, decoded)
def _fix_qubits( operator: Union[int, PauliSumOp, PauliOp, OperatorBase], has_side_chain_second_bead: bool = False, ) -> Union[int, PauliSumOp, PauliOp, OperatorBase]: """ Assigns predefined values for turns qubits on positions 0, 1, 2, 3, 5 in the main chain without the loss of generality (see the paper https://arxiv.org/pdf/1908.02163.pdf). Qubits on these position are considered fixed and not subject to optimization. Args: operator: an operator whose qubits shall be fixed. Returns: An operator with relevant qubits changed to fixed values. """ # operator might be 0 (int) because it is initialized as operator = 0; then we should not # attempt fixing qubits if (not isinstance(operator, PauliOp) and not isinstance(operator, PauliSumOp) and not isinstance(operator, OperatorBase)): return operator operator = operator.reduce() new_tables = [] new_coeffs = [] if isinstance(operator, PauliOp): table_z = np.copy(operator.primitive.z) table_x = np.copy(operator.primitive.x) _preset_binary_vals(table_z, has_side_chain_second_bead) return PauliOp(Pauli((table_z, table_x))) for hamiltonian in operator: table_z = np.copy(hamiltonian.primitive.paulis.z[0]) table_x = np.copy(hamiltonian.primitive.paulis.x[0]) coeffs = _calc_updated_coeffs(hamiltonian, table_z, has_side_chain_second_bead) _preset_binary_vals(table_z, has_side_chain_second_bead) new_table = np.concatenate((table_x, table_z), axis=0) new_tables.append(new_table) new_coeffs.append(coeffs) new_pauli_table = PauliTable(data=new_tables) operator_updated = PauliSumOp( SparsePauliOp(data=new_pauli_table, coeffs=new_coeffs)) operator_updated = operator_updated.reduce() return operator_updated
def synthesize(self, evolution): # get operators and time to evolve operators = evolution.operator time = evolution.time if not isinstance(operators, list): pauli_list = [(Pauli(op), coeff) for op, coeff in operators.to_list()] coeffs = [np.real(coeff) for op, coeff in operators.to_list()] else: pauli_list = [(op, 1) for op in operators] coeffs = [1 for op in operators] # We artificially make the weights positive weights = np.abs(coeffs) lambd = np.sum(weights) num_gates = int(np.ceil(2 * (lambd**2) * (time**2) * self.reps)) # The protocol calls for the removal of the individual coefficients, # and multiplication by a constant evolution time. evolution_time = lambd * time / num_gates self.sampled_ops = algorithm_globals.random.choice( np.array(pauli_list, dtype=object), size=(num_gates, ), p=weights / lambd, ) # Update the coefficients of sampled_ops self.sampled_ops = [(op, evolution_time) for op, coeff in self.sampled_ops] # pylint: disable=cyclic-import from qiskit.circuit.library.pauli_evolution import PauliEvolutionGate from qiskit.opflow import PauliOp # Build the evolution circuit using the LieTrotter synthesis with the sampled operators lie_trotter = LieTrotter(insert_barriers=self.insert_barriers, atomic_evolution=self.atomic_evolution) evolution_circuit = PauliEvolutionGate( sum(PauliOp(op) for op, coeff in self.sampled_ops), time=evolution_time, synthesis=lie_trotter, ).definition return evolution_circuit
def test_pauli_op_to_circuit(self): """Test PauliOp.to_circuit()""" with self.subTest("single Pauli"): pauli = PauliOp(Pauli("Y")) expected = QuantumCircuit(1) expected.y(0) self.assertEqual(pauli.to_circuit(), expected) with self.subTest("single Pauli with phase"): pauli = PauliOp(Pauli("-iX")) expected = QuantumCircuit(1) expected.x(0) expected.global_phase = -pi / 2 self.assertEqual(Operator(pauli.to_circuit()), Operator(expected)) with self.subTest("two qubit"): pauli = PauliOp(Pauli("IX")) expected = QuantumCircuit(2) expected.pauli("IX", range(2)) self.assertEqual(pauli.to_circuit(), expected) expected = QuantumCircuit(2) expected.x(0) expected.id(1) self.assertEqual(pauli.to_circuit().decompose(), expected) with self.subTest("two qubit with phase"): pauli = PauliOp(Pauli("iXZ")) expected = QuantumCircuit(2) expected.pauli("XZ", range(2)) expected.global_phase = pi / 2 self.assertEqual(pauli.to_circuit(), expected) expected = QuantumCircuit(2) expected.z(0) expected.x(1) expected.global_phase = pi / 2 self.assertEqual(pauli.to_circuit().decompose(), expected)
def test_summed_op_reduce(self): """Test SummedOp""" sum_op = (X ^ X * 2) + (Y ^ Y) # type: PauliSumOp sum_op = sum_op.to_pauli_op() # type: SummedOp[PauliOp] with self.subTest("SummedOp test 1"): self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ["XX", "YY"]) self.assertListEqual([op.coeff for op in sum_op], [2, 1]) sum_op = (X ^ X * 2) + (Y ^ Y) sum_op += Y ^ Y sum_op = sum_op.to_pauli_op() # type: SummedOp[PauliOp] with self.subTest("SummedOp test 2-a"): self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ["XX", "YY", "YY"]) self.assertListEqual([op.coeff for op in sum_op], [2, 1, 1]) sum_op = sum_op.collapse_summands() with self.subTest("SummedOp test 2-b"): self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ["XX", "YY"]) self.assertListEqual([op.coeff for op in sum_op], [2, 2]) sum_op = (X ^ X * 2) + (Y ^ Y) sum_op += (Y ^ Y) + (X ^ X * 2) sum_op = sum_op.to_pauli_op() # type: SummedOp[PauliOp] with self.subTest("SummedOp test 3-a"): self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ["XX", "YY", "YY", "XX"]) self.assertListEqual([op.coeff for op in sum_op], [2, 1, 1, 2]) sum_op = sum_op.reduce().to_pauli_op() with self.subTest("SummedOp test 3-b"): self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ["XX", "YY"]) self.assertListEqual([op.coeff for op in sum_op], [4, 2]) sum_op = SummedOp([X ^ X * 2, Y ^ Y], 2) with self.subTest("SummedOp test 4-a"): self.assertEqual(sum_op.coeff, 2) self.assertListEqual([str(op.primitive) for op in sum_op], ["XX", "YY"]) self.assertListEqual([op.coeff for op in sum_op], [2, 1]) sum_op = sum_op.collapse_summands() with self.subTest("SummedOp test 4-b"): self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ["XX", "YY"]) self.assertListEqual([op.coeff for op in sum_op], [4, 2]) sum_op = SummedOp([X ^ X * 2, Y ^ Y], 2) sum_op += Y ^ Y with self.subTest("SummedOp test 5-a"): self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ["XX", "YY", "YY"]) self.assertListEqual([op.coeff for op in sum_op], [4, 2, 1]) sum_op = sum_op.collapse_summands() with self.subTest("SummedOp test 5-b"): self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ["XX", "YY"]) self.assertListEqual([op.coeff for op in sum_op], [4, 3]) sum_op = SummedOp([X ^ X * 2, Y ^ Y], 2) sum_op += ((X ^ X) * 2 + (Y ^ Y)).to_pauli_op() with self.subTest("SummedOp test 6-a"): self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ["XX", "YY", "XX", "YY"]) self.assertListEqual([op.coeff for op in sum_op], [4, 2, 2, 1]) sum_op = sum_op.collapse_summands() with self.subTest("SummedOp test 6-b"): self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ["XX", "YY"]) self.assertListEqual([op.coeff for op in sum_op], [6, 3]) sum_op = SummedOp([X ^ X * 2, Y ^ Y], 2) sum_op += sum_op with self.subTest("SummedOp test 7-a"): self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ["XX", "YY", "XX", "YY"]) self.assertListEqual([op.coeff for op in sum_op], [4, 2, 4, 2]) sum_op = sum_op.collapse_summands() with self.subTest("SummedOp test 7-b"): self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ["XX", "YY"]) self.assertListEqual([op.coeff for op in sum_op], [8, 4]) sum_op = SummedOp([X ^ X * 2, Y ^ Y], 2) + SummedOp([X ^ X * 2, Z ^ Z], 3) with self.subTest("SummedOp test 8-a"): self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ["XX", "YY", "XX", "ZZ"]) self.assertListEqual([op.coeff for op in sum_op], [4, 2, 6, 3]) sum_op = sum_op.collapse_summands() with self.subTest("SummedOp test 8-b"): self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ["XX", "YY", "ZZ"]) self.assertListEqual([op.coeff for op in sum_op], [10, 2, 3]) sum_op = SummedOp([]) with self.subTest("SummedOp test 9"): self.assertEqual(sum_op.reduce(), sum_op) sum_op = ((Z + I) ^ Z) + (Z ^ X) with self.subTest("SummedOp test 10"): expected = SummedOp([ PauliOp(Pauli("ZZ")), PauliOp(Pauli("IZ")), PauliOp(Pauli("ZX")) ]) self.assertEqual(sum_op.to_pauli_op(), expected)
H = generate_ising(spins, V, g) print(wfn) print(H) ### Backend shots = 8000 backend = Aer.get_backend('qasm_simulator') instance = QuantumInstance(backend=backend, shots=shots) ### Prepare the observables to measure obs = {} # Magnetization for i in range(spins): obs['Sz_' + str(i)] = PauliOp(generate_pauli([], [i], spins), 1.0) obs['Sx_' + str(i)] = PauliOp(generate_pauli([i], [], spins), 1.0) obs['Sy_' + str(i)] = PauliOp(generate_pauli([i], [i], spins), 1.0) for (name, pauli) in obs.items(): print(name) print(pauli) ### Initialize the algorithm # Choose a specific set of parameters initial_point = None # Choose the gradient optimizer: 'sgd', 'adam' opt = 'sgd' # Choose how to estimate the gradient on hardware: 'param_shift', 'spsa'
def test_h2_bopes_sampler_auxiliaries(self): """Test BOPES Sampler on H2""" # Molecule dof = partial(Molecule.absolute_distance, atom_pair=(1, 0)) m = Molecule( geometry=[["H", [0.0, 0.0, 1.0]], ["H", [0.0, 0.45, 1.0]]], degrees_of_freedom=[dof], ) driver = ElectronicStructureMoleculeDriver( m, driver_type=ElectronicStructureDriverType.PYSCF) problem = ElectronicStructureProblem(driver) qubit_converter = QubitConverter(JordanWignerMapper(), z2symmetry_reduction=None) quantum_instance = QuantumInstance( backend=qiskit.providers.aer.Aer.get_backend( "aer_simulator_statevector"), seed_simulator=self.seed, seed_transpiler=self.seed, ) solver = VQE(quantum_instance=quantum_instance) me_gsc = GroundStateEigensolver(qubit_converter, solver) # Sets up the auxiliary operators def build_hamiltonian( current_problem: BaseProblem) -> SecondQuantizedOp: """Returns the SecondQuantizedOp H(R) where H is the electronic hamiltonian and R is the current nuclear coordinates. This gives the electronic energies.""" hamiltonian_name = current_problem.main_property_name hamiltonian_op = current_problem.second_q_ops().get( hamiltonian_name, None) return hamiltonian_op aux = { "PN": problem.second_q_ops()["ParticleNumber"], # SecondQuantizedOp "EN": build_hamiltonian, # Callable "IN": PauliOp(Pauli("IIII"), 1.0), # PauliOp } # Note that the first item is defined once for R=0.45. # The second item is a function of the problem giving the electronic energy. # At each step, a perturbation is applied to the molecule degrees of freedom which updates # the aux_operators. # The third item is the identity written as a PauliOp, yielding the norm of the eigenstates. # Sets up the BOPESSampler sampler = BOPESSampler(me_gsc) # absolute internuclear distance in Angstrom points = [0.7, 1.0, 1.3] results = sampler.sample(problem, points, aux_operators=aux) points_run = results.points particle_numbers = [] total_energies = [] norm_eigenstates = [] for results_point in list(results.raw_results.values()): aux_op_dict = results_point.raw_result.aux_operator_eigenvalues particle_numbers.append(aux_op_dict["PN"][0]) total_energies.append(aux_op_dict["EN"][0] + results_point.nuclear_repulsion_energy) norm_eigenstates.append(aux_op_dict["IN"][0]) points_run_reference = [0.7, 1.0, 1.3] particle_numbers_reference = [2, 2, 2] total_energies_reference = [-1.136, -1.101, -1.035] norm_eigenstates_reference = [1, 1, 1] np.testing.assert_array_almost_equal(points_run, points_run_reference) np.testing.assert_array_almost_equal(particle_numbers, particle_numbers_reference, decimal=2) np.testing.assert_array_almost_equal( total_energies, total_energies_reference, decimal=2, ) np.testing.assert_array_almost_equal( norm_eigenstates, norm_eigenstates_reference, decimal=2, )
def to_ising(quad_prog: QuadraticProgram) -> Tuple[OperatorBase, float]: """Return the Ising Hamiltonian of this problem. Variables are mapped to qubits in the same order, i.e., i-th variable is mapped to i-th qubit. See https://github.com/Qiskit/qiskit-terra/issues/1148 for details. Returns: qubit_op: The qubit operator for the problem offset: The constant value in the Ising Hamiltonian. Raises: QiskitOptimizationError: If an integer variable or a continuous variable exists in the problem. QiskitOptimizationError: If constraints exist in the problem. """ # if problem has variables that are not binary, raise an error if quad_prog.get_num_vars() > quad_prog.get_num_binary_vars(): raise QiskitOptimizationError( "The type of all variables must be binary. " "You can use `QuadraticProgramToQubo` converter " "to convert integer variables to binary variables. " "If the problem contains continuous variables, `to_ising` cannot handle it. " "You might be able to solve it with `ADMMOptimizer`.") # if constraints exist, raise an error if quad_prog.linear_constraints or quad_prog.quadratic_constraints: raise QiskitOptimizationError( "There must be no constraint in the problem. " "You can use `QuadraticProgramToQubo` converter " "to convert constraints to penalty terms of the objective function." ) # initialize Hamiltonian. num_nodes = quad_prog.get_num_vars() pauli_list = [] offset = 0.0 zero = np.zeros(num_nodes, dtype=bool) # set a sign corresponding to a maximized or minimized problem. # sign == 1 is for minimized problem. sign == -1 is for maximized problem. sense = quad_prog.objective.sense.value # convert a constant part of the object function into Hamiltonian. offset += quad_prog.objective.constant * sense # convert linear parts of the object function into Hamiltonian. for idx, coef in quad_prog.objective.linear.to_dict().items(): z_p = zero.copy() weight = coef * sense / 2 z_p[idx] = True pauli_list.append(PauliOp(Pauli((z_p, zero)), -weight)) offset += weight # create Pauli terms for (i, j), coeff in quad_prog.objective.quadratic.to_dict().items(): weight = coeff * sense / 4 if i == j: offset += weight else: z_p = zero.copy() z_p[i] = True z_p[j] = True pauli_list.append(PauliOp(Pauli((z_p, zero)), weight)) z_p = zero.copy() z_p[i] = True pauli_list.append(PauliOp(Pauli((z_p, zero)), -weight)) z_p = zero.copy() z_p[j] = True pauli_list.append(PauliOp(Pauli((z_p, zero)), -weight)) offset += weight # Remove paulis whose coefficients are zeros. qubit_op = sum(pauli_list) # qubit_op could be the integer 0, in this case return an identity operator of # appropriate size if isinstance(qubit_op, OperatorBase): qubit_op = qubit_op.reduce() else: qubit_op = I ^ num_nodes return qubit_op, offset