def test_change_between_composites(self): a = Basis.cast('std', [4, 1]) b = Basis.cast('gm', [4, 1]) mxStd = np.identity(5) test = bt.change_basis(mxStd, a, b) self.assertEqual(test.shape, mxStd.shape) test2 = bt.change_basis(test, b, a) self.assertArraysAlmostEqual(test2, mxStd)
def jamiolkowski_iso_inv(choi_mx, choi_mx_basis='pp', op_mx_basis='pp'): """ Given a choi matrix, return the corresponding operation matrix. This function performs the inverse of :function:`jamiolkowski_iso`. Parameters ---------- choi_mx : numpy array the Choi matrix, normalized to have trace == 1, to compute operation matrix for. choi_mx_basis : Basis object The source and destination basis, respectively. Allowed values are Matrix-unit (std), Gell-Mann (gm), Pauli-product (pp), and Qutrit (qt) (or a custom basis object). op_mx_basis : Basis object The source and destination basis, respectively. Allowed values are Matrix-unit (std), Gell-Mann (gm), Pauli-product (pp), and Qutrit (qt) (or a custom basis object). Returns ------- numpy array operation matrix in the desired basis. """ choi_mx = _np.asarray(choi_mx) # will have "expanded" dimension even if bases are for reduced... N = choi_mx.shape[0] # dimension of full-basis (expanded) operation matrix if not isinstance(choi_mx_basis, _Basis): # if we're not given a basis, build choi_mx_basis = _Basis.cast(choi_mx_basis, N) # one with the full dimension dmDim = int(round(_np.sqrt(N))) # density matrix dimension #get full list of basis matrices (in std basis) BVec = _bt.basis_matrices(choi_mx_basis.create_simple_equivalent(), N) assert(len(BVec) == N) # make sure the number of basis matrices matches the dim of the choi matrix given # Invert normalization choiMx_unnorm = choi_mx * dmDim opMxInStdBasis = _np.zeros((N, N), 'complex') # in matrix unit basis of entire density matrix for i in range(N): for j in range(N): BiBj = _np.kron(BVec[i], _np.conjugate(BVec[j])) opMxInStdBasis += choiMx_unnorm[i, j] * BiBj if not isinstance(op_mx_basis, _Basis): op_mx_basis = _Basis.cast(op_mx_basis, N) # make sure op_mx_basis is a Basis; we'd like dimension to be N #project operation matrix so it acts only on the space given by the desired state space blocks opMxInStdBasis = _bt.resize_std_mx(opMxInStdBasis, 'contract', op_mx_basis.create_simple_equivalent('std'), op_mx_basis.create_equivalent('std')) #transform operation matrix into appropriate basis return _bt.change_basis(opMxInStdBasis, op_mx_basis.create_equivalent('std'), op_mx_basis)
def test_flexible_change_basis(self): comp = Basis.cast([( 'gm', 4, ), ('gm', 1)]) std = Basis.cast('std', 9) mx = np.identity(5) test = bt.flexible_change_basis(mx, comp, std) self.assertEqual(test.shape[0], comp.elsize) test2 = bt.flexible_change_basis(test, std, comp) self.assertArraysAlmostEqual(test2, mx)
def test_lind_errgens(self): bases = [Basis.cast('gm', 4), Basis.cast('pp', 4), Basis.cast('PP', 4)] for basis in bases: print(basis) Hblk = LindbladCoefficientBlock('ham', basis) Hblk_superops = Hblk.create_lindblad_term_superoperators( mx_basis='std') for i, mi in enumerate(basis[1:]): Hi = lt.create_elementary_errorgen('H', mi) HiB = lt.create_lindbladian_term_errorgen('H', mi) self.assertArraysAlmostEqual(Hi, HiB) self.assertArraysAlmostEqual(Hi, Hblk_superops[i]) ODblk = LindbladCoefficientBlock('other_diagonal', basis) ODblk_superops = ODblk.create_lindblad_term_superoperators( mx_basis='std') for i, mi in enumerate(basis[1:]): ODi = lt.create_elementary_errorgen('S', mi) ODiB = lt.create_lindbladian_term_errorgen('O', mi, mi) self.assertArraysAlmostEqual(ODi, ODiB) self.assertArraysAlmostEqual(ODi, ODblk_superops[i]) Oblk = LindbladCoefficientBlock('other', basis) Oblk_superops = Oblk.create_lindblad_term_superoperators( mx_basis='std') for i, mi in enumerate(basis[1:]): for j, mj in enumerate(basis[1:]): Oij = lt.create_lindbladian_term_errorgen('O', mi, mj) self.assertArraysAlmostEqual(Oij, Oblk_superops[i][j]) # C_PQ = NH_PQ + NH_QP # A_PQ = i(NH_PQ - NH_QP) if i < j: Cij = lt.create_elementary_errorgen('C', mi, mj) Aij = lt.create_elementary_errorgen('A', mi, mj) self.assertArraysAlmostEqual(Oij, (Cij + 1j * Aij) / 2.0) elif j < i: Cji = lt.create_elementary_errorgen('C', mj, mi) Aji = lt.create_elementary_errorgen('A', mj, mi) self.assertArraysAlmostEqual(Oij, (Cji - 1j * Aji) / 2.0) else: # i == j Sii = lt.create_elementary_errorgen('S', mi) self.assertArraysAlmostEqual(Oij, Sii)
def test_auto_expand(self): comp = Basis.cast([( 'std', 4, ), ('std', 1)]) std = Basis.cast('std', 9) mxStd = np.identity(5) test = bt.resize_std_mx(mxStd, 'expand', comp, std) # Intermediate test mxInter = np.identity(9) mxInter[2, 2] = mxInter[5, 5] = mxInter[6, 6] = mxInter[7, 7] = 0 self.assertArraysAlmostEqual(test, mxInter) test2 = bt.resize_std_mx(test, 'contract', std, comp) self.assertArraysAlmostEqual(test2, mxStd)
def test_complement_spamvec(self): model = pygsti.models.modelconstruction.create_explicit_model_from_expressions( [('Q0', )], ['Gi', 'Gx', 'Gy'], ["I(Q0)", "X(pi/8,Q0)", "Y(pi/8,Q0)"]) E0 = model.povms['Mdefault']['0'] E1 = model.povms['Mdefault']['1'] Ec = povms.ComplementPOVMEffect( modelconstruction.create_identity_vec(Basis.cast("pp", [4])), [E0]) print(Ec.gpindices) #Test TPPOVM which uses a complement evec model.povms['Mtest'] = povms.TPPOVM([('+', E0), ('-', E1)]) E0 = model.povms['Mtest']['+'] Ec = model.povms['Mtest']['-'] v = model.to_vector() model.from_vector(v) #print(Ec.num_params) #not implemented for complement vecs - only for POVM identity = np.array([[np.sqrt(2)], [0], [0], [0]], 'd') print("TEST1") print(E0) print(Ec) print(E0 + Ec) self.assertArraysAlmostEqual(E0 + Ec, identity)
def __init__(self, mx, basis, evotype, state_space): """ Initialize a new LinearOperator """ mx = _LinearOperator.convert_to_matrix(mx) state_space = _statespace.default_space_for_udim(mx.shape[0]) if (state_space is None) \ else _statespace.StateSpace.cast(state_space) basis = _Basis.cast( basis, state_space.dim) # basis for Hilbert-Schmidt (superop) space evotype = _Evotype.cast(evotype) #Try to create a dense unitary rep. If this fails, see if a dense superop rep # can be created, as this type of rep can also hold arbitrary unitary ops. try: rep = evotype.create_dense_unitary_rep(mx, basis, state_space) self._reptype = 'unitary' self._unitary = None except Exception: if mx.shape[0] == basis.dim and _np.linalg.norm(mx.imag) < 1e-10: # Special case when a *superop* was provided instead of a unitary mx superop_mx = mx.real # used as a convenience case that really shouldn't be used else: superop_mx = _ot.unitary_to_superop(mx, basis) rep = evotype.create_dense_superop_rep(superop_mx, state_space) self._reptype = 'superop' self._unitary = mx self._basis = basis _LinearOperator.__init__(self, rep, evotype) DenseOperatorInterface.__init__(self)
def __init__(self, vec, basis, truncate=False, evotype="default", state_space=None): vector = _State._to_vector(vec) basis = _Basis.cast(basis, len(vector)) self.basis = basis self.basis_mxs = basis.elements # shape (len(vec), dmDim, dmDim) self.basis_mxs = _np.rollaxis(self.basis_mxs, 0, 3) # shape (dmDim, dmDim, len(vec)) assert(self.basis_mxs.shape[-1] == len(vector)) # set self.params and self.dmDim self._set_params_from_vector(vector, truncate) #parameter labels (parameter encode the Cholesky Lmx) labels = [] for i, ilbl in enumerate(basis.labels[1:]): for j, jlbl in enumerate(basis.labels[1:]): if i == j: labels.append("%s diagonal element of density matrix Cholesky decomp" % ilbl) elif j < i: labels.append("Re[(%s,%s) element of density matrix Cholesky decomp]" % (ilbl, jlbl)) else: labels.append("Im[(%s,%s) element of density matrix Cholesky decomp]" % (ilbl, jlbl)) #scratch space self.Lmx = _np.zeros((self.dmDim, self.dmDim), 'complex') state_space = _statespace.default_space_for_dim(len(vector)) if (state_space is None) \ else _statespace.StateSpace.cast(state_space) evotype = _Evotype.cast(evotype) _DenseState.__init__(self, vector, evotype, state_space) self._paramlbls = _np.array(labels, dtype=object)
def __init__(self, purevec, basis, evotype, state_space): purevec = _State._to_vector(purevec) purevec = purevec.astype(complex) state_space = _statespace.default_space_for_udim(purevec.shape[0]) if (state_space is None) \ else _statespace.StateSpace.cast(state_space) evotype = _Evotype.cast(evotype) basis = _Basis.cast( basis, state_space.dim) # basis for Hilbert-Schmidt (superop) space #Try to create a dense pure rep. If this fails, see if a dense superkey rep # can be created, as this type of rep can also hold arbitrary pure states. try: rep = evotype.create_pure_state_rep(purevec, basis, state_space) self._reptype = 'pure' self._purevec = self._basis = None except Exception: if len(purevec) == basis.dim and _np.linalg.norm( purevec.imag) < 1e-10: # Special case when a *superket* was provided instead of a purevec superket_vec = purevec.real # used as a convenience case that really shouldn't be used else: superket_vec = _bt.change_basis(_ot.state_to_dmvec(purevec), 'std', basis) rep = evotype.create_dense_state_rep(superket_vec, state_space) self._reptype = 'superket' self._purevec = purevec self._basis = basis _State.__init__(self, rep, evotype) DenseStateInterface.__init__(self)
def __init__(self, state_space, basis="PP", evotype="default", initial_rates=None, seed_or_state=None): state_space = _statespace.StateSpace.cast(state_space) self.basis = _Basis.cast(basis, state_space.dim, sparse=False) assert ( state_space.dim == self.basis.dim ), "Dimension of `basis` must match the dimension (`dim`) of this op." evotype = _Evotype.cast(evotype) #Setup initial parameters self.params = _np.zeros( self.basis.size - 1, 'd') # note that basis.dim can be < self.dim (OK) if initial_rates is not None: assert(len(initial_rates) == self.basis.size - 1), \ "Expected %d initial rates but got %d!" % (self.basis.size - 1, len(initial_rates)) self.params[:] = self._rates_to_params(initial_rates) rates = _np.array(initial_rates) else: rates = _np.zeros(len(self.params), 'd') rep = evotype.create_stochastic_rep(self.basis, self._get_rate_poly_dicts(), rates, seed_or_state, state_space) _LinearOperator.__init__(self, rep, evotype) self._update_rep() # initialize self._rep self._paramlbls = _np.array( ['sqrt(%s error rate)' % bl for bl in self.basis.labels[1:]], dtype=object)
def from_basis_coefficients(cls, parameterization, lindblad_basis, state_space, ham_coefficients=None, nonham_coefficients=None): """ Create a :class:`LindbladNoise` object containing a complete basis of elementary terms. This method provides a convenient way to create a lindblad noise specification containing the complete set of terms in a Lindbladian based on a given "Lindblad basis" (often just a Pauli product basis). This routine by default creates all the terms with zero coefficients, but coefficient vectors or matrices (usually obtained by projecting an arbitrary error generator onto the lindblad basis) can be specified via the `ham_coefficients` and `nonham_coefficients` arguments. Parameters ---------- parameterization : str or LindbladParameterization The Lindblad parameterization, specifying what constitutes the "complete" set of Lindblad terms. For example, `"H"` means that just Hamiltonian terms are included whereas `"CPTP"` includes all the terms in a standard Lindblad decomposition. lindblad_basis : str or Basis The basis used to construct the Lindblad terms. state_space : StateSpace The state space, used only to convert string-valued `lindblad_basis` names into a :class:`Basis` object. If `lindblad_basis` is given as a :class:`Basis`, then this can be set to `None`. ham_coefficients : numpy.ndarray or None, optional A 1-dimensional array of coefficients giving the initial values of the Hamiltonian-term coefficients. The length of this arrays should be one less than the size of `lindblad_basis` (since there's no Lindblad term for the identity element). nonham_coefficients : numpy.ndarray or None, optional A 1- or 2-dimensional array of coefficients for the "other" (non-Hamiltonian) terms. The shape of this array should be `(d,)`, `(2,d)`, or `(d,d)` depending on `parameterization` (e.g. for S, S+A, and CPTP parameterizations). Returns ------- LindbladNoise """ lindblad_basis = _Basis.cast(lindblad_basis, state_space) parameterization = _op.LindbladParameterization.cast(parameterization) assert(len(parameterization.block_types) <= 2 and len(parameterization.block_types) == len(set(parameterization.block_types))), \ "Parameterization must have distinct block types and at most 2!" # coeffs + bases => elementary errorgen dict elementary_errorgens = {} for blk_type, blk_param in zip(parameterization.block_types, parameterization.param_modes): initial_data = ham_coefficients if blk_type == 'ham' else nonham_coefficients blk = _LindbladCoefficientBlock(blk_type, lindblad_basis, initial_block_data=initial_data) elementary_errorgens.update(blk.elementary_errorgens) return cls(elementary_errorgens, parameterization)
def __init__(self, zvals, basis='pp', evotype="default", state_space=None): zvals = _np.ascontiguousarray(_np.array(zvals, _np.int64)) state_space = _statespace.default_space_for_num_qubits(len(zvals)) if (state_space is None) \ else _statespace.StateSpace.cast(state_space) basis = _Basis.cast( basis, state_space.dim) # basis for Hilbert-Schmidt (superop) space evotype = _Evotype.cast(evotype) self._evotype = evotype # set this before call to _State.__init__ so self.to_dense() can work... rep = evotype.create_computational_effect_rep(zvals, basis, state_space) _POVMEffect.__init__(self, rep, evotype)
def test_expand_contract(self): # matrix that operates on 2x2 density matrices, but only on the 0-th and 3-rd # elements which correspond to the diagonals of the 2x2 density matrix. mxInStdBasis = np.array( [[1, 0, 0, 2], [0, 0, 0, 0], [0, 0, 0, 0], [3, 0, 0, 4]], 'd') # Reduce to a matrix operating on a density matrix space with 2 1x1 blocks (hence [1,1]) begin = Basis.cast('std', [1, 1]) end = Basis.cast('std', 4) mxInReducedBasis = bt.resize_std_mx(mxInStdBasis, 'contract', end, begin) #mxInReducedBasis = bt.change_basis(mxInStdBasis, begin, end) notReallyContracted = bt.change_basis(mxInStdBasis, 'std', 'std') # 4 correctAnswer = np.array([[1.0, 2.0], [3.0, 4.0]]) self.assertArraysAlmostEqual(mxInReducedBasis, correctAnswer) self.assertArraysAlmostEqual(notReallyContracted, mxInStdBasis) expandedMx = bt.resize_std_mx(mxInReducedBasis, 'expand', begin, end) #expandedMx = bt.change_basis(mxInReducedBasis, end, begin) expandedMxAgain = bt.change_basis(expandedMx, 'std', 'std') # , 4) self.assertArraysAlmostEqual(expandedMx, mxInStdBasis) self.assertArraysAlmostEqual(expandedMxAgain, mxInStdBasis)
def test_sparse_lindblad_bases(self): sparsePP = Basis.cast("pp", 16, sparse=True) mxs = sparsePP.elements #for lbl, mx in zip(sparsePP.labels, mxs): # print("{}: {} matrix with {} nonzero entries (of {} total)".format( # lbl, mx.shape, mx.nnz, mx.shape[0] * mx.shape[1] # )) # print(mx.toarray()) #print("{} basis elements".format(len(sparsePP))) self.assertEqual(len(sparsePP), 16) densePP = Basis.cast("pp", 16, sparse=False) for smx, dmx in zip(sparsePP.elements, densePP.elements): self.assertArraysAlmostEqual(smx.toarray(), dmx) M = np.ones((16, 16), 'd') v = np.ones(16, 'd') S = scipy.sparse.identity(16, 'd', 'csr') #print("Test types after basis change by sparse basis:") Mout = bt.change_basis(M, sparsePP, 'std') vout = bt.change_basis(v, sparsePP, 'std') Sout = bt.change_basis(S, sparsePP, 'std') #print("{} -> {}".format(type(M), type(Mout))) #print("{} -> {}".format(type(v), type(vout))) #print("{} -> {}".format(type(S), type(Sout))) self.assertIsInstance(Mout, np.ndarray) self.assertIsInstance(vout, np.ndarray) self.assertIsInstance(Sout, scipy.sparse.csr_matrix) Mdout = bt.change_basis(M, densePP, 'std') vdout = bt.change_basis(v, densePP, 'std') Sdout = bt.change_basis(S, densePP, 'std') self.assertIsInstance(Sdout, np.ndarray) self.assertArraysAlmostEqual(Mout, Mdout) self.assertArraysAlmostEqual(vout, vdout) self.assertArraysAlmostEqual(Sout, Sdout)
def __init__(self, state_space, target_labels, errgen_to_embed): _EmbeddedOp.__init__(self, state_space, target_labels, errgen_to_embed) # set "API" error-generator members (to interface properly w/other objects) # FUTURE: create a base class that defines this interface (maybe w/properties?) #self.sparse = True # Embedded error generators are *always* sparse (pointless to # # have dense versions of these) embedded_matrix_basis = errgen_to_embed.matrix_basis if isinstance(embedded_matrix_basis, str): self.matrix_basis = embedded_matrix_basis else: # assume a Basis object my_basis_dim = self.state_space.dim self.matrix_basis = _Basis.cast(embedded_matrix_basis.name, my_basis_dim, sparse=True)
def __init__(self, state_space, basis="PP", evotype="default", initial_rate=0, seed_or_state=None): #TODO - need to fix CHP basis dimension issue (dim ~= statevec but acts as density mx) #if evotype == 'chp': # assert (basis == 'pp'), "Only Pauli basis is allowed for 'chp' evotype" # # For chp (and statevec, etc), want full superoperator basis # basis = _Basis.cast(basis, 2**dim, sparse=False) #else: state_space = _statespace.StateSpace.cast(state_space) self.basis = _Basis.cast(basis, state_space.dim, sparse=False) num_rates = self.basis.size - 1 initial_sto_rates = [initial_rate / num_rates] * num_rates _StochasticNoiseOp.__init__(self, state_space, self.basis, evotype, initial_sto_rates, seed_or_state) # For DepolarizeOp, set params to only first element self.params = _np.array([self.params[0]]) self._paramlbls = _np.array(["common stochastic error rate for depolarization"], dtype=object)
def test_general(self): std = Basis.cast('std', 4) std4 = Basis.cast('std', 16) std2x2 = Basis.cast([('std', 4), ('std', 4)]) gm = Basis.cast('gm', 4) from_basis, to_basis = bt.create_basis_pair(np.identity(4, 'd'), "std", "gm") from_basis, to_basis = bt.create_basis_pair(np.identity(4, 'd'), std, "gm") from_basis, to_basis = bt.create_basis_pair(np.identity(4, 'd'), "std", gm) mx = np.array([[1, 0, 0, 1], [0, 1, 2, 0], [0, 2, 1, 0], [1, 0, 0, 1]]) bt.change_basis(mx, 'std', 'gm') # shortname lookup bt.change_basis(mx, std, gm) # object bt.change_basis(mx, std, 'gm') # combination bt.flexible_change_basis(mx, std, gm) # same dimension I2x2 = np.identity(8, 'd') I4 = bt.flexible_change_basis(I2x2, std2x2, std4) self.assertArraysAlmostEqual( bt.flexible_change_basis(I4, std4, std2x2), I2x2) with self.assertRaises(AssertionError): bt.change_basis(mx, std, std4) # basis size mismatch mxInStdBasis = np.array( [[1, 0, 0, 2], [0, 0, 0, 0], [0, 0, 0, 0], [3, 0, 0, 4]], 'd') begin = Basis.cast('std', [1, 1]) end = Basis.cast('std', 4) mxInReducedBasis = bt.resize_std_mx(mxInStdBasis, 'contract', end, begin) original = bt.resize_std_mx(mxInReducedBasis, 'expand', begin, end) self.assertArraysAlmostEqual(mxInStdBasis, original)
def test_gaugeopt_and_contract(self): ds = self.ds_lgst #pygsti.construction.generate_fake_data(self.datagen_gateset, self.lgstStrings, # nSamples=10000,sampleError='binomial', seed=100) mdl_lgst = pygsti.do_lgst(ds, self.fiducials, self.fiducials, self.model, svdTruncateTo=4, verbosity=0) #Gauge Opt to Target mdl_lgst_target = self.runSilent(pygsti.gaugeopt_to_target, mdl_lgst, self.model, verbosity=10, checkJac=True) # mdl_lgst.basis = self.model.basis.copy() mdl_clgst_cp = self.runSilent(pygsti.contract, mdl_lgst, "CP",verbosity=10, tol=10.0, useDirectCP=False) #non-direct CP contraction #Gauge Opt to Target using non-frobenius metrics mdl_lgst_targetAlt = self.runSilent(pygsti.gaugeopt_to_target, mdl_lgst_target, self.model, gatesMetric='fidelity', verbosity=10, checkJac=True) mdl_lgst_targetAlt = self.runSilent(pygsti.gaugeopt_to_target, mdl_lgst_target, self.model, gatesMetric='tracedist', verbosity=10, checkJac=True) mdl_lgst_targetAlt = self.runSilent(pygsti.gaugeopt_to_target, mdl_lgst_target, self.model, spamMetric='fidelity', verbosity=10, checkJac=True) mdl_lgst_targetAlt = self.runSilent(pygsti.gaugeopt_to_target, mdl_lgst_target, self.model, spamMetric='tracedist', verbosity=10, checkJac=True) #Using other methods mdl_BFGS = self.runSilent(pygsti.gaugeopt_to_target, mdl_lgst, self.model, method='BFGS', verbosity=10) with self.assertRaises(ValueError): #Invalid metric self.runSilent(pygsti.gaugeopt_to_target, mdl_lgst, self.model, method='BFGS', spamMetric='foobar', verbosity=10) with self.assertRaises(ValueError): #Invalid metric self.runSilent(pygsti.gaugeopt_to_target, mdl_lgst, self.model, method='BFGS', gatesMetric='foobar', verbosity=10) with self.assertRaises(ValueError): #can't use least-squares for anything but frobenius metric self.runSilent(pygsti.gaugeopt_to_target, mdl_lgst_target, self.model, spamMetric='tracedist', method='ls', verbosity=10, checkJac=True) #with self.assertRaises(ValueError): # self.runSilent(pygsti.gaugeopt_to_target, mdl_lgst_target, self.model, # gatesMetric='foobar', verbosity=10) #bad gatesMetric # #with self.assertRaises(ValueError): # self.runSilent(pygsti.gaugeopt_to_target, mdl_lgst_target, self.model, # spamMetric='foobar', verbosity=10) #bad spamMetric #Contractions mdl_clgst_tp = self.runSilent(pygsti.contract, mdl_lgst_target, "TP",verbosity=10, tol=10.0) mdl_clgst_cp = self.runSilent(pygsti.contract, mdl_lgst_target, "CP",verbosity=10, tol=10.0) mdl_clgst_cp2 = self.runSilent(pygsti.contract, mdl_lgst_target, "CP",verbosity=10, tol=10.0) mdl_clgst_cptp = self.runSilent(pygsti.contract, mdl_lgst_target, "CPTP",verbosity=10, tol=10.0) mdl_clgst_cptp2 = self.runSilent(pygsti.contract, mdl_lgst_target, "CPTP",verbosity=10, useDirectCP=False) mdl_clgst_cptp3 = self.runSilent(pygsti.contract, mdl_lgst_target, "CPTP",verbosity=10, tol=10.0, maxiter=0) mdl_clgst_xp = self.runSilent(pygsti.contract, mdl_lgst_target, "XP", ds,verbosity=10, tol=10.0) mdl_clgst_xptp = self.runSilent(pygsti.contract, mdl_lgst_target, "XPTP", ds,verbosity=10, tol=10.0) mdl_clgst_vsp = self.runSilent(pygsti.contract, mdl_lgst_target, "vSPAM",verbosity=10, tol=10.0) mdl_clgst_none = self.runSilent(pygsti.contract, mdl_lgst_target, "nothing",verbosity=10, tol=10.0) #test bad effect vector cases mdl_bad_effect = mdl_lgst_target.copy() mdl_bad_effect.povms['Mdefault'] = pygsti.obj.UnconstrainedPOVM( [('0',[100.0,0,0,0])] ) # E eigvals all > 1.0 self.runSilent(pygsti.contract, mdl_bad_effect, "vSPAM",verbosity=10, tol=10.0) mdl_bad_effect.povms['Mdefault'] = pygsti.obj.UnconstrainedPOVM( [('0',[-100.0,0,0,0])] ) # E eigvals all < 0 self.runSilent(pygsti.contract, mdl_bad_effect, "vSPAM",verbosity=10, tol=10.0) #with self.assertRaises(ValueError): # self.runSilent(pygsti.contract, mdl_lgst_target, "foobar",verbosity=10, tol=10.0) #bad toWhat #More gauge optimizations TP_gauge_group = pygsti.obj.TPGaugeGroup(mdl_lgst.dim) mdl_lgst_target_cp = self.runSilent(pygsti.gaugeopt_to_target, mdl_clgst_cptp, self.model, cptp_penalty_factor=1.0, gauge_group=TP_gauge_group, verbosity=10, checkJac=True) mdl_lgst_tp = self.runSilent(pygsti.gaugeopt_to_target, mdl_lgst, None, spam_penalty_factor=1.0, verbosity=10, checkJac=True) mdl_lgst.basis = Basis.cast("gm",4) #so CPTP optimizations can work on mdl_lgst mdl_lgst_cptp = self.runSilent(pygsti.gaugeopt_to_target, mdl_lgst, None, cptp_penalty_factor=1.0, spam_penalty_factor=1.0, verbosity=10, checkJac=True) mdl_lgst_cptp_tp = self.runSilent(pygsti.gaugeopt_to_target, mdl_lgst, None, cptp_penalty_factor=1.0, spam_penalty_factor=1.0, gauge_group=TP_gauge_group, verbosity=10, checkJac=True) #no point? (remove?) #I'm not sure why moving this test upward fixes a singlar matrix error (TODO LATER? - could one of above tests modify mdl_lgst??) #mdl_lgst_tp = self.runSilent(pygsti.gaugeopt_to_target( mdl_lgst, None, # spam_penalty_factor=1.0, verbosity=10, checkJac=True) mdl_lgst_tptarget = self.runSilent(pygsti.gaugeopt_to_target, mdl_lgst, self.model, spam_penalty_factor=1.0, verbosity=10, checkJac=True) mdl_lgst_cptptarget = self.runSilent(pygsti.gaugeopt_to_target, mdl_lgst, self.model, cptp_penalty_factor=1.0, spam_penalty_factor=1.0, verbosity=10, checkJac=True) mdl_lgst_cptptarget2= self.runSilent(pygsti.gaugeopt_to_target, mdl_lgst, self.model, cptp_penalty_factor=1.0, spam_penalty_factor=1.0, gauge_group=TP_gauge_group, verbosity=10, checkJac=True) #no point? (remove?) #Use "None" gauge group mdl_none = self.runSilent(pygsti.gaugeopt_to_target, mdl_lgst, self.model, gauge_group=None, verbosity=10) soln, trivialEl, mdl_none = self.runSilent(pygsti.gaugeopt_to_target, mdl_lgst, self.model, gauge_group=None, verbosity=10, returnAll=True) #Use "None" default gauge group mdl_none = self.model.copy() mdl_none.default_gauge_group = None self.runSilent(pygsti.gaugeopt_to_target, mdl_none, self.model, verbosity=10) soln, trivialEl, mdl_none = self.runSilent(pygsti.gaugeopt_to_target, mdl_none, self.model, verbosity=10, returnAll=True) #TODO: check output lies in space desired # big kick that should land it outside XP, TP, etc, so contraction # routines are more tested mdl_bigkick = mdl_lgst_target.kick(absmag=1.0) mdl_badspam = mdl_bigkick.copy() mdl_badspam.povms['Mdefault'] = pygsti.obj.UnconstrainedPOVM( [('0',np.array( [[2],[0],[0],[4]], 'd'))] ) #set a bad evec so vSPAM has to work... mdl_clgst_tp = self.runSilent(pygsti.contract,mdl_bigkick, "TP", verbosity=10, tol=10.0) mdl_clgst_cp = self.runSilent(pygsti.contract,mdl_bigkick, "CP", verbosity=10, tol=10.0) mdl_clgst_cptp = self.runSilent(pygsti.contract,mdl_bigkick, "CPTP", verbosity=10, tol=10.0) mdl_clgst_xp = self.runSilent(pygsti.contract,mdl_bigkick, "XP", ds, verbosity=10, tol=10.0) mdl_clgst_xptp = self.runSilent(pygsti.contract,mdl_bigkick, "XPTP", ds, verbosity=10, tol=10.0) mdl_clgst_vsp = self.runSilent(pygsti.contract,mdl_badspam, "vSPAM", verbosity=10, tol=10.0) mdl_clgst_none = self.runSilent(pygsti.contract,mdl_bigkick, "nothing", verbosity=10, tol=10.0) #TODO: check output lies in space desired #Check Errors with self.assertRaises(ValueError): pygsti.contract(mdl_lgst_target, "FooBar",verbosity=0) # bad toWhat argument
def jamiolkowski_iso(operation_mx, op_mx_basis='pp', choi_mx_basis='pp'): """ Given a operation matrix, return the corresponding Choi matrix that is normalized to have trace == 1. Parameters ---------- operation_mx : numpy array the operation matrix to compute Choi matrix of. op_mx_basis : Basis object The source and destination basis, respectively. Allowed values are Matrix-unit (std), Gell-Mann (gm), Pauli-product (pp), and Qutrit (qt) (or a custom basis object). choi_mx_basis : Basis object The source and destination basis, respectively. Allowed values are Matrix-unit (std), Gell-Mann (gm), Pauli-product (pp), and Qutrit (qt) (or a custom basis object). Returns ------- numpy array the Choi matrix, normalized to have trace == 1, in the desired basis. """ operation_mx = _np.asarray(operation_mx) op_mx_basis = _bt.create_basis_for_matrix(operation_mx, op_mx_basis) opMxInStdBasis = _bt.change_basis(operation_mx, op_mx_basis, op_mx_basis.create_equivalent('std')) #expand operation matrix so it acts on entire space of dmDim x dmDim density matrices # so that we can take dot products with the BVec matrices below opMxInStdBasis = _bt.resize_std_mx(opMxInStdBasis, 'expand', op_mx_basis.create_equivalent( 'std'), op_mx_basis.create_simple_equivalent('std')) N = opMxInStdBasis.shape[0] # dimension of the full-basis (expanded) gate dmDim = int(round(_np.sqrt(N))) # density matrix dimension #Note: we need to use the *full* basis of Matrix Unit, Gell-Mann, or Pauli-product matrices when # generating the Choi matrix, even when the original operation matrix doesn't include the entire basis. # This is because even when the original operation matrix doesn't include a certain basis element (B0 say), # conjugating with this basis element and tracing, i.e. trace(B0^dag * Operation * B0), is not necessarily zero. #get full list of basis matrices (in std basis) -- i.e. we use dmDim if not isinstance(choi_mx_basis, _Basis): choi_mx_basis = _Basis.cast(choi_mx_basis, N) # we'd like a basis of dimension N BVec = choi_mx_basis.create_simple_equivalent().elements M = len(BVec) # can be < N if basis has multiple block dims assert(M == N), 'Expected {}, got {}'.format(M, N) choiMx = _np.empty((N, N), 'complex') for i in range(M): for j in range(M): BiBj = _np.kron(BVec[i], _np.conjugate(BVec[j])) BiBj_dag = _np.transpose(_np.conjugate(BiBj)) choiMx[i, j] = _mt.trace(_np.dot(opMxInStdBasis, BiBj_dag)) \ / _mt.trace(_np.dot(BiBj, BiBj_dag)) # This construction results in a Jmx with trace == dim(H) = sqrt(operation_mx.shape[0]) # (dimension of density matrix) but we'd like a Jmx with trace == 1, so normalize: choiMx_normalized = choiMx / dmDim return choiMx_normalized
def test_raises_on_basis_mismatch(self): with self.assertRaises(ValueError): mdl_target_gm = std2Q_XXYYII.target_model() mdl_target_gm.basis = Basis.cast("gm", 16) ot.project_model(self.model, mdl_target_gm, self.projectionTypes, 'logGti') # basis mismatch
def test_lind_errgen_projects(self): mx_basis = Basis.cast('pp', 4) basis = Basis.cast('PP', 4) X = basis['X'] Y = basis['Y'] Z = basis['Z'] # Build known combination to project back to errgen = 0.1 * lt.create_elementary_errorgen('H', Z) \ - 0.01 * lt.create_elementary_errorgen('H', X) \ + 0.2 * lt.create_elementary_errorgen('S', X) \ + 0.25 * lt.create_elementary_errorgen('S', Y) \ + 0.05 * lt.create_elementary_errorgen('C', X, Y) \ - 0.01 * lt.create_elementary_errorgen('A', X, Y) errgen = bt.change_basis(errgen, 'std', mx_basis) Hblk = LindbladCoefficientBlock('ham', basis) ODblk = LindbladCoefficientBlock('other_diagonal', basis) Oblk = LindbladCoefficientBlock('other', basis) Hblk.set_from_errorgen_projections(errgen, errorgen_basis=mx_basis) ODblk.set_from_errorgen_projections(errgen, errorgen_basis=mx_basis) Oblk.set_from_errorgen_projections(errgen, errorgen_basis=mx_basis) self.assertArraysAlmostEqual(Hblk.block_data, [-0.01, 0, 0.1]) self.assertArraysAlmostEqual(ODblk.block_data, [0.2, 0.25, 0]) self.assertArraysAlmostEqual( Oblk.block_data, np.array([[0.2, 0.05 + 0.01j, 0], [0.05 - 0.01j, 0.25, 0], [0, 0, 0]])) def dicts_equal(d, f): f = {LEEL.cast(k): v for k, v in f.items()} if set(d.keys()) != set(f.keys()): return False for k in d: if abs(d[k] - f[k]) > 1e-12: return False return True self.assertTrue( dicts_equal(Hblk.elementary_errorgens, { ('H', 'Z'): 0.1, ('H', 'X'): -0.01, ('H', 'Y'): 0 })) self.assertTrue( dicts_equal(ODblk.elementary_errorgens, { ('S', 'X'): 0.2, ('S', 'Y'): 0.25, ('S', 'Z'): 0 })) self.assertTrue( dicts_equal( Oblk.elementary_errorgens, { ('S', 'X'): 0.2, ('S', 'Y'): 0.25, ('S', 'Z'): 0.0, ('C', 'X', 'Y'): 0.05, ('A', 'X', 'Y'): -0.01, ('C', 'X', 'Z'): 0, ('A', 'X', 'Z'): 0, ('C', 'Y', 'Z'): 0, ('A', 'Y', 'Z'): 0, }))