def trotter_step( self, qubits: Sequence[cirq.QubitId], time: float, control_qubit: Optional[cirq.QubitId] = None) -> cirq.OP_TREE: n_qubits = len(qubits) # Simulate the one-body terms for half of the full time yield (cirq.RotZGate(rads=-0.5 * self.orbital_energies[i] * time).on( qubits[i]) for i in range(n_qubits)) # Rotate to the computational basis yield bogoliubov_transform(qubits, self.basis_change_matrix) # Simulate the two-body terms for the full time def two_body_interaction(p, q, a, b) -> cirq.OP_TREE: yield cirq.Rot11Gate(rads=-2 * self.hamiltonian.two_body[p, q] * time).on(a, b) yield swap_network(qubits, two_body_interaction) # The qubit ordering has been reversed qubits = qubits[::-1] # Rotate back to the basis in which the one-body term is diagonal yield cirq.inverse( bogoliubov_transform(qubits, self.basis_change_matrix)) # Simulate the one-body terms for half of the full time yield (cirq.RotZGate(rads=-0.5 * self.orbital_energies[i] * time).on( qubits[i]) for i in range(n_qubits))
def test_z_matrix(): assert np.allclose( cirq.RotZGate(half_turns=1).matrix(), np.array([[1, 0], [0, -1]])) assert np.allclose( cirq.RotZGate(half_turns=0.5).matrix(), np.array([[1, 0], [0, 1j]])) assert np.allclose( cirq.RotZGate(half_turns=0).matrix(), np.array([[1, 0], [0, 1]])) assert np.allclose( cirq.RotZGate(half_turns=-0.5).matrix(), np.array([[1, 0], [0, -1j]]))
def test_single_qubit_matrix_to_gates_fuzz_half_turns_merge_z_gates( pre_turns, post_turns): intended_effect = cirq.dot( cirq.RotZGate(half_turns=2 * pre_turns).matrix(), cirq.X.matrix(), cirq.RotZGate(half_turns=2 * post_turns).matrix()) gates = cirq.single_qubit_matrix_to_gates(intended_effect, tolerance=1e-7) assert len(gates) <= 2 assert_gates_implement_unitary(gates, intended_effect, atol=1e-6)
def test_single_qubit_matrix_to_native_gates_fuzz_half_turns_always_one_gate( pre_turns, post_turns): intended_effect = cirq.dot( cirq.RotZGate(half_turns=2 * pre_turns).matrix(), cirq.X.matrix(), cirq.RotZGate(half_turns=2 * post_turns).matrix()) gates = decompositions.single_qubit_matrix_to_native_gates( intended_effect, tolerance=0.0001) assert len(gates) == 1 assert_gates_implement_unitary(gates, intended_effect)
def operations(self, qubits: Sequence[cirq.QubitId]) -> cirq.OP_TREE: """Produce the operations of the ansatz circuit.""" n_qubits = len(qubits) param_set = set(self.params()) for i in range(self.iterations): # Change to the basis in which the one-body term is diagonal yield bogoliubov_transform( qubits, self.one_body_basis_change_matrix.T.conj()) # Simulate the one-body terms. for p in range(n_qubits): u_symbol = LetterWithSubscripts('U', p, i) if u_symbol in param_set: yield cirq.RotZGate(half_turns=u_symbol).on(qubits[p]) # Simulate each singular vector of the two-body terms. prior_basis_matrix = self.one_body_basis_change_matrix for j in range(len(self.eigenvalues)): # Get the basis change matrix. basis_change_matrix = self.basis_change_matrices[j] # Merge previous basis change matrix with the inverse of the # current one merged_basis_change_matrix = numpy.dot( prior_basis_matrix, basis_change_matrix.T.conj()) yield bogoliubov_transform(qubits, merged_basis_change_matrix) # Simulate the off-diagonal two-body terms. def two_body_interaction(p, q, a, b) -> cirq.OP_TREE: v_symbol = LetterWithSubscripts('V', p, q, j, i) if v_symbol in param_set: yield cirq.Rot11Gate(half_turns=v_symbol).on(a, b) yield swap_network(qubits, two_body_interaction) qubits = qubits[::-1] # Simulate the diagonal two-body terms. for p in range(n_qubits): u_symbol = LetterWithSubscripts('U', p, j, i) if u_symbol in param_set: yield cirq.RotZGate(half_turns=u_symbol).on(qubits[p]) # Update prior basis change matrix. prior_basis_matrix = basis_change_matrix # Undo final basis transformation. yield bogoliubov_transform(qubits, prior_basis_matrix)
def test_ignores_czs_separated_by_parameterized(): a, b = cirq.LineQubit.range(2) assert_optimizes( before=cirq.Circuit([ cirq.Moment([cirq.CZ(a, b)]), cirq.Moment([cirq.RotZGate(half_turns=cirq.Symbol('boo'))(a)]), cirq.Moment([cirq.CZ(a, b)]), ]), expected=cirq.Circuit([ cirq.Moment([cirq.CZ(a, b)]), cirq.Moment([cirq.RotZGate(half_turns=cirq.Symbol('boo'))(a)]), cirq.Moment([cirq.CZ(a, b)]), ]))
def trotter_step( self, qubits: Sequence[cirq.QubitId], time: float, control_qubit: Optional[cirq.QubitId] = None) -> cirq.OP_TREE: n_qubits = len(qubits) # Change to the basis in which the one-body term is diagonal yield bogoliubov_transform(qubits, self.one_body_basis_change_matrix.T.conj()) # Simulate the one-body terms. for p in range(n_qubits): yield cirq.RotZGate(rads=-self.one_body_energies[p] * time).on( qubits[p]) # Simulate each singular vector of the two-body terms. prior_basis_matrix = self.one_body_basis_change_matrix for j in range(len(self.eigenvalues)): # Get the two-body coefficients and basis change matrix. two_body_coefficients = self.scaled_density_density_matrices[j] basis_change_matrix = self.basis_change_matrices[j] # Merge previous basis change matrix with the inverse of the # current one merged_basis_change_matrix = numpy.dot( prior_basis_matrix, basis_change_matrix.T.conj()) yield bogoliubov_transform(qubits, merged_basis_change_matrix) # Simulate the off-diagonal two-body terms. yield swap_network( qubits, lambda p, q, a, b: cirq.Rot11Gate( rads=-2 * two_body_coefficients[p, q] * time).on(a, b)) qubits = qubits[::-1] # Simulate the diagonal two-body terms. for p in range(n_qubits): yield cirq.RotZGate(rads=-two_body_coefficients[p, p] * time).on(qubits[p]) # Update prior basis change matrix prior_basis_matrix = basis_change_matrix # Undo final basis transformation yield bogoliubov_transform(qubits, prior_basis_matrix)
def _slater_basis_change( qubits: Sequence[cirq.QubitId], transformation_matrix: numpy.ndarray, initially_occupied_orbitals: Optional[Sequence[int]]) -> cirq.OP_TREE: n_qubits = len(qubits) if initially_occupied_orbitals is None: decomposition, diagonal = givens_decomposition_square( transformation_matrix) circuit_description = list(reversed(decomposition)) # The initial state is not a computational basis state so the # phases left on the diagonal in the decomposition matter yield (cirq.RotZGate(rads=numpy.angle(diagonal[j])).on(qubits[j]) for j in range(n_qubits)) else: initially_occupied_orbitals = cast(Sequence[int], initially_occupied_orbitals) transformation_matrix = transformation_matrix[list( initially_occupied_orbitals)] n_occupied = len(initially_occupied_orbitals) # Flip bits so that the first n_occupied are 1 and the rest 0 initially_occupied_orbitals_set = set(initially_occupied_orbitals) yield (cirq.X(qubits[j]) for j in range(n_qubits) if (j < n_occupied) != (j in initially_occupied_orbitals_set)) circuit_description = slater_determinant_preparation_circuit( transformation_matrix) yield _ops_from_givens_rotations_circuit_description( qubits, circuit_description)
def rot_z_layer(h, half_turns): """Yields Z rotations by half_turns conditioned on the field h.""" gate = cirq.RotZGate(half_turns=half_turns) for i, h_row in enumerate(h): for j, h_ij in enumerate(h_row): if h_ij == 1: yield gate(cirq.GridQubit(i, j))
def _gaussian_basis_change( qubits: Sequence[cirq.QubitId], transformation_matrix: numpy.ndarray, initially_occupied_orbitals: Optional[Sequence[int]]) -> cirq.OP_TREE: n_qubits = len(qubits) # Rearrange the transformation matrix because the OpenFermion routine # expects it to describe annihilation operators rather than creation # operators left_block = transformation_matrix[:, :n_qubits] right_block = transformation_matrix[:, n_qubits:] transformation_matrix = numpy.block( [numpy.conjugate(right_block), numpy.conjugate(left_block)]) decomposition, left_decomposition, _, left_diagonal = ( fermionic_gaussian_decomposition(transformation_matrix)) if (initially_occupied_orbitals is not None and len(initially_occupied_orbitals) == 0): # Starting with the vacuum state yields additional symmetry circuit_description = list(reversed(decomposition)) else: if initially_occupied_orbitals is None: # The initial state is not a computational basis state so the # phases left on the diagonal in the Givens decomposition matter yield (cirq.RotZGate(rads=numpy.angle(left_diagonal[j])).on( qubits[j]) for j in range(n_qubits)) circuit_description = list(reversed(decomposition + left_decomposition)) yield _ops_from_givens_rotations_circuit_description( qubits, circuit_description)
def test_arbitrary_xyz_repr(): cirq.testing.assert_equivalent_repr( cirq.RotXGate(half_turns=0.1, global_shift_in_half_turns=0.2)) cirq.testing.assert_equivalent_repr( cirq.RotYGate(half_turns=0.1, global_shift_in_half_turns=0.2)) cirq.testing.assert_equivalent_repr( cirq.RotZGate(half_turns=0.1, global_shift_in_half_turns=0.2))
def test_text_diagrams(): a = cirq.NamedQubit('a') b = cirq.NamedQubit('b') circuit = Circuit.from_ops( cirq.SWAP(a, b), cirq.X(a), cirq.Y(a), cirq.Z(a), cirq.RotZGate(half_turns=cirq.Symbol('x')).on(a), cirq.CZ(a, b), cirq.CNOT(a, b), cirq.CNOT(b, a), cirq.H(a), cirq.ISWAP(a, b), cirq.ISWAP(a, b)**-1) assert circuit.to_text_diagram().strip() == """ a: ───×───X───Y───Z───Z^x───@───@───X───H───iSwap───iSwap────── │ │ │ │ │ │ b: ───×─────────────────────@───X───@───────iSwap───iSwap^-1─── """.strip() assert circuit.to_text_diagram(use_unicode_characters=False).strip() == """ a: ---swap---X---Y---Z---Z^x---@---@---X---H---iSwap---iSwap------ | | | | | | b: ---swap---------------------@---X---@-------iSwap---iSwap^-1--- """.strip()
def trotter_step( self, qubits: Sequence[cirq.QubitId], time: float, control_qubit: Optional[cirq.QubitId] = None) -> cirq.OP_TREE: n_qubits = len(qubits) # Apply one- and two-body interactions for the full time def one_and_two_body_interaction(p, q, a, b) -> cirq.OP_TREE: yield ControlledXXYYGate( duration=self.hamiltonian.one_body[p, q].real * time).on( control_qubit, a, b) yield ControlledYXXYGate( duration=self.hamiltonian.one_body[p, q].imag * time).on( control_qubit, a, b) yield Rot111Gate(rads=-2 * self.hamiltonian.two_body[p, q] * time).on(control_qubit, a, b) yield swap_network(qubits, one_and_two_body_interaction, fermionic=True) qubits = qubits[::-1] # Apply one-body potential for the full time yield (cirq.Rot11Gate(rads=-self.hamiltonian.one_body[i, i].real * time).on(control_qubit, qubits[i]) for i in range(n_qubits)) # Apply phase from constant term yield cirq.RotZGate(rads=-self.hamiltonian.constant * time).on(control_qubit)
def test_rot_gates_eq(): eq = cirq.testing.EqualsTester() gates = [ cirq.RotXGate, cirq.RotYGate, cirq.RotZGate, cirq.CNotGate, cirq.Rot11Gate ] for gate in gates: eq.add_equality_group(gate(half_turns=3.5), gate(half_turns=-0.5), gate(rads=-np.pi / 2), gate(degs=-90)) eq.make_equality_group(lambda: gate(half_turns=0)) eq.make_equality_group(lambda: gate(half_turns=0.5)) eq.add_equality_group(cirq.RotXGate(), cirq.RotXGate(half_turns=1), cirq.X) eq.add_equality_group(cirq.RotYGate(), cirq.RotYGate(half_turns=1), cirq.Y) eq.add_equality_group(cirq.RotZGate(), cirq.RotZGate(half_turns=1), cirq.Z) eq.add_equality_group( cirq.RotZGate(half_turns=1, global_shift_in_half_turns=-0.5), cirq.RotZGate(half_turns=5, global_shift_in_half_turns=-0.5)) eq.add_equality_group( cirq.RotZGate(half_turns=3, global_shift_in_half_turns=-0.5)) eq.add_equality_group( cirq.RotZGate(half_turns=1, global_shift_in_half_turns=-0.1)) eq.add_equality_group( cirq.RotZGate(half_turns=5, global_shift_in_half_turns=-0.1)) eq.add_equality_group(cirq.CNotGate(), cirq.CNotGate(half_turns=1), cirq.CNOT) eq.add_equality_group(cirq.Rot11Gate(), cirq.Rot11Gate(half_turns=1), cirq.CZ)
def operations(self, qubits: Sequence[cirq.QubitId]) -> cirq.OP_TREE: """Produce the operations of the ansatz circuit.""" # TODO implement asymmetric ansatzes? for i in range(self.iterations): suffix = '-{}'.format(i) if self.iterations > 1 else '' # Apply one- and two-body interactions with a swap network that # reverses the order of the modes def one_and_two_body_interaction(p, q, a, b) -> cirq.OP_TREE: if 'T{}_{}'.format(p, q) + suffix in self.params: yield XXYYGate( half_turns=self.params['T{}_{}'.format(p, q) + suffix]).on(a, b) if 'W{}_{}'.format(p, q) + suffix in self.params: yield YXXYGate( half_turns=self.params['W{}_{}'.format(p, q) + suffix]).on(a, b) if 'V{}_{}'.format(p, q) + suffix in self.params: yield cirq.Rot11Gate( half_turns=self.params['V{}_{}'.format(p, q) + suffix]).on(a, b) yield swap_network(qubits, one_and_two_body_interaction, fermionic=True) qubits = qubits[::-1] # Apply one-body potential yield (cirq.RotZGate(half_turns=self.params['U{}'.format(p) + suffix]).on(qubits[p]) for p in range(len(qubits)) if 'U{}'.format(p) + suffix in self.params) # Apply one- and two-body interactions again. This time, reorder # them so that the entire iteration is symmetric def one_and_two_body_interaction_reversed_order(p, q, a, b) -> cirq.OP_TREE: if 'V{}_{}'.format(p, q) + suffix in self.params: yield cirq.Rot11Gate( half_turns=self.params['V{}_{}'.format(p, q) + suffix]).on(a, b) if 'W{}_{}'.format(p, q) + suffix in self.params: yield YXXYGate( half_turns=self.params['W{}_{}'.format(p, q) + suffix]).on(a, b) if 'T{}_{}'.format(p, q) + suffix in self.params: yield XXYYGate( half_turns=self.params['T{}_{}'.format(p, q) + suffix]).on(a, b) yield swap_network(qubits, one_and_two_body_interaction_reversed_order, fermionic=True, offset=True) qubits = qubits[::-1]
def test_parameterizable_effect(): q = cirq.NamedQubit('q') r = cirq.ParamResolver({'a': 0.5}) op1 = cirq.GateOperation(cirq.RotZGate(half_turns=cirq.Symbol('a')), [q]) assert cirq.is_parameterized(op1) op2 = cirq.resolve_parameters(op1, r) assert not cirq.is_parameterized(op2) assert op2 == cirq.S.on(q)
def operations(self, qubits: Sequence[cirq.QubitId]) -> cirq.OP_TREE: """Produce the operations of the ansatz circuit.""" # TODO implement asymmetric ansatz # Change to the basis in which the one-body term is diagonal yield cirq.inverse( bogoliubov_transform(qubits, self.basis_change_matrix)) for i in range(self.iterations): suffix = '-{}'.format(i) if self.iterations > 1 else '' # Simulate one-body terms yield (cirq.RotZGate(half_turns=self.params['U{}'.format(p) + suffix]).on(qubits[p]) for p in range(len(qubits)) if 'U{}'.format(p) + suffix in self.params) # Rotate to the computational basis yield bogoliubov_transform(qubits, self.basis_change_matrix) # Simulate the two-body terms def two_body_interaction(p, q, a, b) -> cirq.OP_TREE: if 'V{}_{}'.format(p, q) + suffix in self.params: yield cirq.Rot11Gate( half_turns=self.params['V{}_{}'.format(p, q) + suffix]).on(a, b) yield swap_network(qubits, two_body_interaction) qubits = qubits[::-1] # Rotate back to the basis in which the one-body term is diagonal yield cirq.inverse( bogoliubov_transform(qubits, self.basis_change_matrix)) # Simulate one-body terms again yield (cirq.RotZGate(half_turns=self.params['U{}'.format(p) + suffix]).on(qubits[p]) for p in range(len(qubits)) if 'U{}'.format(p) + suffix in self.params) # Rotate to the computational basis yield bogoliubov_transform(qubits, self.basis_change_matrix)
def operations(self, qubits: Sequence[cirq.QubitId]) -> cirq.OP_TREE: """Produce the operations of the ansatz circuit.""" # TODO implement asymmetric ansatz param_set = set(self.params()) # Change to the basis in which the one-body term is diagonal yield cirq.inverse( bogoliubov_transform(qubits, self.basis_change_matrix)) for i in range(self.iterations): # Simulate one-body terms for p in range(len(qubits)): u_symbol = LetterWithSubscripts('U', p, i) if u_symbol in param_set: yield cirq.RotZGate(half_turns=u_symbol).on(qubits[p]) # Rotate to the computational basis yield bogoliubov_transform(qubits, self.basis_change_matrix) # Simulate the two-body terms def two_body_interaction(p, q, a, b) -> cirq.OP_TREE: v_symbol = LetterWithSubscripts('V', p, q, i) if v_symbol in param_set: yield cirq.Rot11Gate(half_turns=v_symbol).on(a, b) yield swap_network(qubits, two_body_interaction) qubits = qubits[::-1] # Rotate back to the basis in which the one-body term is diagonal yield cirq.inverse( bogoliubov_transform(qubits, self.basis_change_matrix)) # Simulate one-body terms again for p in range(len(qubits)): u_symbol = LetterWithSubscripts('U', p, i) if u_symbol in param_set: yield cirq.RotZGate(half_turns=u_symbol).on(qubits[p]) # Rotate to the computational basis yield bogoliubov_transform(qubits, self.basis_change_matrix)
def _rot(self, qubit, params): """Helper function that returns an arbitrary rotation of the form R = Rz(params[2]) * Ry(params[1]) * Rx(params[0]) on the qubit, e.g. R |qubit>. Note that order is reversed when put into the circuit. The circuit is: |qubit>---Rx(params[0])---Ry(params[1])---Rz(params[2])--- """ rx = cirq.RotXGate(half_turns=params[0]) ry = cirq.RotYGate(half_turns=params[1]) rz = cirq.RotZGate(half_turns=params[2]) yield (rx(qubit), ry(qubit), rz(qubit))
def operations(self, qubits: Sequence[cirq.QubitId]) -> cirq.OP_TREE: """Produce the operations of the ansatz circuit.""" # TODO implement asymmetric ansatz param_set = set(self.params()) for i in range(self.iterations): # Apply one- and two-body interactions with a swap network that # reverses the order of the modes def one_and_two_body_interaction(p, q, a, b) -> cirq.OP_TREE: t_symbol = LetterWithSubscripts('T', p, q, i) w_symbol = LetterWithSubscripts('W', p, q, i) v_symbol = LetterWithSubscripts('V', p, q, i) if t_symbol in param_set: yield XXYYGate(half_turns=t_symbol).on(a, b) if w_symbol in param_set: yield YXXYGate(half_turns=w_symbol).on(a, b) if v_symbol in param_set: yield cirq.Rot11Gate(half_turns=v_symbol).on(a, b) yield swap_network(qubits, one_and_two_body_interaction, fermionic=True) qubits = qubits[::-1] # Apply one-body potential for p in range(len(qubits)): u_symbol = LetterWithSubscripts('U', p, i) if u_symbol in param_set: yield cirq.RotZGate(half_turns=u_symbol).on(qubits[p]) # Apply one- and two-body interactions again. This time, reorder # them so that the entire iteration is symmetric def one_and_two_body_interaction_reversed_order(p, q, a, b) -> cirq.OP_TREE: t_symbol = LetterWithSubscripts('T', p, q, i) w_symbol = LetterWithSubscripts('W', p, q, i) v_symbol = LetterWithSubscripts('V', p, q, i) if v_symbol in param_set: yield cirq.Rot11Gate(half_turns=v_symbol).on(a, b) if w_symbol in param_set: yield YXXYGate(half_turns=w_symbol).on(a, b) if t_symbol in param_set: yield XXYYGate(half_turns=t_symbol).on(a, b) yield swap_network(qubits, one_and_two_body_interaction_reversed_order, fermionic=True, offset=True) qubits = qubits[::-1]
def trotter_step( self, qubits: Sequence[cirq.QubitId], time: float, control_qubit: Optional[cirq.QubitId] = None) -> cirq.OP_TREE: n_qubits = len(qubits) # Apply one- and two-body interactions for half of the full time def one_and_two_body_interaction(p, q, a, b) -> cirq.OP_TREE: yield XXYYGate(duration=0.5 * self.hamiltonian.one_body[p, q].real * time).on( a, b) yield YXXYGate(duration=0.5 * self.hamiltonian.one_body[p, q].imag * time).on( a, b) yield cirq.Rot11Gate(rads=-self.hamiltonian.two_body[p, q] * time).on(a, b) yield swap_network(qubits, one_and_two_body_interaction, fermionic=True) qubits = qubits[::-1] # Apply one-body potential for the full time yield (cirq.RotZGate(rads=-self.hamiltonian.one_body[i, i].real * time).on(qubits[i]) for i in range(n_qubits)) # Apply one- and two-body interactions for half of the full time # This time, reorder the operations so that the entire Trotter step is # symmetric def one_and_two_body_interaction_reverse_order(p, q, a, b) -> cirq.OP_TREE: yield cirq.Rot11Gate(rads=-self.hamiltonian.two_body[p, q] * time).on(a, b) yield YXXYGate(duration=0.5 * self.hamiltonian.one_body[p, q].imag * time).on( a, b) yield XXYYGate(duration=0.5 * self.hamiltonian.one_body[p, q].real * time).on( a, b) yield swap_network(qubits, one_and_two_body_interaction_reverse_order, fermionic=True, offset=True)
def test_parameterizable_effect(): q = cirq.NamedQubit('q') r = cirq.ParamResolver({'a': 0.5}) # If the gate isn't parameterizable, you get a type error. op0 = cirq.GateOperation(cirq.Gate(), [q]) assert not cirq.can_cast(cirq.ParameterizableEffect, op0) with pytest.raises(TypeError): _ = op0.is_parameterized() with pytest.raises(TypeError): _ = op0.with_parameters_resolved_by(r) op1 = cirq.GateOperation(cirq.RotZGate(half_turns=cirq.Symbol('a')), [q]) assert cirq.can_cast(cirq.ParameterizableEffect, op1) assert op1.is_parameterized() op2 = op1.with_parameters_resolved_by(r) assert not op2.is_parameterized() assert op2 == cirq.S.on(q)
def rot_z_layer(h, half_turns): """Yields Z rotations by half_turns conditioned on the field h.""" for (i, j), h_ij in np.ndenumerate(h): yield cirq.RotZGate(half_turns=(h_ij * half_turns))(cirq.GridQubit( i, j))
def trotter_step( self, qubits: Sequence[cirq.QubitId], time: float, control_qubit: Optional[cirq.QubitId]=None ) -> cirq.OP_TREE: n_qubits = len(qubits) # Simulate the off-diagonal one-body terms. yield swap_network( qubits, lambda p, q, a, b: ControlledXXYYGate(duration= self.one_body_coefficients[p, q].real * time).on( control_qubit, a, b), fermionic=True) qubits = qubits[::-1] # Simulate the diagonal one-body terms. yield (cirq.Rot11Gate(rads= -self.one_body_coefficients[j, j].real * time).on( control_qubit, qubits[j]) for j in range(n_qubits)) # Simulate each singular vector of the two-body terms. prior_basis_matrix = numpy.identity(n_qubits, complex) for j in range(len(self.eigenvalues)): # Get the basis change matrix and its inverse. two_body_coefficients = self.scaled_density_density_matrices[j] basis_change_matrix = self.basis_change_matrices[j] # If the basis change matrix is unitary, merge rotations. # Otherwise, you must simulate two basis rotations. is_unitary = cirq.is_unitary(basis_change_matrix) if is_unitary: inverse_basis_matrix = numpy.conjugate( numpy.transpose(basis_change_matrix)) merged_basis_matrix = numpy.dot(prior_basis_matrix, inverse_basis_matrix) yield bogoliubov_transform(qubits, merged_basis_matrix) else: # TODO add LiH test to cover this. # coverage: ignore if j: yield bogoliubov_transform(qubits, prior_basis_matrix) yield cirq.inverse( bogoliubov_transform(qubits, basis_change_matrix)) # Simulate the off-diagonal two-body terms. yield swap_network( qubits, lambda p, q, a, b: Rot111Gate(rads= -2 * two_body_coefficients[p, q] * time).on( control_qubit, a, b)) qubits = qubits[::-1] # Simulate the diagonal two-body terms. yield (cirq.Rot11Gate(rads= -two_body_coefficients[k, k] * time).on( control_qubit, qubits[k]) for k in range(n_qubits)) # Undo basis transformation non-unitary case. # Else, set basis change matrix to prior matrix for merging. if is_unitary: prior_basis_matrix = basis_change_matrix else: # TODO add LiH test to cover this. # coverage: ignore yield bogoliubov_transform(qubits, basis_change_matrix) prior_basis_matrix = numpy.identity(n_qubits, complex) # Undo final basis transformation in unitary case. if is_unitary: yield bogoliubov_transform(qubits, prior_basis_matrix) # Apply phase from constant term yield cirq.RotZGate(rads=-self.constant * time).on(control_qubit)
def test_z_init(): z = cirq.RotZGate(half_turns=5) assert z.half_turns == 1
def test_z_extrapolate(): assert cirq.RotZGate(half_turns=1)**0.5 == cirq.RotZGate(half_turns=0.5) assert cirq.Z**-0.25 == cirq.RotZGate(half_turns=1.75) assert cirq.RotZGate(half_turns=0.5).phase_by( 0.25, 0) == cirq.RotZGate(half_turns=0.5)