def test_CheckMulType(): "Qobj multiplication type" # ket-bra and bra-ket multiplication psi = basis(5) dm = psi * psi.dag() assert_(dm.isoper) assert_(dm.isherm) nrm = psi.dag() * psi assert_equal(np.prod(nrm.shape), 1) assert_((abs(nrm) == 1)[0, 0]) # operator-operator multiplication H1 = rand_herm(3) H2 = rand_herm(3) out = H1 * H2 assert_(out.isoper) out = H1 * H1 assert_(out.isoper) assert_(out.isherm) out = H2 * H2 assert_(out.isoper) assert_(out.isherm) U = rand_unitary(5) out = U.dag() * U assert_(out.isoper) assert_(out.isherm) N = num(5) out = N * N assert_(out.isoper) assert_(out.isherm) # operator-ket and bra-operator multiplication op = sigmax() ket1 = basis(2) ket2 = op * ket1 assert_(ket2.isket) bra1 = basis(2).dag() bra2 = bra1 * op assert_(bra2.isbra) assert_(bra2.dag() == ket2) # superoperator-operket and operbra-superoperator multiplication sop = to_super(sigmax()) opket1 = operator_to_vector(fock_dm(2)) opket2 = sop * opket1 assert(opket2.isoperket) opbra1 = operator_to_vector(fock_dm(2)).dag() opbra2 = opbra1 * sop assert(opbra2.isoperbra) assert_(opbra2.dag() == opket2)
def testOperatorListState(self): """ expect: operator list and state """ res = expect([sigmax(), sigmay(), sigmaz()], fock(2, 0)) assert_(len(res) == 3) assert_(all(abs(res - [0, 0, 1]) < 1e-12)) res = expect([sigmax(), sigmay(), sigmaz()], fock_dm(2, 1)) assert_(len(res) == 3) assert_(all(abs(res - [0, 0, -1]) < 1e-12))
def __init__(self, N, correct_global_phase=True, sx=None, sz=None, sxsy=None): """ Parameters ---------- sx: Integer/List The delta for each of the qubits in the system. sz: Integer/List The epsilon for each of the qubits in the system. sxsy: Integer/List The interaction strength for each of the qubit pair in the system. """ super(SpinChain, self).__init__(N, correct_global_phase) self.sx_ops = [tensor([sigmax() if m == n else identity(2) for n in range(N)]) for m in range(N)] self.sz_ops = [tensor([sigmaz() if m == n else identity(2) for n in range(N)]) for m in range(N)] self.sxsy_ops = [] for n in range(N - 1): x = [identity(2)] * N x[n] = x[n + 1] = sigmax() y = [identity(2)] * N y[n] = y[n + 1] = sigmay() self.sxsy_ops.append(tensor(x) + tensor(y)) if sx is None: self.sx_coeff = [0.25 * 2 * np.pi] * N elif not isinstance(sx, list): self.sx_coeff = [sx * 2 * np.pi] * N else: self.sx_coeff = sx if sz is None: self.sz_coeff = [1.0 * 2 * np.pi] * N elif not isinstance(sz, list): self.sz_coeff = [sz * 2 * np.pi] * N else: self.sz_coeff = sz if sxsy is None: self.sxsy_coeff = [0.1 * 2 * np.pi] * (N - 1) elif not isinstance(sxsy, list): self.sxsy_coeff = [sxsy * 2 * np.pi] * (N - 1) else: self.sxsy_coeff = sxsy
def test_unitarity_known(): """ Metrics: Unitarity for known cases. """ def case(q_oper, known_unitarity): assert_almost_equal(unitarity(q_oper), known_unitarity) yield case, to_super(sigmax()), 1.0 yield case, sum(map( to_super, [qeye(2), sigmax(), sigmay(), sigmaz()] )) / 4, 0.0 yield case, sum(map( to_super, [qeye(2), sigmax()] )) / 2, 1 / 3.0
def test_known_iscptp(self): """ Superoperator: iscp, istp and iscptp known cases. """ # Check that unitaries are CPTP. assert_(identity(2).iscptp) assert_(sigmax().iscptp) # The partial transpose map, whose Choi matrix is SWAP, is TP but not # CP. W = Qobj(swap(), type='super', superrep='choi') assert_(W.istp) assert_(not W.iscp) assert_(not W.iscptp) # Subnormalized maps (representing erasure channels, for instance) # can be CP but not TP. subnorm_map = Qobj(identity(4) * 0.9, type='super', superrep='super') assert_(subnorm_map.iscp) assert_(not subnorm_map.istp) assert_(not subnorm_map.iscptp) # Check that things which aren't even operators aren't identified as # CPTP. assert_(not (basis(2).iscptp))
def add_annotation(self, state_or_vector, text, **kwargs): """Add a text or LaTeX annotation to Bloch sphere, parametrized by a qubit state or a vector. Parameters ---------- state_or_vector : Qobj/array/list/tuple Position for the annotaion. Qobj of a qubit or a vector of 3 elements. text : str/unicode Annotation text. You can use LaTeX, but remember to use raw string e.g. r"$\\langle x \\rangle$" or escape backslashes e.g. "$\\\\langle x \\\\rangle$". **kwargs : Options as for mplot3d.axes3d.text, including: fontsize, color, horizontalalignment, verticalalignment. """ if isinstance(state_or_vector, Qobj): vec = [expect(sigmax(), state_or_vector), expect(sigmay(), state_or_vector), expect(sigmaz(), state_or_vector)] elif isinstance(state_or_vector, (list, ndarray, tuple)) \ and len(state_or_vector) == 3: vec = state_or_vector else: raise Exception("Position needs to be specified by a qubit " + "state or a 3D vector.") self.annotations.append({'position': vec, 'text': text, 'opts': kwargs})
def testExpandGate3toN_permutation(self): """ gates: expand 3 to 3 with permuTation (using toffoli) """ for _p in itertools.permutations([0, 1, 2]): controls, target = [_p[0], _p[1]], _p[2] controls = [1, 2] target = 0 p = [1, 2, 3] p[controls[0]] = 0 p[controls[1]] = 1 p[target] = 2 U = toffoli(N=3, controls=controls, target=target) ops = [basis(2, 0).dag(), basis(2, 0).dag(), identity(2)] P = tensor(ops[p[0]], ops[p[1]], ops[p[2]]) assert_(P * U * P.dag() == identity(2)) ops = [basis(2, 1).dag(), basis(2, 0).dag(), identity(2)] P = tensor(ops[p[0]], ops[p[1]], ops[p[2]]) assert_(P * U * P.dag() == identity(2)) ops = [basis(2, 0).dag(), basis(2, 1).dag(), identity(2)] P = tensor(ops[p[0]], ops[p[1]], ops[p[2]]) assert_(P * U * P.dag() == identity(2)) ops = [basis(2, 1).dag(), basis(2, 1).dag(), identity(2)] P = tensor(ops[p[0]], ops[p[1]], ops[p[2]]) assert_(P * U * P.dag() == sigmax())
def test_stinespring_dims(self): """ Stinespring: Check that dims of channels are preserved. """ # FIXME: not the most general test, since this assumes a map # from square matrices to square matrices on the same space. chan = super_tensor(to_super(sigmax()), to_super(qeye(3))) A, B = to_stinespring(chan) assert_equal(A.dims, [[2, 3, 1], [2, 3]]) assert_equal(B.dims, [[2, 3, 1], [2, 3]])
def case_is_clifford(self, U): paulis = (identity(2), sigmax(), sigmay(), sigmaz()) for P in paulis: U_P = U * P * U.dag() assert_(any( self._prop_identity(U_P * Q) for Q in paulis ))
def case_is_clifford(self, U): paulis = (identity(2), sigmax(), sigmay(), sigmaz()) for P in paulis: U_P = U * P * U.dag() out = (np.any( np.array([self._prop_identity(U_P * Q) for Q in paulis]) )) return out
def qubit_clifford_group(N=None, target=0): """ Generates the Clifford group on a single qubit, using the presentation of the group given by Ross and Selinger (http://www.mathstat.dal.ca/~selinger/newsynth/). Parameters ----------- N : int or None Number of qubits on which each operator is to be defined (default: 1). target : int Index of the target qubit on which the single-qubit Clifford operators are to act. Yields ------ op : Qobj Clifford operators, represented as Qobj instances. """ # The Ross-Selinger presentation of the single-qubit Clifford # group expresses each element in the form C_{ijk} = E^i X^j S^k # for gates E, X and S, and for i in range(3), j in range(2) and # k in range(4). # # We start by defining these gates. E is defined in terms of H, # \omega and S, so we define \omega and H first. w = np.exp(1j * 2 * np.pi / 8) H = snot() X = sigmax() S = phasegate(np.pi / 2) E = H * (S ** 3) * w ** 3 for op in map( # partial(reduce, mul) returns a function that takes products of its argument, # by analogy to sum. Note that by analogy, sum can be written partial(reduce, add). partial(reduce, mul), # product(...) yields the Cartesian product of its arguments. Here, each element is # a tuple (E**i, X**j, S**k) such that partial(reduce, mul) acting on the tuple # yields E**i * X**j * S**k. product(_powers(E, 3), _powers(X, 2), _powers(S, 4)) ): # Finally, we optionally expand the gate. if N is not None: yield gate_expand_1toN(op, N, target) else: yield op
def TestUserNoise(self): """ Test for the user-defined noise object """ dr_noise = DriftNoise(sigmax()) proc = Processor(1) proc.add_noise(dr_noise) proc.tlist = np.array([0, np.pi / 2.]) result = proc.run_state(rho0=basis(2, 0)) assert_allclose(fidelity(result.states[-1], basis(2, 1)), 1, rtol=1.0e-6)
def test_chi_known(self): """ Superoperator: Chi-matrix for known cases is correct. """ def case(S, chi_expected, silent=True): chi_actual = to_chi(S) chiq = Qobj(chi_expected, dims=[[[2], [2]], [[2], [2]]], superrep='chi') if not silent: print(chi_actual) print(chi_expected) assert_almost_equal((chi_actual - chiq).norm('tr'), 0) case(sigmax(), [[0, 0, 0, 0], [0, 4, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) case(to_super(sigmax()), [[0, 0, 0, 0], [0, 4, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) case(qeye(2), [[4, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) case((-1j * sigmax() * pi / 4).expm(), [[2, 2j, 0, 0], [-2j, 2, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]])
def add_states(self, state, kind="vector"): """Add a state vector Qobj to Bloch sphere. Parameters ---------- state : qobj Input state vector. kind : str {'vector','point'} Type of object to plot. """ if isinstance(state, Qobj): state = [state] for st in state: if kind == "vector": vec = [expect(sigmax(), st), expect(sigmay(), st), expect(sigmaz(), st)] self.add_vectors(vec) elif kind == "point": pnt = [expect(sigmax(), st), expect(sigmay(), st), expect(sigmaz(), st)] self.add_points(pnt)
def test_QobjHerm(): "Qobj Hermicity" N = 10 data = np.random.random( (N, N)) + 1j * np.random.random((N, N)) - (0.5 + 0.5j) q = Qobj(data) assert_equal(q.isherm, False) data = data + data.conj().T q = Qobj(data) assert_(q.isherm) q_a = destroy(5) assert_(not q_a.isherm) q_ad = create(5) assert_(not q_ad.isherm) # test addition of two nonhermitian operators adding up to a hermitian one q_x = q_a + q_ad assert_hermicity(q_x, True) # test addition of one hermitan and one nonhermitian operator q = q_x + q_a assert_hermicity(q, False) # test addition of two hermitan operators q = q_x + q_x assert_hermicity(q, True) # Test multiplication of two Hermitian operators. # This results in a skew-Hermitian operator, so # we're checking here that __mul__ doesn't set wrong # metadata. q = sigmax() * sigmay() assert_hermicity(q, False, "Expected iZ = X * Y to be skew-Hermitian.") # Similarly, we need to check that -Z = X * iY is correctly # identified as Hermitian. q = sigmax() * (1j * sigmay()) assert_hermicity(q, True, "Expected -Z = X * iY to be Hermitian.")
def TestDecoherenceNoise(self): """ Test for the decoherence noise """ tlist = np.array([1, 2, 3, 4, 5, 6]) coeffs = [np.array([1, 1, 1, 1, 1, 1])] # Time-dependent decnoise = DecoherenceNoise(sigmaz(), coeffs=coeffs, tlist=tlist, targets=[1]) noise_list = decnoise.get_noise(2) assert_allclose(noise_list[0].ops[0].qobj, tensor(qeye(2), sigmaz())) assert_allclose(noise_list[0].ops[0].coeff, coeffs[0]) assert_allclose(noise_list[0].tlist, tlist) # Time-indenpendent and all qubits decnoise = DecoherenceNoise(sigmax(), all_qubits=True) noise_list = decnoise.get_noise(2) assert_(tensor([qeye(2), sigmax()]) in noise_list) assert_(tensor([sigmax(), qeye(2)]) in noise_list) # Time-denpendent and all qubits decnoise = DecoherenceNoise(sigmax(), all_qubits=True, coeffs=coeffs * 2, tlist=tlist) noise_list = decnoise.get_noise(2) assert_allclose(noise_list[0].ops[0].qobj, tensor(sigmax(), qeye(2))) assert_allclose(noise_list[0].ops[0].coeff, coeffs[0]) assert_allclose(noise_list[0].tlist, tlist) assert_allclose(noise_list[1].ops[0].qobj, tensor(qeye(2), sigmax()))
def TestNoisyPulse(): """ Test for lindblad noise and different tlist """ coeff = np.array([0.1, 0.2, 0.3, 0.4]) tlist = np.array([0., 1., 2., 3.]) ham = sigmaz() pulse1 = Pulse(ham, 1, tlist, coeff) # Add coherent noise and lindblad noise with different tlist pulse1.spline_kind = "step_func" tlist_noise = np.array([1., 2.5, 3.]) coeff_noise = np.array([0.5, 0.1, 0.5]) pulse1.add_coherent_noise(sigmay(), 0, tlist_noise, coeff_noise) tlist_noise2 = np.array([0.5, 2, 3.]) coeff_noise2 = np.array([0.1, 0.2, 0.3]) pulse1.add_lindblad_noise(sigmax(), 1, coeff=True) pulse1.add_lindblad_noise( sigmax(), 0, tlist=tlist_noise2, coeff=coeff_noise2) assert_allclose( pulse1.get_ideal_qobjevo(2).ops[0].qobj, tensor(identity(2), sigmaz())) noise_qu, c_ops = pulse1.get_noisy_qobjevo(2) assert_allclose(noise_qu.tlist, np.array([0., 0.5, 1., 2., 2.5, 3.])) for ele in noise_qu.ops: if ele.qobj == tensor(identity(2), sigmaz()): assert_allclose( ele.coeff, np.array([0.1, 0.1, 0.2, 0.3, 0.3, 0.4])) elif ele.qobj == tensor(sigmay(), identity(2)): assert_allclose( ele.coeff, np.array([0., 0., 0.5, 0.5, 0.1, 0.5])) for c_op in c_ops: if len(c_op.ops) == 0: assert_allclose(c_ops[0].cte, tensor(identity(2), sigmax())) else: assert_allclose( c_ops[1].ops[0].qobj, tensor(sigmax(), identity(2))) assert_allclose( c_ops[1].tlist, np.array([0., 0.5, 1., 2., 2.5, 3.])) assert_allclose( c_ops[1].ops[0].coeff, np.array([0., 0.1, 0.1, 0.2, 0.2, 0.3]))
def qubit_clifford_group(N=None, target=0): """ Generates the Clifford group on a single qubit, using the presentation of the group given by Ross and Selinger (http://www.mathstat.dal.ca/~selinger/newsynth/). Parameters ----------- N : int or None Number of qubits on which each operator is to be defined (default: 1). target : int Index of the target qubit on which the single-qubit Clifford operators are to act. Yields ------ op : Qobj Clifford operators, represented as Qobj instances. """ # The Ross-Selinger presentation of the single-qubit Clifford # group expresses each element in the form C_{ijk} = E^i X^j S^k # for gates E, X and S, and for i in range(3), j in range(2) and # k in range(4). # # We start by defining these gates. E is defined in terms of H, # \omega and S, so we define \omega and H first. w = np.exp(1j * 2 * np.pi / 8) H = snot() X = sigmax() S = phasegate(np.pi / 2) E = H * (S**3) * w**3 for op in map( # partial(reduce, mul) returns a function that takes products of its argument, # by analogy to sum. Note that by analogy, sum can be written partial(reduce, add). partial(reduce, mul), # product(...) yields the Cartesian product of its arguments. Here, each element is # a tuple (E**i, X**j, S**k) such that partial(reduce, mul) acting on the tuple # yields E**i * X**j * S**k. product(_powers(E, 3), _powers(X, 2), _powers(S, 4))): # Finally, we optionally expand the gate. if N is not None: yield gate_expand_1toN(op, N, target) else: yield op
def TestChooseSolver(self): # setup and fidelity without noise init_state = qubit_states(2, [0, 0, 0, 0]) tlist = np.array([0., np.pi/2.]) a = destroy(2) proc = Processor(N=2) proc.add_control(sigmax(), targets=1) proc.pulses[0].tlist = tlist proc.pulses[0].coeff = np.array([1]) result = proc.run_state(init_state=init_state, solver="mcsolve") assert_allclose( fidelity(result.states[-1], qubit_states(2, [0, 1, 0, 0])), 1, rtol=1.e-7)
def testExpectSolverCompatibility(self): """ expect: operator list and state list """ c_ops = [0.0001 * sigmaz()] e_ops = [sigmax(), sigmay(), sigmaz(), sigmam(), sigmap()] times = np.linspace(0, 10, 100) res1 = mesolve(sigmax(), fock(2, 0), times, c_ops, e_ops) res2 = mesolve(sigmax(), fock(2, 0), times, c_ops, []) e1 = res1.expect e2 = expect(e_ops, res2.states) assert_(len(e1) == len(e2)) for n in range(len(e1)): assert_(len(e1[n]) == len(e2[n])) assert_(isinstance(e1[n], np.ndarray)) assert_(isinstance(e2[n], np.ndarray)) assert_(e1[n].dtype == e2[n].dtype) assert_(all(abs(e1[n] - e2[n]) < 1e-12))
def test_user_defined_noise(self): """ Test for the user-defined noise object """ dr_noise = DriftNoise(sigmax()) proc = Processor(1) proc.add_noise(dr_noise) tlist = np.array([0, np.pi / 2.]) proc.add_pulse(Pulse(identity(2), 0, tlist, False)) result = proc.run_state(init_state=basis(2, 0)) assert_allclose(fidelity(result.states[-1], basis(2, 1)), 1, rtol=1.0e-6)
def TestControlAmpNoise(self): """ Test for the control amplitude noise """ tlist = np.array([1, 2, 3, 4, 5, 6]) coeff = np.array([1, 1, 1, 1, 1, 1]) # use external operators and no expansion dummy_qobjevo = QobjEvo(sigmaz(), tlist=tlist) connoise = ControlAmpNoise(ops=sigmax(), coeffs=[coeff], tlist=tlist) noise = connoise.get_noise(N=1, proc_qobjevo=dummy_qobjevo) assert_allclose(noise.ops[0].qobj, sigmax()) assert_allclose(noise.tlist, tlist) assert_allclose(noise.ops[0].coeff, coeff) dummy_qobjevo = QobjEvo(tensor([sigmaz(), sigmaz()]), tlist=tlist) connoise = ControlAmpNoise(ops=[sigmay()], coeffs=[coeff], tlist=tlist, targets=1) noise = connoise.get_noise(N=2, proc_qobjevo=dummy_qobjevo) assert_allclose(noise.ops[0].qobj, tensor([qeye(2), sigmay()])) # use external operators with expansion dummy_qobjevo = QobjEvo(sigmaz(), tlist=tlist) connoise = ControlAmpNoise(ops=sigmaz(), coeffs=[coeff] * 2, tlist=tlist, cyclic_permutation=True) noise = connoise.get_noise(N=2, proc_qobjevo=dummy_qobjevo) assert_allclose(noise.ops[0].qobj, tensor([sigmaz(), qeye(2)])) assert_allclose(noise.ops[1].qobj, tensor([qeye(2), sigmaz()])) # use proc_qobjevo proc_qobjevo = QobjEvo([[sigmaz(), coeff]], tlist=tlist) connoise = ControlAmpNoise(coeffs=[coeff], tlist=tlist) noise = connoise.get_noise(N=2, proc_qobjevo=proc_qobjevo) assert_allclose(noise.ops[0].qobj, sigmaz()) assert_allclose(noise.ops[0].coeff, coeff[0])
def x_gate(N=None, target=0): """Pauli-X gate or sigmax operator. Returns ------- result : :class:`qutip.Qobj` Quantum object for operator describing a single-qubit rotation through pi radians around the x-axis. """ if N is not None: return gate_expand_1toN(x_gate(), N, target) return sigmax()
def set_up_ops(self, N): """ Generate the Hamiltonians for the spinchain model and save them in the attribute `ctrls`. Parameters ---------- N: int The number of qubits in the system. """ # sx_ops for m in range(N): self.pulses.append( Pulse(sigmax(), m, spline_kind=self.spline_kind)) # sz_ops for m in range(N): self.pulses.append( Pulse(sigmaz(), m, spline_kind=self.spline_kind)) # sxsy_ops operator = tensor([sigmax(), sigmax()]) + tensor([sigmay(), sigmay()]) for n in range(N - 1): self.pulses.append( Pulse(operator, [n, n+1], spline_kind=self.spline_kind))
def add_states(self, state, kind='vector'): """Add a state vector Qobj to Bloch sphere. Parameters ---------- state : qobj Input state vector. kind : str {'vector','point'} Type of object to plot. """ if isinstance(state, Qobj): state = [state] for st in state: if kind == 'vector': vec = [expect(sigmax(), st), expect(sigmay(), st), expect(sigmaz(), st)] self.add_vectors(vec) elif kind == 'point': pnt = [expect(sigmax(), st), expect(sigmay(), st), expect(sigmaz(), st)] self.add_points(pnt)
def TestNoise(self): """ Test for Processor with noise """ # setup and fidelity without noise rho0 = qubit_states(2, [0, 0, 0, 0]) tlist = np.array([0., np.pi / 2.]) a = destroy(2) proc = Processor(N=2) proc.tlist = tlist proc.coeffs = np.array([1]).reshape((1, 1)) proc.add_ctrl(sigmax(), targets=1) result = proc.run_state(rho0=rho0) assert_allclose(fidelity(result.states[-1], qubit_states(2, [0, 1, 0, 0])), 1, rtol=1.e-7) # decoherence noise dec_noise = DecoherenceNoise([0.25 * a], targets=1) proc.add_noise(dec_noise) result = proc.run_state(rho0=rho0) assert_allclose(fidelity(result.states[-1], qubit_states(2, [0, 1, 0, 0])), 0.981852, rtol=1.e-3) # white noise with internal/external operators proc.noise = [] white_noise = RandomNoise(loc=0.1, scale=0.1) proc.add_noise(white_noise) result = proc.run_state(rho0=rho0) proc.noise = [] white_noise = RandomNoise(loc=0.1, scale=0.1, ops=sigmax(), targets=1) proc.add_noise(white_noise) result = proc.run_state(rho0=rho0)
def testPulseConstructor(self): """ Test for creating empty Pulse, Pulse with constant coefficients etc. """ coeff = np.array([0.1, 0.2, 0.3, 0.4]) tlist = np.array([0., 1., 2., 3.]) ham = sigmaz() # Special ways of initializing pulse pulse2 = Pulse(sigmax(), 0, tlist, True) assert_allclose( pulse2.get_ideal_qobjevo(2).ops[0].qobj, tensor(sigmax(), identity(2))) pulse3 = Pulse(sigmay(), 0) assert_allclose(pulse3.get_ideal_qobjevo(2).cte.norm(), 0.) pulse4 = Pulse(None, None) # Dummy empty ham assert_allclose(pulse4.get_ideal_qobjevo(2).cte.norm(), 0.) tlist_noise = np.array([1., 2.5, 3.]) coeff_noise = np.array([0.5, 0.1, 0.5]) tlist_noise2 = np.array([0.5, 2, 3.]) coeff_noise2 = np.array([0.1, 0.2, 0.3]) # Pulse with different dims random_qobj = Qobj(np.random.random((3, 3))) pulse5 = Pulse(sigmaz(), 1, tlist, True) pulse5.add_coherent_noise(sigmay(), 1, tlist_noise, coeff_noise) pulse5.add_lindblad_noise(random_qobj, 0, tlist=tlist_noise2, coeff=coeff_noise2) qu, c_ops = pulse5.get_noisy_qobjevo(dims=[3, 2]) assert_allclose(qu.ops[0].qobj, tensor([identity(3), sigmaz()])) assert_allclose(qu.ops[1].qobj, tensor([identity(3), sigmay()])) assert_allclose(c_ops[0].ops[0].qobj, tensor([random_qobj, identity(2)]))
def test_chi_known(self): """ Superoperator: Chi-matrix for known cases is correct. """ def case(S, chi_expected, silent=True): chi_actual = to_chi(S) chiq = Qobj(chi_expected, dims=[[[2], [2]], [[2], [2]]], superrep='chi') if not silent: print(chi_actual) print(chi_expected) assert_almost_equal((chi_actual - chiq).norm('tr'), 0) yield case, sigmax(), [ [0, 0, 0, 0], [0, 4, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0] ] yield case, to_super(sigmax()), [ [0, 0, 0, 0], [0, 4, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0] ] yield case, qeye(2), [ [4, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0] ] yield case, (-1j * sigmax() * pi / 4).expm(), [ [2, 2j, 0, 0], [-2j, 2, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0] ]
def _spin_hamiltonian(N): from qutip.tensor import tensor from qutip.operators import qeye, sigmax, sigmay, sigmaz # array of spin energy splittings and coupling strengths. here we use # uniform parameters, but in general we don't have too h = 1.0 * 2 * np.pi * np.ones(N) Jz = 0.1 * 2 * np.pi * np.ones(N) Jx = 0.1 * 2 * np.pi * np.ones(N) Jy = 0.1 * 2 * np.pi * np.ones(N) # dephasing rate gamma = 0.01 * np.ones(N) si = qeye(2) sx = sigmax() sy = sigmay() sz = sigmaz() sx_list = [] sy_list = [] sz_list = [] for n in range(N): op_list = [] for m in range(N): op_list.append(si) op_list[n] = sx sx_list.append(tensor(op_list)) op_list[n] = sy sy_list.append(tensor(op_list)) op_list[n] = sz sz_list.append(tensor(op_list)) # construct the hamiltonian H = 0 # energy splitting terms for n in range(N): H += - 0.5 * h[n] * sz_list[n] # interaction terms for n in range(N-1): H += - 0.5 * Jx[n] * sx_list[n] * sx_list[n+1] H += - 0.5 * Jy[n] * sy_list[n] * sy_list[n+1] H += - 0.5 * Jz[n] * sz_list[n] * sz_list[n+1] return H
def _spin_hamiltonian(N): from qutip.tensor import tensor from qutip.operators import qeye, sigmax, sigmay, sigmaz # array of spin energy splittings and coupling strengths. here we use # uniform parameters, but in general we don't have too h = 1.0 * 2 * np.pi * np.ones(N) Jz = 0.1 * 2 * np.pi * np.ones(N) Jx = 0.1 * 2 * np.pi * np.ones(N) Jy = 0.1 * 2 * np.pi * np.ones(N) # dephasing rate gamma = 0.01 * np.ones(N) si = qeye(2) sx = sigmax() sy = sigmay() sz = sigmaz() sx_list = [] sy_list = [] sz_list = [] for n in range(N): op_list = [] for m in range(N): op_list.append(si) op_list[n] = sx sx_list.append(tensor(op_list)) op_list[n] = sy sy_list.append(tensor(op_list)) op_list[n] = sz sz_list.append(tensor(op_list)) # construct the hamiltonian H = 0 # energy splitting terms for n in range(N): H += -0.5 * h[n] * sz_list[n] # interaction terms for n in range(N - 1): H += -0.5 * Jx[n] * sx_list[n] * sx_list[n + 1] H += -0.5 * Jy[n] * sy_list[n] * sy_list[n + 1] H += -0.5 * Jz[n] * sz_list[n] * sz_list[n + 1] return H
def test_heom(): """ heom: Tests the HEOM method. """ Q = sigmax() wq = 1.0 lam, gamma, w0 = 0.2, 0.05, 1.0 tlist = np.linspace(0, 200, 1000) Nc = 9 # zero temperature case beta = np.inf Hsys = 0.5 * wq * sigmaz() initial_ket = basis(2, 1) rho0 = initial_ket * initial_ket.dag() omega = np.sqrt(w0 ** 2 - (gamma / 2.0) ** 2) a = omega + 1j * gamma / 2.0 lam_coeff = lam ** 2 / (2 * (omega)) options = Options(nsteps=1500, store_states=True, atol=1e-12, rtol=1e-12) ck1, vk1 = nonmatsubara_exponents(lam, gamma, w0, beta) mats_data_zero = matsubara_zero_analytical(lam, gamma, w0, tlist) ck20, vk20 = biexp_fit(tlist, mats_data_zero) hsolver = HeomUB( Hsys, Q, lam_coeff, np.concatenate([ck1, ck20]), np.concatenate([-vk1, -vk20]), ncut=Nc, ) output = hsolver.solve(rho0, tlist) result = np.real(expect(output.states, sigmaz())) # Ignore Matsubara hsolver2 = HeomUB(Hsys, Q, lam_coeff, ck1, -vk1, ncut=Nc) output2 = hsolver2.solve(rho0, tlist) result2 = np.real(expect(output2.states, sigmaz())) steady_state_error = np.abs(result[-1] - result2[-1]) assert_(steady_state_error > 0.0)
def test_QobjUnitaryOper(): "Qobj unitarity" # Check some standard operators Sx = sigmax() Sy = sigmay() assert_unitarity(qeye(4), True) assert_unitarity(Sx, True) assert_unitarity(Sy, True) assert_unitarity(sigmam(), False) assert_unitarity(destroy(10), False) # Check multiplcation of unitary is unitary assert_unitarity(Sx * Sy, True) # Check some other operations clear unitarity assert_unitarity(Sx + Sy, False) assert_unitarity(4 * Sx, False) assert_unitarity(Sx * 4, False) assert_unitarity(4 + Sx, False) assert_unitarity(Sx + 4, False)
def __init__(self, N, correct_global_phase=True, sx=None, sz=None, sxsy=None): super(CircularSpinChain, self).__init__(N, correct_global_phase, sx, sz, sxsy) x = [identity(2)] * N x[0] = x[N - 1] = sigmax() y = [identity(2)] * N y[0] = y[N - 1] = sigmay() self.sxsy_ops.append(tensor(x) + tensor(y)) if sxsy is None: self.sxsy_coeff = [0.1 * 2 * np.pi] * N elif not isinstance(sxsy, list): self.sxsy_coeff = [sxsy * 2 * np.pi] * N else: self.sxsy_coeff = sxsy
def test_QobjUnitaryOper(): "Qobj unitarity" # Check some standard operators Sx = sigmax() Sy = sigmay() assert_unitarity(qeye(4), True, "qeye(4) should be unitary.") assert_unitarity(Sx, True, "sigmax() should be unitary.") assert_unitarity(Sy, True, "sigmax() should be unitary.") assert_unitarity(sigmam(), False, "sigmam() should NOT be unitary.") assert_unitarity(destroy(10), False, "destroy(10) should NOT be unitary.") # Check multiplcation of unitary is unitary assert_unitarity(Sx*Sy, True, "sigmax()*sigmay() should be unitary.") # Check some other operations clear unitarity assert_unitarity(Sx+Sy, False, "sigmax()+sigmay() should NOT be unitary.") assert_unitarity(4*Sx, False, "4*sigmax() should NOT be unitary.") assert_unitarity(Sx*4, False, "sigmax()*4 should NOT be unitary.") assert_unitarity(4+Sx, False, "4+sigmax() should NOT be unitary.") assert_unitarity(Sx+4, False, "sigmax()+4 should NOT be unitary.")
def test_dnorm_qubit_simple_known_cases(self): """ Metrics: check agreement for known qubit channels. """ id_chan = to_choi(qeye(2)) X_chan = to_choi(sigmax()) depol = to_choi( Qobj(diag(ones((4, ))), dims=[[[2], [2]], [[2], [2]]], superrep='chi')) # We need to restrict the number of iterations for things on the # boundary, such as perfectly distinguishable channels. assert 2 == pytest.approx(dnorm(id_chan, X_chan), abs=1e-7) assert 1.5 == pytest.approx(dnorm(id_chan, depol), abs=1e-7) # Finally, we add a known case from Johnston's QETLAB documentation, # || Phi - I ||_♢, # where Phi(X) = UXU⁺ and U = [[1, 1], [-1, 1]] / sqrt(2). assert np.sqrt(2) == pytest.approx( dnorm(Qobj([[1, 1], [-1, 1]]) / np.sqrt(2), qeye(2)))
def dict_to_qutip(dictH): """ Converts ising H to QuTip Hz and makes QuTip Hx of D-Wave in the process to avoid redundant function calls. """ # make useful operators X = qto.sigmax() Z = qto.sigmaz() nqbits = len([key for key in dictH.keys() if key[0] == key[1]]) Hx = sum([nqubit_1pauli(X, m, nqbits) for m in range(nqbits)]) zeros = [qto.qzero(2) for m in range(nqbits)] Hz = qt.tensor(*zeros) for key, value in dictH.items(): if key[0] == key[1]: Hz += value*nqubit_1pauli(Z, key[0], nqbits) else: Hz += value*nqubit_2pauli(Z, Z, key[0], key[1], nqbits) return [Hz, Hx]
def testOperatorListStateList(self): """ expect: operator list and state list """ operators = [sigmax(), sigmay(), sigmaz(), sigmam(), sigmap()] states = [fock(2, 0), fock(2, 1), fock_dm(2, 0), fock_dm(2, 1)] res = expect(operators, states) assert_(len(res) == len(operators)) for r_idx, r in enumerate(res): assert_(isinstance(r, np.ndarray)) if operators[r_idx].isherm: assert_(r.dtype == np.float64) else: assert_(r.dtype == np.complex128) for s_idx, s in enumerate(states): assert_(r[s_idx] == expect(operators[r_idx], states[s_idx]))
def add_annotation(self, state_or_vector, text, **kwargs): """ Add a text or LaTeX annotation to Bloch sphere, parametrized by a qubit state or a vector. Parameters ---------- state_or_vector : Qobj/array/list/tuple Position for the annotaion. Qobj of a qubit or a vector of 3 elements. text : str Annotation text. You can use LaTeX, but remember to use raw string e.g. r"$\\langle x \\rangle$" or escape backslashes e.g. "$\\\\langle x \\\\rangle$". kwargs : Options as for mplot3d.axes3d.text, including: fontsize, color, horizontalalignment, verticalalignment. """ if isinstance(state_or_vector, Qobj): vec = [ expect(sigmax(), state_or_vector), expect(sigmay(), state_or_vector), expect(sigmaz(), state_or_vector) ] elif isinstance(state_or_vector, (list, ndarray, tuple)) \ and len(state_or_vector) == 3: vec = state_or_vector else: raise Exception("Position needs to be specified by a qubit " + "state or a 3D vector.") self.annotations.append({ 'position': vec, 'text': text, 'opts': kwargs })
def test_multi_gates(self): N = 2 H_d = tensor([sigmaz()] * 2) H_c = [] test = OptPulseProcessor(N) test.add_drift(H_d, [0, 1]) test.add_control(sigmax(), cyclic_permutation=True) test.add_control(sigmay(), cyclic_permutation=True) test.add_control(tensor([sigmay(), sigmay()])) # qubits circuit with 3 gates setting_args = { "SNOT": { "num_tslots": 10, "evo_time": 1 }, "SWAP": { "num_tslots": 30, "evo_time": 3 }, "CNOT": { "num_tslots": 30, "evo_time": 3 } } qc = QubitCircuit(N) qc.add_gate("SNOT", 0) qc.add_gate("SWAP", targets=[0, 1]) qc.add_gate('CNOT', controls=1, targets=[0]) test.load_circuit(qc, setting_args=setting_args, merge_gates=False) rho0 = rand_ket(4) # use random generated ket state rho0.dims = [[2, 2], [1, 1]] U = gate_sequence_product(qc.propagators()) rho1 = U * rho0 result = test.run_state(rho0) assert_(fidelity(result.states[-1], rho1) > 1 - 1.0e-6)
def set_up_ops(self, N): """ Generate the Hamiltonians for the spinchain model and save them in the attribute `ctrls`. Parameters ---------- N: int The number of qubits in the system. """ self.pulse_dict = {} index = 0 # single qubit terms for m in range(N): self.pulses.append( Pulse(sigmax(), [m + 1], spline_kind=self.spline_kind)) self.pulse_dict["sx" + str(m)] = index index += 1 for m in range(N): self.pulses.append( Pulse(sigmaz(), [m + 1], spline_kind=self.spline_kind)) self.pulse_dict["sz" + str(m)] = index index += 1 # coupling terms a = tensor([destroy(self.num_levels)] + [identity(2) for n in range(N)]) for n in range(N): sm = tensor( [identity(self.num_levels)] + [destroy(2) if m == n else identity(2) for m in range(N)]) self.pulses.append( Pulse(a.dag() * sm + a * sm.dag(), list(range(N + 1)), spline_kind=self.spline_kind)) self.pulse_dict["g" + str(n)] = index index += 1
def test_decoherence_noise(self): """ Test for the decoherence noise """ tlist = np.array([1, 2, 3, 4, 5, 6]) coeff = np.array([1, 1, 1, 1, 1, 1]) # Time-dependent decnoise = DecoherenceNoise(sigmaz(), coeff=coeff, tlist=tlist, targets=[1]) dims = [2] * 2 pulses, systematic_noise = decnoise.get_noisy_dynamics(dims=dims) noisy_qu, c_ops = systematic_noise.get_noisy_qobjevo(dims=dims) assert_allclose(c_ops[0].ops[0].qobj, tensor(qeye(2), sigmaz())) assert_allclose(c_ops[0].ops[0].coeff, coeff) assert_allclose(c_ops[0].tlist, tlist) # Time-indenpendent and all qubits decnoise = DecoherenceNoise(sigmax(), all_qubits=True) pulses, systematic_noise = decnoise.get_noisy_dynamics(dims=dims) noisy_qu, c_ops = systematic_noise.get_noisy_qobjevo(dims=dims) c_ops = [qu.cte for qu in c_ops] assert_(tensor([qeye(2), sigmax()]) in c_ops) assert_(tensor([sigmax(), qeye(2)]) in c_ops) # Time-denpendent and all qubits decnoise = DecoherenceNoise(sigmax(), all_qubits=True, coeff=coeff * 2, tlist=tlist) pulses, systematic_noise = decnoise.get_noisy_dynamics(dims=dims) noisy_qu, c_ops = systematic_noise.get_noisy_qobjevo(dims=dims) assert_allclose(c_ops[0].ops[0].qobj, tensor(sigmax(), qeye(2))) assert_allclose(c_ops[0].ops[0].coeff, coeff * 2) assert_allclose(c_ops[0].tlist, tlist) assert_allclose(c_ops[1].ops[0].qobj, tensor(qeye(2), sigmax()))
def test_dnorm_qubit_known_cases(): """ Metrics: check agreement for known qubit channels. """ def case(chan1, chan2, expected, significant=4): # We again take a generous tolerance so that we don't kill off # SCS solvers. assert_approx_equal( dnorm(chan1, chan2), expected, significant=significant ) id_chan = to_choi(qeye(2)) S_eye = to_super(id_chan) X_chan = to_choi(sigmax()) depol = to_choi(Qobj( diag(ones((4,))), dims=[[[2], [2]], [[2], [2]]], superrep='chi' )) S_H = to_super(hadamard_transform()) W = swap() # We need to restrict the number of iterations for things on the boundary, # such as perfectly distinguishable channels. yield case, id_chan, X_chan, 2 yield case, id_chan, depol, 1.5 # Next, we'll generate some test cases based on comparisons to pre-existing # dnorm() implementations. In particular, the targets for the following # test cases were generated using QuantumUtils for MATLAB (https://goo.gl/oWXhO9). def overrotation(x): return to_super((1j * np.pi * x * sigmax() / 2).expm()) for x, target in { 1.000000e-03: 3.141591e-03, 3.100000e-03: 9.738899e-03, 1.000000e-02: 3.141463e-02, 3.100000e-02: 9.735089e-02, 1.000000e-01: 3.128689e-01, 3.100000e-01: 9.358596e-01 }.items(): yield case, overrotation(x), id_chan, target def had_mixture(x): return (1 - x) * S_eye + x * S_H for x, target in { 1.000000e-03: 2.000000e-03, 3.100000e-03: 6.200000e-03, 1.000000e-02: 2.000000e-02, 3.100000e-02: 6.200000e-02, 1.000000e-01: 2.000000e-01, 3.100000e-01: 6.200000e-01 }.items(): yield case, had_mixture(x), id_chan, target def swap_map(x): S = (1j * x * W).expm() S._type = None S.dims = [[[2], [2]], [[2], [2]]] S.superrep = 'super' return S for x, target in { 1.000000e-03: 2.000000e-03, 3.100000e-03: 6.199997e-03, 1.000000e-02: 1.999992e-02, 3.100000e-02: 6.199752e-02, 1.000000e-01: 1.999162e-01, 3.100000e-01: 6.173918e-01 }.items(): yield case, swap_map(x), id_chan, target # Finally, we add a known case from Johnston's QETLAB documentation, # || Phi - I ||,_♢ where Phi(X) = UXU⁺ and U = [[1, 1], [-1, 1]] / sqrt(2). yield case, Qobj([[1, 1], [-1, 1]]) / np.sqrt(2), qeye(2), np.sqrt(2)
CPTP, expand to arbitrary dimensional systems, etc. """ return Qobj(dims=[[[2], [2]], [[2], [2]]], inpt=array([[1. - pe / 2., 0., 0., 1. - pe], [0., pe / 2., 0., 0.], [0., 0., pe / 2., 0.], [1. - pe, 0., 0., 1. - pe / 2.]]), superrep='choi') # CHANGE OF BASIS FUNCTIONS --------------------------------------------------- # These functions find change of basis matrices, and are useful in converting # between (for instance) Choi and chi matrices. At some point, these should # probably be moved out to another module. _SINGLE_QUBIT_PAULI_BASIS = (identity(2), sigmax(), sigmay(), sigmaz()) def _pauli_basis(nq=1): # NOTE: This is slow as can be. # TODO: Make this sparse. CSR format was causing problems for the [idx, :] # slicing below. B = zeros((4 ** nq, 4 ** nq), dtype=complex) dims = [[[2] * nq] * 2] * 2 for idx, op in enumerate(starmap(tensor, product(_SINGLE_QUBIT_PAULI_BASIS, repeat=nq))): B[:, idx] = operator_to_vector(op).dag().data.todense() return Qobj(B, dims=dims)
TODO: if this is going into production (hopefully it isn't) then check CPTP, expand to arbitrary dimensional systems, etc. """ return Qobj(dims=[[[2], [2]], [[2], [2]]], inpt=array([[1. - pe / 2., 0., 0., 1. - pe], [0., pe / 2., 0., 0.], [0., 0., pe / 2., 0.], [1. - pe, 0., 0., 1. - pe / 2.]]), superrep='choi') # CHANGE OF BASIS FUNCTIONS --------------------------------------------------- # These functions find change of basis matrices, and are useful in converting # between (for instance) Choi and chi matrices. At some point, these should # probably be moved out to another module. _SINGLE_QUBIT_PAULI_BASIS = (identity(2), sigmax(), sigmay(), sigmaz()) def _pauli_basis(nq=1): # NOTE: This is slow as can be. # TODO: Make this sparse. CSR format was causing problems for the [idx, :] # slicing below. B = zeros((4**nq, 4**nq), dtype=complex) dims = [[[2] * nq] * 2] * 2 for idx, op in enumerate( starmap(tensor, product(_SINGLE_QUBIT_PAULI_BASIS, repeat=nq))): B[:, idx] = operator_to_vector(op).dag().full() return Qobj(B, dims=dims)
def test_known_iscptp(self): """ Superoperator: ishp, iscp, istp and iscptp known cases. """ def case(qobj, shouldhp, shouldcp, shouldtp): hp = qobj.ishp cp = qobj.iscp tp = qobj.istp cptp = qobj.iscptp shouldcptp = shouldcp and shouldtp if ( hp == shouldhp and cp == shouldcp and tp == shouldtp and cptp == shouldcptp ): return fails = [] if hp != shouldhp: fails.append(("ishp", shouldhp, hp)) if tp != shouldtp: fails.append(("istp", shouldtp, tp)) if cp != shouldcp: fails.append(("iscp", shouldcp, cp)) if cptp != shouldcptp: fails.append(("iscptp", shouldcptp, cptp)) raise AssertionError("Expected {}.".format(" and ".join([ "{} == {} (got {})".format(fail, expected, got) for fail, expected, got in fails ]))) # Conjugation by a creation operator should # have be CP (and hence HP), but not TP. a = create(2).dag() S = sprepost(a, a.dag()) yield case, S, True, True, False # A single off-diagonal element should not be CP, # nor even HP. S = sprepost(a, a) yield case, S, False, False, False # Check that unitaries are CPTP and HP. yield case, identity(2), True, True, True yield case, sigmax(), True, True, True # The partial transpose map, whose Choi matrix is SWAP, is TP # and HP but not CP (one negative eigenvalue). W = Qobj(swap(), type='super', superrep='choi') yield case, W, True, False, True # Subnormalized maps (representing erasure channels, for instance) # can be CP but not TP. subnorm_map = Qobj(identity(4) * 0.9, type='super', superrep='super') yield case, subnorm_map, True, True, False # Check that things which aren't even operators aren't identified as # CPTP. yield case, basis(2), False, False, False
def overrotation(x): return to_super((1j * np.pi * x * sigmax() / 2).expm())
def set_up_ops(self, N): super(CircularSpinChain, self).set_up_ops(N) operator = tensor([sigmax(), sigmax()]) + tensor([sigmay(), sigmay()]) self.pulses.append( Pulse(operator, [N-1, 0], spline_kind=self.spline_kind)) self.pulse_dict["g" + str(N-1)] = len(self.pulses) - 1
def test_known_iscptp(self): """ Superoperator: ishp, iscp, istp and iscptp known cases. """ def case(qobj, shouldhp, shouldcp, shouldtp): hp = qobj.ishp cp = qobj.iscp tp = qobj.istp cptp = qobj.iscptp shouldcptp = shouldcp and shouldtp if (hp == shouldhp and cp == shouldcp and tp == shouldtp and cptp == shouldcptp): return fails = [] if hp != shouldhp: fails.append(("ishp", shouldhp, hp)) if tp != shouldtp: fails.append(("istp", shouldtp, tp)) if cp != shouldcp: fails.append(("iscp", shouldcp, cp)) if cptp != shouldcptp: fails.append(("iscptp", shouldcptp, cptp)) raise AssertionError("Expected {}.".format(" and ".join([ "{} == {} (got {})".format(fail, expected, got) for fail, expected, got in fails ]))) # Conjugation by a creation operator should # have be CP (and hence HP), but not TP. a = create(2).dag() S = sprepost(a, a.dag()) case(S, True, True, False) # A single off-diagonal element should not be CP, # nor even HP. S = sprepost(a, a) case(S, False, False, False) # Check that unitaries are CPTP and HP. case(identity(2), True, True, True) case(sigmax(), True, True, True) # Check that unitaries on bipartite systems are CPTP and HP. case(tensor(sigmax(), identity(2)), True, True, True) # Check that a linear combination of bipartitie unitaries is CPTP and HP. S = (to_super(tensor(sigmax(), identity(2))) + to_super(tensor(identity(2), sigmay()))) / 2 case(S, True, True, True) # The partial transpose map, whose Choi matrix is SWAP, is TP # and HP but not CP (one negative eigenvalue). W = Qobj(swap(), type='super', superrep='choi') case(W, True, False, True) # Subnormalized maps (representing erasure channels, for instance) # can be CP but not TP. subnorm_map = Qobj(identity(4) * 0.9, type='super', superrep='super') case(subnorm_map, True, True, False) # Check that things which aren't even operators aren't identified as # CPTP. case(basis(2), False, False, False)