def test_opt_basis_two_qubit_2d(self): op = lib2.cnot() # Classical input basis -> classical output basis # Possible flip in control bit b = bases.general(2) b0 = b.subbasis([0]) b01 = b.subbasis([0, 1]) b_in = (b01, b0) op_c = op.compile(bases_in=b_in) assert op_c.bases_in[0] == b01 assert op_c.bases_in[1] == b0 assert op_c.bases_out[0] == b01 assert op_c.bases_out[1] == b01 # Classical control bit is not violated b = bases.general(2) b0 = b.subbasis([0]) b_in = (b0, b) op_c = op.compile(bases_in=b_in) assert op_c.bases_in[0] == b0 assert op_c.bases_in[1] == b assert op_c.bases_out[0] == b0 assert op_c.bases_out[1] == b # Classical target bit will become quantum for quantum control bit, # input should not be violated b = bases.general(2) b0 = b.subbasis([0]) b_in = (b, b0) op_c = op.compile(bases_in=b_in) assert op_c.bases_in[0] == b assert op_c.bases_in[1] == b0 assert op_c.bases_out[0] == b assert op_c.bases_out[1] == b
def test_chain_merge_prev(self, d, lib): b = bases.general(d) rng = np.random.RandomState(4242) dm = rng.randn(d*d, d*d) + 1j * rng.randn(d*d, d*d) dm += dm.conjugate().transpose() dm /= dm.trace() chain = Operation.from_sequence( (lib.cphase(angle=np.pi/7, leakage=0.25) if d == 3 else lib.cphase(3*np.pi / 7)).at(0, 1), lib.rotate_x(4 * np.pi / 7).at(0), ) bases_full = (b, b) chain_c = chain.compile(bases_full, bases_full) assert len(chain.operations) == 2 assert isinstance(chain_c, _PTMOperation) state1 = State.from_dm(dm, bases_full) state2 = State.from_dm(dm, bases_full) chain(state1, 0, 1) chain_c(state2, 0, 1) assert np.allclose(state1.meas_prob(0), state2.meas_prob(0)) assert np.allclose(state1.meas_prob(1), state2.meas_prob(1))
def test_rotate_z(self): sqrt2 = np.sqrt(2) qubit_basis = (bases.general(2),) dm = State(qubit_basis) rotate90 = lib.rotate_z(0.5*np.pi) rotate180 = lib.rotate_z(np.pi) rotate360 = lib.rotate_z(2*np.pi) rotate90(dm, 0) assert np.allclose(dm.to_pv(), [1, 0, 0, 0]) rotate180(dm, 0) assert np.allclose(dm.to_pv(), [1, 0, 0, 0]) # manually apply a Hadamard gate had_expansion = np.array([0.5, 0.5, sqrt2, 0]) superpos_dm = State(qubit_basis, had_expansion) rotate180(superpos_dm, 0) assert np.allclose(superpos_dm.to_pv(), [0.5, 0.5, -sqrt2, 0]) rotate90(superpos_dm, 0) assert np.allclose(superpos_dm.to_pv(), [0.5, 0.5, 0, -sqrt2]) rotate180(superpos_dm, 0) assert np.allclose(superpos_dm.to_pv(), [0.5, 0.5, 0, sqrt2]) rotate360(superpos_dm, 0) assert np.allclose(superpos_dm.to_pv(), [0.5, 0.5, 0, sqrt2])
def test_chain_merge_prev(self, d, lib): b = bases.general(d) rng = np.random.RandomState(4242) dm = rng.randn(d * d, d * d) + 1j * rng.randn(d * d, d * d) dm += dm.conjugate().transpose() dm /= dm.trace() chain = Operation.from_sequence( (lib.cphase(angle=np.pi / 7, leakage_rate=0.25) if d == 3 else lib.cphase(3 * np.pi / 7)).at(0, 1), lib.rotate_x(4 * np.pi / 7).at(0), ) bases_full = (b, b) chain_c = chain.compile(bases_full, bases_full) assert len(chain._units) == 2 assert isinstance(chain_c, PTMOperation) pv1 = PauliVector.from_dm(dm, bases_full) pv2 = PauliVector.from_dm(dm, bases_full) chain(pv1, 0, 1) chain_c(pv2, 0, 1) assert np.allclose(pv1.meas_prob(0), pv2.meas_prob(0)) assert np.allclose(pv1.meas_prob(1), pv2.meas_prob(1))
def meas_butterfly(p0_up, p1_up, p1_down, p2_down): """ Returns a gate, that corresponds to measurement-induced excitations. Each measurement should be sandwiched by two of these gates (before and after projection. This operation dephases the qubit immediately. Note: if measurement-induced leakage is reported by RB, p1_up should be twice larger, since RB would report average probabllity for both 0 and 1 state. Parameters ---------- p0_up : float Probability to excite to state 1, being in the state 0 p1_up : float Probability to excite to state 2, being in the state 1 p1_down : float Probability to relax to state 0, being in the state 1 p2_down : float Probability to relax to state 1, being in the state 2 Returns ------- quantumsim.operation._PTMOperation """ basis = (bases.general(3).computational_subbasis(), ) return amp_damping(0.5 * p0_up, 0.5 * p1_up, 0.5 * p1_down, 0.5 * p2_down).set_bases(bases_in=basis, bases_out=basis)
def amp_damping(p0_up, p1_up, p1_down, p2_down): """ A gate, that excites or relaxes a qubit with a certain probability. Parameters ---------- p0_up : float Probability to excite to state 1, being in the state 0 p1_up : float Probability to excite to state 2, being in the state 1 p1_down : float Probability to relax to state 0, being in the state 1 p2_down : float Probability to relax to state 1, being in the state 2 Returns ------- quantumsim.operation._PTMOperation """ ptm = np.identity(9, dtype=float) ptm[:3, :3] = [[1. - p0_up, p1_down, 0.], [p0_up, 1. - p1_down - p1_up, p2_down], [0., p1_up, 1 - p2_down]] basis = (bases.general(3), ) return Operation.from_ptm(ptm, basis, basis)
def idle(duration, t1, t2, anharmonicity=0.): if np.isfinite(t1) and np.isfinite(t2): t_phi = 1. / (1. / t2 - 0.5 / t1) if t_phi < 0: raise ValueError('t2 must be less than 2*t1') elif np.allclose(t_phi, 0): ops_t2 = [] else: ops_t2 = [(8. / (9 * t_phi))**0.5 * np.array([[1, 0, 0], [0, 0, 0], [0, 0, -1]]), (2. / (9 * t_phi))**0.5 * np.array([[1, 0, 0], [0, -1, 0], [0, 0, 0]]), (2. / (9 * t_phi))**0.5 * np.array([[0, 0, 0], [0, 1, 0], [0, 0, -1]])] else: ops_t2 = [] op_t1 = t1**-0.5 * np.array([[0, 1, 0], [0, 0, np.sqrt(2)], [0, 0, 0]]) if not np.allclose(anharmonicity, 0.): ham = np.array([ [0., 0., 0.], [0., 0., 0.], [0., 0., anharmonicity], ]) else: ham = None return Operation.from_lindblad_form(duration, (bases.general(3), ), hamiltonian=ham, lindblad_ops=[op_t1, *ops_t2])
def test_opt_basis_single_qubit_2d(self): b = bases.general(2) b0 = b.subbasis([0]) b1 = b.subbasis([1]) b01 = b.computational_subbasis() # Identity up to floating point error rot = lib2.rotate_x(2 * np.pi).compile(bases_in=(b0,)) assert rot.bases_in == (b0,) assert rot.bases_out == (b0,) rot = lib2.rotate_x(2 * np.pi).compile(bases_in=(b1,)) assert rot.bases_in == (b1,) assert rot.bases_out == (b1,) # RX(pi) rot = lib2.rotate_x(np.pi).compile(bases_in=(b0,)) assert rot.bases_in == (b0,) assert rot.bases_out == (b1,) rot = lib2.rotate_x(np.pi).compile(bases_in=(b1,)) assert rot.bases_in == (b1,) assert rot.bases_out == (b0,) # RY(pi/2) rot = lib2.rotate_y(np.pi / 2).compile(bases_in=(b01,)) assert rot.bases_in[0] == b01 assert rot.bases_out[0].dim_pauli == 3 assert '0' in rot.bases_out[0].labels assert '1' in rot.bases_out[0].labels assert 'X10' in rot.bases_out[0].labels
def test_kraus_to_ptm_errors(self): qubit_basis = (bases.general(2), ) qutrit_basis = (bases.general(3), ) cz_kraus_mat = np.diag([1, 1, 1, -1]) kraus_op = Operation.from_kraus(cz_kraus_mat, qubit_basis * 2) wrong_dim_kraus = np.random.random((4, 4, 2, 2)) with pytest.raises(ValueError): _ = Operation.from_kraus(wrong_dim_kraus, qubit_basis) not_sqr_kraus = np.random.random((4, 2, 3)) with pytest.raises(ValueError): _ = Operation.from_kraus(not_sqr_kraus, qubit_basis) with pytest.raises(ValueError): _ = Operation.from_kraus(cz_kraus_mat, qutrit_basis) with pytest.raises(ValueError): _ = kraus_op.set_bases(qutrit_basis * 2)
def test_lindblad_singlequbit(self): ham = random_hermitian_matrix(2, seed=56) lindblad_ops = np.array([ [[0, 0.1], [0, 0]], [[0, 0], [0, 0.33]], ]) t1 = 10 t2 = 25 b1 = (bases.general(2), ) b2 = (bases.gell_mann(2), ) op1 = Operation.from_lindblad_form(t1, b1, b2, hamiltonian=ham, lindblad_ops=lindblad_ops) op2 = Operation.from_lindblad_form(t2, b2, b1, hamiltonian=ham, lindblad_ops=lindblad_ops) op = Operation.from_lindblad_form(t1 + t2, b1, hamiltonian=ham, lindblad_ops=lindblad_ops) dm = random_hermitian_matrix(2, seed=3) state1 = PauliVector.from_dm(dm, b1) state2 = PauliVector.from_dm(dm, b1) op1(state1, 0) op2(state1, 0) op(state2, 0) assert np.allclose(state1.to_pv(), state2.to_pv())
def test_opt_basis_single_qubit_2d(self): b = bases.general(2) b0 = b.subbasis([0]) b1 = b.subbasis([1]) b01 = b.computational_subbasis() # Identity up to floating point error rot = lib2.rotate_x(2 * np.pi).compile(bases_in=(b0, )) assert rot.bases_in == (b0, ) assert rot.bases_out == (b0, ) rot = lib2.rotate_x(2 * np.pi).compile(bases_in=(b1, )) assert rot.bases_in == (b1, ) assert rot.bases_out == (b1, ) # RX(pi) rot = lib2.rotate_x(np.pi).compile(bases_in=(b0, )) assert rot.bases_in == (b0, ) assert rot.bases_out == (b1, ) rot = lib2.rotate_x(np.pi).compile(bases_in=(b1, )) assert rot.bases_in == (b1, ) assert rot.bases_out == (b0, ) # RY(pi/2) rot = lib2.rotate_y(np.pi / 2).compile(bases_in=(b01, )) assert rot.bases_in[0] == b01 assert rot.bases_out[0].dim_pauli == 3 assert '0' in rot.bases_out[0].labels assert '1' in rot.bases_out[0].labels assert 'X10' in rot.bases_out[0].labels
def test_chain_compile_leaking(self): b = bases.general(3) chain0 = Operation.from_sequence( lib3.rotate_x(0.5 * np.pi).at(2), lib3.cphase(leakage_rate=0.1).at(0, 2), lib3.cphase(leakage_rate=0.1).at(1, 2), lib3.rotate_x(-0.75 * np.pi).at(2), lib3.rotate_x(0.25 * np.pi).at(2), ) b0 = b.subbasis([0]) b01 = b.subbasis([0, 1]) b0134 = b.subbasis([0, 1, 3, 4]) chain1 = chain0.compile((b0, b0, b0134), (b, b, b)) assert isinstance(chain1, _Chain) # Ancilla is not leaking here anc_basis = chain1._units[1].operation.bases_out[1] for label in anc_basis.labels: assert '2' not in label chain2 = chain0.compile((b01, b01, b0134), (b, b, b)) # Ancilla is leaking here assert isinstance(chain2, _Chain) anc_basis = chain2._units[1].operation.bases_out[1] for label in '2', 'X20', 'Y20', 'X21', 'Y21': assert label in anc_basis.labels
def test_create_untimed_model(): basis = (bases.general(2), ) class SampleModel(Model): dim = 2 @Model.gate() def rotate_y(self, qubit): return (ParametrizedOperation(lib.rotate_y, basis), ) @Model.gate() def cphase(self, qubit_static, qubit_fluxed): return (lib.cphase(pi).at(qubit_static, qubit_fluxed), ) sample_setup = Setup(""" setup: [] """) m = SampleModel(sample_setup) cnot = m.rotate_y('D0', angle=0.5*pi) + m.cphase('D0', 'D1') + \ m.rotate_y('D0', angle=-0.5*pi) assert cnot.finalize().operation.ptm(basis * 2, basis * 2) == approx( Operation.from_sequence( lib.rotate_y(0.5 * pi).at(0), lib.cphase(pi).at(0, 1), lib.rotate_y(-0.5 * pi).at(0), ).ptm(basis * 2, basis * 2))
def test_create_timed_model(): basis = (bases.general(2), ) class SampleModel(Model): dim = 2 @Model.gate(duration=20) def rotate_y(self, qubit): return ( self.wait(qubit, 10), ParametrizedOperation(lib.rotate_y, basis), self.wait(qubit, 10), ) @Model.gate(duration='t_twoqubit') def cphase(self, qubit_static, qubit_fluxed): return ( self.wait(qubit_static, 0.5 * self.p('t_twoqubit')), self.wait(qubit_fluxed, 0.5 * self.p('t_twoqubit')), lib.cphase(pi).at(qubit_static, qubit_fluxed), self.wait(qubit_static, 0.5 * self.p('t_twoqubit')), self.wait(qubit_fluxed, 0.5 * self.p('t_twoqubit')), ) @Model.gate(duration=lambda qubit, setup: 600 if qubit == 'D0' else 400) def strange_duration_gate(self, qubit): return lib.rotate_y(pi) @staticmethod def _filter_wait_placeholders(operation): return Operation.from_sequence([ unit for unit in operation.units() if not isinstance(unit.operation, WaitPlaceholder) ]) def finalize(self, circuit, bases_in=None): return circuit.finalize([self._filter_wait_placeholders], bases_in) sample_setup = Setup(""" setup: - t_twoqubit: 40 """) m = SampleModel(sample_setup) cnot = m.rotate_y('D0', angle=0.5*pi) + m.cphase('D0', 'D1') + \ m.rotate_y('D0', angle=-0.5*pi) cnot = m.finalize(cnot) assert cnot.operation.ptm(basis * 2, basis * 2) == approx( Operation.from_sequence( lib.rotate_y(0.5 * pi).at(0), lib.cphase(pi).at(0, 1), lib.rotate_y(-0.5 * pi).at(0), ).ptm(basis * 2, basis * 2)) gate1 = m.strange_duration_gate('D0') assert gate1.duration == 600 gate2 = m.strange_duration_gate('D1') assert gate2.duration == 400
def test_circuits_add(self): dim = 2 orplus = lib.rotate_y(0.5 * pi) ocphase = lib.cphase(pi) orminus = lib.rotate_y(-0.5 * pi) grplus = Gate('Q0', dim, orplus) gcphase = Gate(('Q0', 'Q1'), dim, ocphase) grminus = Gate('Q0', dim, orminus) basis = (bases.general(2), ) * 2 circuit = grplus + gcphase assert circuit.qubits == ['Q0', 'Q1'] assert len(circuit.gates) == 2 assert c_op(circuit).ptm(basis, basis) == approx( Operation.from_sequence(orplus.at(0), ocphase.at(0, 1)).ptm(basis, basis)) circuit = circuit + grminus assert circuit.qubits == ['Q0', 'Q1'] assert len(circuit.gates) == 3 assert c_op(circuit).ptm(basis, basis) == approx( Operation.from_sequence(orplus.at(0), ocphase.at(0, 1), orminus.at(0)).ptm(basis, basis)) circuit = grplus + (gcphase + grminus) assert circuit.qubits == ['Q0', 'Q1'] assert len(circuit.gates) == 3 assert c_op(circuit).ptm(basis, basis) == approx( Operation.from_sequence(orplus.at(0), ocphase.at(0, 1), orminus.at(0)).ptm(basis, basis)) grplus = Gate('Q1', dim, orplus) grminus = Gate('Q1', dim, orminus) circuit = grplus + gcphase + grminus assert circuit.qubits == ['Q1', 'Q0'] assert len(circuit.gates) == 3 assert c_op(circuit).ptm(basis, basis) == approx( Operation.from_sequence(orplus.at(0), ocphase.at(0, 1), orminus.at(0)).ptm(basis, basis)) basis = (basis[0], ) * 3 grplus = Gate('Q2', dim, orplus) grminus = Gate('Q0', dim, orminus) circuit = grplus + gcphase + grminus assert circuit.qubits == ['Q2', 'Q0', 'Q1'] assert len(circuit.gates) == 3 assert c_op(circuit).ptm(basis, basis) == approx( Operation.from_sequence(orplus.at(0), ocphase.at(1, 2), orminus.at(1)).ptm(basis, basis)) grplus = Gate('Q0', dim, orplus) grminus = Gate('Q2', dim, orminus) circuit = grplus + gcphase + grminus assert circuit.qubits == ['Q0', 'Q1', 'Q2'] assert len(circuit.gates) == 3 assert c_op(circuit).ptm(basis, basis) == approx( Operation.from_sequence(orplus.at(0), ocphase.at(0, 1), orminus.at(2)).ptm(basis, basis))
def test_cnot(self): cnot = lib.cnot() qubit_bases = (bases.general(2), bases.general(2), bases.general(2)) dm = np.diag([0.25, 0, 0.75, 0, 0, 0, 0, 0]) s = PauliVector.from_dm(dm, qubit_bases) assert np.allclose(s.meas_prob(0), (1, 0)) assert np.allclose(s.meas_prob(1), (0.25, 0.75)) assert np.allclose(s.meas_prob(2), (1, 0)) cnot(s, 0, 1) assert np.allclose(s.meas_prob(0), (1, 0)) assert np.allclose(s.meas_prob(1), (0.25, 0.75)) assert np.allclose(s.meas_prob(2), (1, 0)) cnot(s, 1, 2) assert np.allclose(s.meas_prob(0), (1, 0)) assert np.allclose(s.meas_prob(1), (0.25, 0.75)) assert np.allclose(s.meas_prob(2), (0.25, 0.75))
def test_lindblad_two_qubit(self): b = (bases.general(2), ) id = np.array([[1, 0], [0, 1]]) ham1 = random_hermitian_matrix(2, seed=6) ham2 = random_hermitian_matrix(2, seed=7) ham = np.kron(ham1, id).reshape(2, 2, 2, 2) + \ np.kron(id, ham2).reshape(2, 2, 2, 2) dm = random_hermitian_matrix(4, seed=3) op1 = Operation.from_lindblad_form(25, b, hamiltonian=ham1) op2 = Operation.from_lindblad_form(25, b, hamiltonian=ham2) op = Operation.from_lindblad_form(25, b * 2, hamiltonian=ham) state1 = PauliVector.from_dm(dm, b * 2) state2 = PauliVector.from_dm(dm, b * 2) op1(state1, 0) op2(state1, 1) op(state2, 0, 1) assert np.allclose(state1.to_pv(), state2.to_pv()) ops1 = np.array([ [[0, 0.1], [0, 0]], [[0, 0], [0, 0.33]], ]) ops2 = np.array([ [[0, 0.15], [0, 0]], [[0, 0], [0, 0.17]], ]) ops = [np.kron(op, id).reshape(2, 2, 2, 2) for op in ops1] +\ [np.kron(id, op).reshape(2, 2, 2, 2) for op in ops2] op1 = Operation.from_lindblad_form(25, b, lindblad_ops=ops1) op2 = Operation.from_lindblad_form(25, b, lindblad_ops=ops2) op = Operation.from_lindblad_form(25, b * 2, lindblad_ops=ops) state1 = PauliVector.from_dm(dm, b * 2) state2 = PauliVector.from_dm(dm, b * 2) op1(state1, 0) op2(state1, 1) op(state2, 0, 1) assert np.allclose(state1.to_pv(), state2.to_pv()) op1 = Operation.from_lindblad_form(25, b, hamiltonian=ham1, lindblad_ops=ops1) op2 = Operation.from_lindblad_form(25, b, hamiltonian=ham2, lindblad_ops=ops2) op = Operation.from_lindblad_form(25, b * 2, hamiltonian=ham, lindblad_ops=ops) state1 = PauliVector.from_dm(dm, b * 2) state2 = PauliVector.from_dm(dm, b * 2) op1(state1, 0) op2(state1, 1) op(state2, 0, 1) assert np.allclose(state1.to_pv(), state2.to_pv())
def test_lindblad_time_inverse(self): ham = random_hermitian_matrix(2, seed=4) b = (bases.general(2), ) op_plus = Operation.from_lindblad_form(20, b, hamiltonian=ham) op_minus = Operation.from_lindblad_form(20, b, hamiltonian=-ham) dm = random_hermitian_matrix(2, seed=5) state = PauliVector.from_dm(dm, b) op_plus(state, 0) op_minus(state, 0) assert np.allclose(state.to_dm(), dm)
def test_cnot(self): cnot = lib.cnot() qubit_bases = (bases.general(2), bases.general(2), bases.general(2)) dm = np.diag([0.25, 0, 0.75, 0, 0, 0, 0, 0]) s = State.from_dm(dm, qubit_bases) assert np.allclose(s.meas_prob(0), (1, 0)) assert np.allclose(s.meas_prob(1), (0.25, 0.75)) assert np.allclose(s.meas_prob(2), (1, 0)) cnot(s, 0, 1) assert np.allclose(s.meas_prob(0), (1, 0)) assert np.allclose(s.meas_prob(1), (0.25, 0.75)) assert np.allclose(s.meas_prob(2), (1, 0)) cnot(s, 1, 2) assert np.allclose(s.meas_prob(0), (1, 0)) assert np.allclose(s.meas_prob(1), (0.25, 0.75)) assert np.allclose(s.meas_prob(2), (0.25, 0.75))
def test_compilation_with_placeholders(self): b_full = bases.general(3) b0 = b_full.subbasis([0]) b01 = b_full.subbasis([0, 1]) b012 = b_full.subbasis([0, 1, 2]) bases_in = (b01, b01, b0) bases_out = (b_full, b_full, b012) zz = Operation.from_sequence( lib3.rotate_x(-np.pi / 2).at(2), lib3.cphase(leakage_rate=0.1).at(0, 2), lib3.cphase(leakage_rate=0.25).at(2, 1), lib3.rotate_x(np.pi / 2).at(2), lib3.rotate_x(np.pi).at(0), lib3.rotate_x(np.pi).at(1)).compile(bases_in, bases_out) ptm_ref = zz.ptm(bases_in, bases_out) zz_parametrized = Operation.from_sequence( Operation.from_sequence( ParametrizedOperation(lambda angle1: lib3.rotate_x(angle1), (b_full, )).at(2), ParametrizedOperation( lambda lr02: lib3.cphase(leakage_rate=lr02), (b_full, ) * 2).at(0, 2), ParametrizedOperation( lambda lr21: lib3.cphase(leakage_rate=lr21), (b_full, ) * 2).at(2, 1), ParametrizedOperation(lambda angle2: lib3.rotate_x(angle2), (b_full, )).at(2), lib3.rotate_x(np.pi).at(0), lib3.rotate_x(np.pi).at(1))) zzpc = zz_parametrized.compile(bases_in, bases_out) assert isinstance(zzpc, _Chain) assert len(list(zzpc.units())) == 6 zz_parametrized = Operation.from_sequence( Operation.from_sequence( ParametrizedOperation(lambda angle1: lib3.rotate_x(angle1), (b_full, )).at(2), ParametrizedOperation( lambda lr02: lib3.cphase(leakage_rate=lr02), (b_full, ) * 2).at(0, 2), lib3.cphase(leakage_rate=0.25).at(2, 1), lib3.rotate_x(np.pi / 2).at(2), lib3.rotate_x(np.pi).at(0), lib3.rotate_x(np.pi).at(1))) zzpc = zz_parametrized.compile(bases_in, bases_out) assert len(list(zzpc.units())) == 4 params = dict(angle1=-np.pi / 2, lr02=0.1, foo='bar') new_units = [(op.substitute( **params) if isinstance(op, ParametrizedOperation) else op).at(*ix) for op, ix in zzpc.units()] zzpc = Operation.from_sequence(new_units).compile(bases_in, bases_out) assert len(zzpc._units) == 2 assert zzpc.ptm(bases_in, bases_out) == approx(ptm_ref)
def test_rotate_euler(self): qubit_basis = (bases.general(2),) dm = State(qubit_basis + qubit_basis) rotate90x = lib.rotate_euler(0, 0.5*np.pi, 0) rotate90y = lib.rotate_euler(0, 0.5*np.pi, 0) rotate90x(dm, 0) assert np.allclose(dm.meas_prob(0), (0.5, 0.5)) rotate90y(dm, 1) assert np.allclose(dm.meas_prob(1), (0.5, 0.5))
def test_compile_two_qubit_2d(self): b = bases.general(2) b0 = b.subbasis([0]) b01 = b.computational_subbasis() op = lib2.cnot() assert op.shape == (4, 4, 4, 4) op_full = op.compile(bases_in=(b, b)) assert op_full.shape == (4, 4, 4, 4) op_cl = op.compile(bases_in=(b01, b01)) assert op_cl.shape == (2, 2, 2, 2) op_cl = op.compile(bases_in=(b0, b)) assert op_cl.shape == (1, 4, 1, 4)
def test_hadamard(self): qubit_basis = (bases.general(2),) sys_bases = qubit_basis+qubit_basis dm = State(sys_bases) hadamard = lib.hadamard() hadamard(dm, 1) assert np.allclose(dm.meas_prob(0), (1, 0)) assert np.allclose(dm.meas_prob(1), (0.5, 0.5)) hadamard(dm, 1) assert np.allclose(dm.meas_prob(1), (1, 0))
def test_convert_ptm_basis(self): p_damp = 0.5 damp_kraus_mat = np.array([[[1, 0], [0, np.sqrt(1 - p_damp)]], [[0, np.sqrt(p_damp)], [0, 0]]]) gell_mann_basis = (bases.gell_mann(2), ) general_basis = (bases.general(2), ) op1 = Operation.from_kraus(damp_kraus_mat, gell_mann_basis) op2 = op1.set_bases(general_basis, general_basis) \ .set_bases(gell_mann_basis, gell_mann_basis) assert np.allclose(op1.ptm(gell_mann_basis), op2.ptm(gell_mann_basis)) assert op1.bases_in == op2.bases_in assert op1.bases_out == op2.bases_out
def test_convert_ptm_basis(self): p_damp = 0.5 damp_kraus_mat = np.array( [[[1, 0], [0, np.sqrt(1-p_damp)]], [[0, np.sqrt(p_damp)], [0, 0]]]) gell_mann_basis = (bases.gell_mann(2),) general_basis = (bases.general(2),) damp_op_kraus = Operation.from_kraus(damp_kraus_mat, 2) op1 = damp_op_kraus.set_bases(gell_mann_basis, gell_mann_basis) op2 = damp_op_kraus.set_bases(general_basis, general_basis) \ .set_bases(gell_mann_basis, gell_mann_basis) assert np.allclose(op1.ptm, op2.ptm) assert op1.bases_in == op2.bases_in assert op1.bases_out == op2.bases_out
def test_kraus_to_ptm_errors(self): qutrit_basis = (bases.general(3),) cz_kraus_mat = np.diag([1, 1, 1, -1]) kraus_op = Operation.from_kraus(cz_kraus_mat, 2) wrong_dim_kraus = np.random.random((4, 4, 2, 2)) with pytest.raises(ValueError): _ = Operation.from_kraus(wrong_dim_kraus, 2) not_sqr_kraus = np.random.random((4, 2, 3)) with pytest.raises(ValueError): _ = Operation.from_kraus(not_sqr_kraus, 2) with pytest.raises(ValueError): _ = Operation.from_kraus(cz_kraus_mat, 3) with pytest.raises(ValueError): _ = kraus_op.set_bases(qutrit_basis + qutrit_basis)
def test_create(self): op_1q = lib2.rotate_x(0.5 * pi) basis = (bases.general(2), ) with pytest.raises(ValueError, match=".*can't accept free arguments.*"): ParametrizedOperation(lambda *args: op_1q, basis, basis) with pytest.raises(ValueError, match=".*can't accept free keyword arguments.*"): ParametrizedOperation(lambda **kwargs: op_1q, basis, basis) with pytest.raises(OperationNotDefinedError, match="Operation placeholder does not have a PTM"): ParametrizedOperation(lambda: op_1q, basis).ptm(basis) with pytest.raises(OperationNotDefinedError, match="Operation placeholder can not be called"): ParametrizedOperation(lambda: op_1q, basis)(PauliVector(basis))
def test_zz_parity_compilation(self): b_full = bases.general(3) b0 = b_full.subbasis([0]) b01 = b_full.subbasis([0, 1]) b012 = b_full.subbasis([0, 1, 2]) bases_in = (b01, b01, b0) bases_out = (b_full, b_full, b012) zz = Operation.from_sequence( lib3.rotate_x(-np.pi / 2).at(2), lib3.cphase(leakage_rate=0.1).at(0, 2), lib3.cphase(leakage_rate=0.25).at(2, 1), lib3.rotate_x(np.pi / 2).at(2), lib3.rotate_x(np.pi).at(0), lib3.rotate_x(np.pi).at(1)) zz_ptm = zz.ptm(bases_in, bases_out) zzc = zz.compile(bases_in=bases_in, bases_out=bases_out) zzc_ptm = zzc.ptm(bases_in, bases_out) assert zz_ptm == approx(zzc_ptm) units = list(zzc.units()) assert len(units) == 2 op1, ix1 = units[0] op2, ix2 = units[1] assert ix1 == (0, 2) assert ix2 == (1, 2) assert op1.bases_in[0] == bases_in[0] assert op2.bases_in[0] == bases_in[1] assert op1.bases_in[1] == bases_in[2] # Qubit 0 did not leak assert op1.bases_out[0] == bases_out[0].subbasis([0, 1]) # Qubit 1 leaked assert op2.bases_out[0] == bases_out[1].subbasis([0, 1, 2, 6]) # Qubit 2 is measured assert op2.bases_out[1] == bases_out[2] dm = random_hermitian_matrix(3**3, seed=85) pv1 = PauliVector.from_dm(dm, (b01, b01, b0)) pv2 = PauliVector.from_dm(dm, (b01, b01, b0)) zz(pv1, 0, 1, 2) zzc(pv2, 0, 1, 2) # Compiled version still needs to be projected, so we can't compare # Pauli vectors, so we can to check only DM diagonals. assert np.allclose(pv1.diagonal(), pv2.diagonal())
def test_circuits_params(self): dim = 2 basis = (bases.general(dim), ) * 2 orotate = lib.rotate_y ocphase = lib.cphase grotate = Gate('Q0', dim, ParametrizedOperation(orotate, basis[:1])) gcphase = Gate(('Q0', 'Q1'), dim, ParametrizedOperation(ocphase, basis)) with pytest.raises(RuntimeError, match=r".*free parameters.*\n" r".*angle.*\n" r".*allow_param_repeat.*"): _ = gcphase + grotate with allow_param_repeat(): circuit = grotate + gcphase + grotate assert circuit.free_parameters == {sympy.symbols('angle')} assert len(circuit.gates) == 3 angle = 0.736 assert c_op(circuit(angle=angle)).ptm(basis, basis) == \ approx(Operation.from_sequence( orotate(angle).at(0), ocphase(angle).at(0, 1), orotate(angle).at(0) ).ptm(basis, basis)) angle1 = 0.4 * pi angle2 = 1.01 * pi angle3 = -0.6 * pi ptm_ref = Operation.from_sequence( orotate(angle1).at(0), ocphase(angle2).at(0, 1), orotate(angle3).at(0)).ptm(basis, basis) circuit = grotate(angle=angle1) + gcphase(angle=angle2) + \ grotate(angle=angle3) assert circuit.finalize().operation.ptm(basis, basis) == \ approx(ptm_ref) circuit = grotate(angle='angle1') + gcphase(angle='angle2') + \ grotate(angle='angle3') assert c_op(circuit(angle1=angle1, angle2=angle2, angle3=angle3)).ptm(basis, basis) == approx(ptm_ref)
def test_zz_parity_compilation(self): b_full = bases.general(3) b0 = b_full.subbasis([0]) b01 = b_full.subbasis([0, 1]) b012 = b_full.subbasis([0, 1, 2]) bases_in = (b01, b01, b0) bases_out = (b_full, b_full, b012) zz = Operation.from_sequence( lib3.rotate_x(-np.pi/2).at(2), lib3.cphase(leakage=0.1).at(0, 2), lib3.cphase(leakage=0.25).at(2, 1), lib3.rotate_x(np.pi/2).at(2), lib3.rotate_x(np.pi).at(0), lib3.rotate_x(np.pi).at(1) ) zzc = zz.compile(bases_in=bases_in, bases_out=bases_out) assert len(zzc.operations) == 2 op1, ix1 = zzc.operations[0] op2, ix2 = zzc.operations[1] assert ix1 == (0, 2) assert ix2 == (1, 2) assert op1.bases_in[0] == bases_in[0] assert op2.bases_in[0] == bases_in[1] assert op1.bases_in[1] == bases_in[2] # Qubit 0 did not leak assert op1.bases_out[0] == bases_out[0].subbasis([0, 1, 3, 4]) # Qubit 1 leaked assert op2.bases_out[0] == bases_out[1].subbasis([0, 1, 2, 6]) # Qubit 2 is measured assert op2.bases_out[1] == bases_out[2] dm = random_density_matrix(3**3, seed=85) state1 = State.from_dm(dm, (b01, b01, b0)) state2 = State.from_dm(dm, (b01, b01, b0)) zz(state1, 0, 1, 2) zzc(state2, 0, 1, 2) # Compiled version still needs to be projected, so we can't compare # Pauli vectors, so we can to check only DM diagonals. assert np.allclose(state1.diagonal(), state2.diagonal())
def test_chain_apply(self): b = (bases.general(2), ) * 3 dm = random_hermitian_matrix(8, seed=93) pv1 = PauliVector.from_dm(dm, b) pv2 = PauliVector.from_dm(dm, b) # Some random gate sequence op_indices = [(lib2.rotate_x(np.pi / 2), (0, )), (lib2.rotate_y(0.3333), (1, )), (lib2.cphase(), (0, 2)), (lib2.cphase(), (1, 2)), (lib2.rotate_x(-np.pi / 2), (0, ))] for op, indices in op_indices: op(pv1, *indices), circuit = Operation.from_sequence(*(op.at(*ix) for op, ix in op_indices)) circuit(pv2, 0, 1, 2) assert np.all(pv1.to_pv() == pv2.to_pv())
def test_compile_single_qubit_2d(self): b = bases.general(2) b0 = b.subbasis([0]) b01 = b.computational_subbasis() op = lib2.rotate_y(np.pi) assert op.shape == (4, 4) op_full = op.compile(bases_in=(b,)) assert op_full.shape == (4, 4) op_cl = op.compile(bases_in=(b01,)) assert op_cl.shape == (2, 2) op = lib2.rotate_x(np.pi / 3) assert op.shape == (4, 4) op_full = op.compile(bases_in=(b,), bases_out=(b01,)) # X component of a state is irrelevant for the output. assert op_full.shape == (2, 3) op_cl = op.compile(bases_in=(b0,)) assert op_cl.shape == (3, 1)
def test_compile_single_qubit_2d(self): b = bases.general(2) b0 = b.subbasis([0]) b01 = b.computational_subbasis() op = lib2.rotate_y(np.pi) assert op.shape == (4, 4) op_full = op.compile(bases_in=(b, )) assert op_full.shape == (4, 4) op_cl = op.compile(bases_in=(b01, )) assert op_cl.shape == (2, 2) op = lib2.rotate_x(np.pi / 3) assert op.shape == (4, 4) op_full = op.compile(bases_in=(b, ), bases_out=(b01, )) # X component of a state is irrelevant for the output. assert op_full.shape == (2, 3) op_cl = op.compile(bases_in=(b0, )) assert op_cl.shape == (3, 1)
def test_chain_compile_single_qubit(self, d, lib): b = bases.general(d) dm = random_hermitian_matrix(d, seed=487) bases_full = (b, ) subbases = (b.subbasis([0, 1]), ) angle = np.pi / 5 rx_angle = lib.rotate_x(angle) rx_2angle = lib.rotate_x(2 * angle) chain0 = Operation.from_sequence(rx_angle.at(0), rx_angle.at(0)) pv0 = PauliVector.from_dm(dm, bases_full) chain0(pv0, 0) assert chain0.num_qubits == 1 assert len(chain0._units) == 2 chain0_c = chain0.compile(bases_full, bases_full) assert isinstance(chain0_c, PTMOperation) pv1 = PauliVector.from_dm(dm, bases_full) chain0_c(pv1, 0) assert chain0_c.num_qubits == 1 assert isinstance(chain0_c, PTMOperation) op_angle = chain0_c op_2angle = rx_2angle.compile(bases_full, bases_full) assert isinstance(op_2angle, PTMOperation) assert op_angle.shape == op_2angle.shape assert op_angle.bases_in == op_2angle.bases_in assert op_angle.bases_out == op_2angle.bases_out assert op_angle.ptm(op_angle.bases_in, op_angle.bases_out) == \ approx(op_2angle.ptm(op_2angle.bases_in, op_2angle.bases_out)) assert pv1.to_pv() == approx(pv0.to_pv()) rx_pi = lib.rotate_x(np.pi) chain_2pi = Operation.from_sequence(rx_pi.at(0), rx_pi.at(0)) chain_2pi_c1 = chain_2pi.compile(subbases, bases_full) assert isinstance(chain_2pi_c1, PTMOperation) assert chain_2pi_c1.bases_in == subbases assert chain_2pi_c1.bases_out == subbases chain_2pi_c2 = chain_2pi.compile(bases_full, subbases) assert isinstance(chain_2pi_c2, PTMOperation) assert chain_2pi_c2.bases_in == subbases assert chain_2pi_c2.bases_out == subbases
def test_chain_compile_three_qubit(self, d, lib): b = bases.general(d) b0 = b.subbasis([0]) chain0 = Operation.from_sequence( lib.rotate_x(0.5*np.pi).at(2), lib.cphase().at(0, 2), lib.cphase().at(1, 2), lib.rotate_x(-0.75*np.pi).at(2), lib.rotate_x(0.25*np.pi).at(2), ) chain1 = chain0.compile((b, b, b0), (b, b, b)) assert chain1.operations[0].indices == (0, 2) assert chain1.operations[0].operation.bases_in == (b, b0) assert chain1.operations[0].operation.bases_out[0] == b assert chain1.operations[1].indices == (1, 2) assert chain1.operations[1].operation.bases_in[0] == b assert chain1.operations[1].operation.bases_out[0] == b for label in '0', '1', 'X10', 'Y10': assert label in chain1.operations[1].operation.bases_out[1].labels
def test_chain_apply(self): b = (bases.general(2), ) * 3 dm = random_density_matrix(8, seed=93) state1 = State.from_dm(dm, b) state2 = State.from_dm(dm, b) # Some random gate sequence op_indices = [(lib2.rotate_x(np.pi / 2), (0, )), (lib2.rotate_y(0.3333), (1, )), (lib2.cphase(), (0, 2)), (lib2.cphase(), (1, 2)), (lib2.rotate_x(-np.pi / 2), (0, ))] for op, indices in op_indices: op(state1, *indices), circuit = Operation.from_sequence(*(op.at(*ix) for op, ix in op_indices)) circuit(state2, 0, 1, 2) assert np.all(state1.to_pv() == state2.to_pv())
def test_chain_apply(self): b = (bases.general(2),) * 3 dm = random_density_matrix(8, seed=93) state1 = State.from_dm(dm, b) state2 = State.from_dm(dm, b) # Some random gate sequence op_indices = [(lib2.rotate_x(np.pi/2), (0,)), (lib2.rotate_y(0.3333), (1,)), (lib2.cphase(), (0, 2)), (lib2.cphase(), (1, 2)), (lib2.rotate_x(-np.pi/2), (0,))] for op, indices in op_indices: op(state1, *indices), circuit = Operation.from_sequence( *(op.at(*ix) for op, ix in op_indices)) circuit(state2, 0, 1, 2) assert np.all(state1.to_pv() == state2.to_pv())
def test_chain_compile_single_qubit(self, d, lib): b = bases.general(d) dm = random_density_matrix(d, seed=487) bases_full = (b,) subbases = (b.subbasis([0, 1]),) angle = np.pi/5 rx_angle = lib.rotate_x(angle) rx_2angle = lib.rotate_x(2*angle) chain0 = Operation.from_sequence(rx_angle.at(0), rx_angle.at(0)) state0 = State.from_dm(dm, bases_full) chain0(state0, 0) assert chain0.num_qubits == 1 assert len(chain0.operations) == 2 chain0_c = chain0.compile(bases_full, bases_full) state1 = State.from_dm(dm, bases_full) chain0_c(state1, 0) assert chain0_c.num_qubits == 1 assert isinstance(chain0_c, _PTMOperation) op_angle = chain0_c op_2angle = rx_2angle.compile(bases_full, bases_full) assert op_angle.shape == op_2angle.shape assert op_angle.bases_in == op_2angle.bases_in assert op_angle.bases_out == op_2angle.bases_out assert op_angle.ptm == approx(op_2angle.ptm) assert state1.to_pv() == approx(state0.to_pv()) rx_pi = lib.rotate_x(np.pi) chain_2pi = Operation.from_sequence(rx_pi.at(0), rx_pi.at(0)) chain_2pi_c1 = chain_2pi.compile(subbases, bases_full) assert isinstance(chain_2pi_c1, _PTMOperation) assert chain_2pi_c1.bases_in == subbases assert chain_2pi_c1.bases_out == subbases chain_2pi_c2 = chain_2pi.compile(bases_full, subbases) assert isinstance(chain_2pi_c2, _PTMOperation) assert chain_2pi_c2.bases_in == subbases assert chain_2pi_c2.bases_out == subbases
def test_rotate_x(self): basis = (bases.general(3),) sys_bases = basis * 3 dm = State(sys_bases) rotate90 = lib.rotate_x(0.5*np.pi) rotate180 = lib.rotate_x(np.pi) rotate360 = lib.rotate_x(2*np.pi) rotate90(dm, 1) rotate180(dm, 2) assert np.allclose(dm.meas_prob(0), (1, 0, 0)) assert np.allclose(dm.meas_prob(1), (0.5, 0.5, 0)) assert np.allclose(dm.meas_prob(2), (0, 1, 0)) rotate180(dm, 1) assert np.allclose(dm.meas_prob(1), (0.5, 0.5, 0)) rotate90(dm, 1) assert np.allclose(dm.meas_prob(1), (1, 0, 0)) rotate360(dm, 0) assert np.allclose(dm.meas_prob(0), (1, 0, 0))
def test_rotate_y(self): qubit_basis = (bases.general(2),) sys_bases = qubit_basis+qubit_basis+qubit_basis dm = State(sys_bases) rotate90 = lib.rotate_y(0.5*np.pi) rotate180 = lib.rotate_y(np.pi) rotate360 = lib.rotate_y(2*np.pi) rotate90(dm, 1) rotate180(dm, 2) assert np.allclose(dm.meas_prob(0), (1, 0)) assert np.allclose(dm.meas_prob(1), (0.5, 0.5)) assert np.allclose(dm.meas_prob(2), (0, 1)) rotate180(dm, 1) assert np.allclose(dm.meas_prob(1), (0.5, 0.5)) rotate90(dm, 1) assert np.allclose(dm.meas_prob(1), (1, 0)) rotate360(dm, 0) assert np.allclose(dm.meas_prob(0), (1, 0))
def test_chain_merge_next(self, d, lib): b = bases.general(d) dm = random_density_matrix(d**2, seed=574) chain = Operation.from_sequence( lib.rotate_x(np.pi / 5).at(0), (lib.cphase(angle=3*np.pi/7, leakage=0.1) if d == 3 else lib.cphase(3*np.pi / 7)).at(0, 1), ) bases_full = (b, b) chain_c = chain.compile(bases_full, bases_full) assert len(chain.operations) == 2 assert isinstance(chain_c, _PTMOperation) state1 = State.from_dm(dm, bases_full) state2 = State.from_dm(dm, bases_full) chain(state1, 0, 1) chain_c(state2, 0, 1) assert state1.meas_prob(0) == approx(state2.meas_prob(0)) assert state1.meas_prob(1) == approx(state2.meas_prob(1))
def test_chain_compile_leaking(self): b = bases.general(3) chain0 = Operation.from_sequence( lib3.rotate_x(0.5*np.pi).at(2), lib3.cphase(leakage=0.1).at(0, 2), lib3.cphase(leakage=0.1).at(1, 2), lib3.rotate_x(-0.75*np.pi).at(2), lib3.rotate_x(0.25*np.pi).at(2), ) b0 = b.subbasis([0]) b01 = b.subbasis([0, 1]) b0134 = b.subbasis([0, 1, 3, 4]) chain1 = chain0.compile((b0, b0, b0134), (b, b, b)) # Ancilla is not leaking here anc_basis = chain1.operations[1].operation.bases_out[1] for label in anc_basis.labels: assert '2' not in label chain2 = chain0.compile((b01, b01, b0134), (b, b, b)) # Ancilla is leaking here anc_basis = chain2.operations[1].operation.bases_out[1] for label in '2', 'X20', 'Y20', 'X21', 'Y21': assert label in anc_basis.labels
def idle(duration, t1, t2, anharmonicity=0.): t_phi = 1./(1./t2 - 0.5/t1) op_t1 = t1**-0.5 * np.array([ [0, 1, 0], [0, 0, np.sqrt(2)], [0, 0, 0] ]) ops_t2 = [ (8. / (9*t_phi))**0.5 * np.array([ [1, 0, 0], [0, 0, 0], [0, 0, -1] ]), (2. / (9*t_phi))**0.5 * np.array([ [1, 0, 0], [0, -1, 0], [0, 0, 0] ]), (2. / (9*t_phi))**0.5 * np.array([ [0, 0, 0], [0, 1, 0], [0, 0, -1] ]) ] if not np.allclose(anharmonicity, 0.): ham = np.array([ [0., 0., 0.], [0., 0., 0.], [0., 0., anharmonicity], ]) else: ham = None return Operation.from_lindblad_form( duration, bases.general(3), hamiltonian=ham, lindblad_ops=[op_t1, *ops_t2])