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.Rot11Gate(rads=-0.5 * self.orbital_energies[i] * time).on( control_qubit, 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 Rot111Gate(rads=-2 * self.hamiltonian.two_body[p, q] * time).on(control_qubit, 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.Rot11Gate(rads=-0.5 * self.orbital_energies[i] * 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 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.Rot11Gate(rads=-self.one_body_energies[p] * time).on( control_qubit, 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: 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)) # Update prior basis change matrix. prior_basis_matrix = basis_change_matrix # Undo final basis transformation. yield bogoliubov_transform(qubits, prior_basis_matrix) # Apply phase from constant term yield cirq.RotZGate(rads=-self.hamiltonian.constant * time).on(control_qubit)
def rot_11_layer(el_jr, el_jc, half_turns): """Yields rotations about |11> conditioned on the jr and jc fields.""" gate = cirq.Rot11Gate(half_turns=half_turns) for i, jr_row in enumerate(el_jr): for j, jr_ij in enumerate(jr_row): if jr_ij == -1: yield cirq.X(cirq.GridQubit(i, j)) yield cirq.X(cirq.GridQubit(i + 1, j)) yield gate(cirq.GridQubit(i, j), cirq.GridQubit(i + 1, j)) if jr_ij == -1: yield cirq.X(cirq.GridQubit(i, j)) yield cirq.X(cirq.GridQubit(i + 1, j)) pass pass pass pass for i, jc_row in enumerate(el_jc): for j, jc_ij in enumerate(jc_row): if jc_ij == 1: yield gate(cirq.GridQubit(i, j), cirq.GridQubit(i, j + 1)) pass pass pass pass
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_cz_matrix(): assert np.allclose( cirq.Rot11Gate(half_turns=1).matrix(), np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, -1]])) assert np.allclose( cirq.Rot11Gate(half_turns=0.5).matrix(), np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1j]])) assert np.allclose( cirq.Rot11Gate(half_turns=0).matrix(), np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])) assert np.allclose( cirq.Rot11Gate(half_turns=-0.5).matrix(), np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, -1j]]))
def one_and_two_body_interaction(p, q, a, b) -> cirq.OP_TREE: yield XXYYGate(duration=self.hamiltonian.one_body[p, q].real * time).on(a, b) yield YXXYGate(duration=self.hamiltonian.one_body[p, q].imag * time).on(a, b) yield cirq.Rot11Gate(rads=-2 * self.hamiltonian.two_body[p, q] * time).on(a, b)
def default_decompose(self, qubits): a, b, c, d = qubits weights_to_exponents = (self._exponent / 4.) * numpy.array( [[1, -1, 1], [1, 1, -1], [-1, 1, 1]]) exponents = weights_to_exponents.dot(self.weights) basis_change = list( cirq.flatten_op_tree([ cirq.CNOT(b, a), cirq.CNOT(c, b), cirq.CNOT(d, c), cirq.CNOT(c, b), cirq.CNOT(b, a), cirq.CNOT(a, b), cirq.CNOT(b, c), cirq.CNOT(a, b), [cirq.X(c), cirq.X(d)], [cirq.CNOT(c, d), cirq.CNOT(d, c)], [cirq.X(c), cirq.X(d)], ])) controlled_Zs = list( cirq.flatten_op_tree([ cirq.Rot11Gate(half_turns=exponents[0])(b, c), cirq.CNOT(a, b), cirq.Rot11Gate(half_turns=exponents[1])(b, c), cirq.CNOT(b, a), cirq.CNOT(a, b), cirq.Rot11Gate(half_turns=exponents[2])(b, c) ])) controlled_swaps = [ [cirq.CNOT(c, d), cirq.H(c)], cirq.CNOT(d, c), controlled_Zs, cirq.CNOT(d, c), [op.inverse() for op in reversed(controlled_Zs)], [cirq.H(c), cirq.CNOT(c, d)], ] yield basis_change yield controlled_swaps yield basis_change[::-1]
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)
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)
def test_not_decompose_partial_czs(): circuit = cirq.Circuit.from_ops( cirq.Rot11Gate(half_turns=0.1)(*cirq.LineQubit.range(2)), ) optimizer = cirq.MergeInteractions(allow_partial_czs=True) optimizer.optimize_circuit(circuit) cz_gates = [ op.gate for op in circuit.all_operations() if isinstance(op, cirq.GateOperation) and isinstance(op.gate, cirq.Rot11Gate) ] num_full_cz = sum(1 for cz in cz_gates if cz.half_turns == 1) num_part_cz = sum(1 for cz in cz_gates if cz.half_turns != 1) assert num_full_cz == 0 assert num_part_cz == 1
def rot_11_layer(jr, jc, half_turns): """Yeilds rotations about |11> conditioned on the jr and jc fields.""" gate = cirq.Rot11Gate(half_turns=0.5) print(gate.matrix()) for i, jr_row in enumerate(jr): for j, jr_ij in enumerate(jr_row): if jr_ij == -1: yield cirq.X(cirq.GridQubit(i, j)) yield cirq.X(cirq.GridQubit(i + 1, j)) yield gate(cirq.GridQubit(i, j), cirq.GridQubit(i + 1, j)) if jr_ij == -1: yield cirq.X(cirq.GridQubit(i, j)) yield cirq.X(cirq.GridQubit(i + 1, j)) for i, jc_row in enumerate(jc): for j, jc_ij in enumerate(jc_row): if jc_ij == 1: yield gate(cirq.GridQubit(i, j), cirq.GridQubit(i, j + 1))
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)
def test_cz_extrapolate(): assert cirq.Rot11Gate(half_turns=1)**0.5 == cirq.Rot11Gate(half_turns=0.5) assert cirq.CZ**-0.25 == cirq.Rot11Gate(half_turns=1.75)
def test_cz_repr(): assert repr(cirq.Rot11Gate()) == 'cirq.CZ' assert repr(cirq.Rot11Gate(half_turns=0.5)) == '(cirq.CZ**0.5)' assert repr(cirq.Rot11Gate(half_turns=-0.25)) == '(cirq.CZ**-0.25)'
def test_cz_str(): assert str(cirq.Rot11Gate()) == 'CZ' assert str(cirq.Rot11Gate(half_turns=0.5)) == 'CZ**0.5' assert str(cirq.Rot11Gate(half_turns=-0.25)) == 'CZ**-0.25'
def test_cz_init(): assert cirq.Rot11Gate(half_turns=0.5).half_turns == 0.5 assert cirq.Rot11Gate(half_turns=5).half_turns == 1
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)
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_cz_extrapolate(): assert cirq.Rot11Gate( half_turns=1).extrapolate_effect(0.5) == cirq.Rot11Gate(half_turns=0.5) assert cirq.CZ**-0.25 == cirq.Rot11Gate(half_turns=1.75)
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)
cirq.Z(a)**-v, cirq.Z(b)**-v, )) def test_optimizes_single_iswap(): a, b = cirq.LineQubit.range(2) c = cirq.Circuit.from_ops(cirq.ISWAP(a, b)) assert_optimization_not_broken(c) cirq.MergeInteractions().optimize_circuit(c) assert len([1 for op in c.all_operations() if len(op.qubits) == 2]) == 2 @pytest.mark.parametrize( 'circuit', (cirq.Circuit.from_ops( cirq.Rot11Gate(half_turns=0.1)(*cirq.LineQubit.range(2)), ), cirq.Circuit.from_ops( cirq.Rot11Gate(half_turns=0.2)(*cirq.LineQubit.range(2)), cirq.Rot11Gate(half_turns=0.3)(*cirq.LineQubit.range(2)), ))) def test_decompose_partial_czs(circuit): optimizer = cirq.MergeInteractions(allow_partial_czs=False) optimizer.optimize_circuit(circuit) cz_gates = [ op.gate for op in circuit.all_operations() if isinstance(op, cirq.GateOperation) and isinstance(op.gate, cirq.Rot11Gate) ] num_full_cz = sum(1 for cz in cz_gates if cz.half_turns == 1) num_part_cz = sum(1 for cz in cz_gates if cz.half_turns != 1)