| @@ -15,9 +15,9 @@ decompositions = ("xxxx", "xx", "zzxx", "zz", "zxx", "z", "zzz", "xxz", | |||
| "xzx", "xzxxx", "xzzzx", "xxxzx", "xzz", "zzx", "xxx", "x", | |||
| "zzzx", "xxzx", "zx", "zxxx", "xxxz", "xzzz", "xz", "xzxx") | |||
| def conjugate(vop, transform): | |||
| def conjugate(operator, unitary): | |||
| """ Returns transform * vop * transform^dagger and a phase in {+1, -1} """ | |||
| return measurement_table[vop, transform] | |||
| return measurement_table[operator, unitary] | |||
| def use_old_cz(): | |||
| """ Use the CZ table from A&B's code """ | |||
| @@ -101,22 +101,32 @@ def get_state_table(unitaries): | |||
| np.dot(kp, state).T) | |||
| return state_table | |||
| def get_measurement_entry(operator, unitary): | |||
| """ | |||
| Any Clifford group unitary will map an operator A in {I, X, Y, Z} | |||
| to an operator B in +-{I, X, Y, Z}. This finds that mapping. | |||
| """ | |||
| matrices = ({"x": qi.msqx, "z": qi.sqz}[c] for c in decompositions[unitary]) | |||
| unitary = reduce(np.dot, matrices, np.eye(2, dtype=complex)) | |||
| operator = qi.operators[operator] | |||
| new_operator = reduce(np.dot, (unitary, operator, qi.hermitian_conjugate(unitary))) | |||
| for i, o in enumerate(qi.operators): | |||
| if np.allclose(o, new_operator): | |||
| return i, 1 | |||
| elif np.allclose(o, -new_operator): | |||
| return i, -1 | |||
| raise IndexError | |||
| def get_measurement_table(): | |||
| """ | |||
| Compute a table of transform * operation * transform^dagger | |||
| This is pretty unintelligible right now, we should probably compute the phase from unitaries instead | |||
| """ | |||
| measurement_table = np.zeros((4, 24, 2), dtype=complex) | |||
| for vop, transform in it.product(range(4), range(24)): | |||
| assert vop in set(xrange(4)) | |||
| op = times_table[transform, vop] | |||
| op = times_table[op, conjugation_table[transform]] | |||
| is_id_or_vop = (transform % 4 == 0) or (transform % 4 == vop) | |||
| is_non_pauli = (transform >= 4) and (transform <= 15) | |||
| phase = ((-1, 1), (1, -1))[is_id_or_vop][is_non_pauli] | |||
| if vop == 0: | |||
| phase = 1 | |||
| measurement_table[vop, transform] = [op, phase] | |||
| for operator, unitary in it.product(range(4), range(24)): | |||
| measurement_table[operator, unitary] = [operator, unitary] | |||
| return measurement_table | |||
| @@ -36,6 +36,8 @@ cz = np.array(np.eye(4), dtype=complex) | |||
| cz[3,3]=-1 | |||
| # States | |||
| zero = np.array([[1],[0]], dtype=complex) | |||
| one = np.array([[0],[1]], dtype=complex) | |||
| plus = np.array([[1],[1]], dtype=complex) / np.sqrt(2) | |||
| bond = cz.dot(np.kron(plus, plus)) | |||
| nobond = np.kron(plus, plus) | |||
| @@ -46,6 +48,7 @@ names = "identity", "px", "py", "pz", "hadamard", "phase", "sqz", "msqz", "sqy", | |||
| by_name = dict(zip(names, common_us)) | |||
| paulis = px, py, pz | |||
| operators = id, px, py, pz | |||
| def normalize_global_phase(m): | |||
| @@ -0,0 +1,46 @@ | |||
| from abp import clifford, qi | |||
| import numpy as np | |||
| import itertools as it | |||
| def conj_hack(operator, unitary): | |||
| """ TODO: make this meaningful / legible """ | |||
| assert operator in set(xrange(4)) | |||
| op = clifford.times_table[unitary, operator] | |||
| op = clifford.times_table[op, clifford.conjugation_table[unitary]] | |||
| is_id_or_operator = (unitary % 4 == 0) or (unitary % 4 == operator) | |||
| is_non_pauli = (unitary >= 4) and (unitary <= 15) | |||
| phase = ((-1, 1), (1, -1))[is_id_or_operator][is_non_pauli] | |||
| if operator == 0: | |||
| phase = 1 | |||
| return op, phase | |||
| def conj(operator, unitary): | |||
| """ Better """ | |||
| matrices = ({"x": qi.msqx, "z": qi.sqz}[c] for c in clifford.decompositions[unitary]) | |||
| unitary = reduce(np.dot, matrices, np.eye(2, dtype=complex)) | |||
| operator = qi.operators[operator] | |||
| new_operator = reduce(np.dot, (unitary, operator, qi.hermitian_conjugate(unitary))) | |||
| for i, o in enumerate(qi.operators): | |||
| if np.allclose(o, new_operator): | |||
| return i, 1 | |||
| elif np.allclose(o, -new_operator): | |||
| return i, -1 | |||
| raise IndexError | |||
| for operator, unitary in it.product(range(4), range(24)): | |||
| assert conj(operator, unitary) == conj_hack(operator, unitary) | |||
| #new = np.dot(u, np.dot(o, qi.hermitian_conjugate(u))) | |||
| #which = clifford.find_clifford(new, clifford.unitaries[:4]) | |||
| #assert which in xrange(4) | |||
| #whichm = [qi.id, qi.px, qi.py, qi.pz][which] | |||
| #if np.allclose(new, whichm): | |||
| #return which, 1 | |||
| #elif np.allclose(new, -whichm): | |||
| #return which, -1 | |||
| #else: | |||
| #raise IndexError | |||
| @@ -4,7 +4,6 @@ import itertools | |||
| #//! replaces op by trans * op * trans^dagger and returns a phase, | |||
| #/*! either +1 or -1 (as RightPhase(0) or RightPhase(2)) */ | |||
| #RightPhase conjugate (const LocCliffOp trans); | |||
| def test_conjugation(): | |||
| """ Test that clifford.conugate() agrees with graphsim.LocCliffOp.conjugate """ | |||