def create_product_testvectors(): """yield instances of class ``QStateMatrix`` for tests """ for m1_data, m2_data, nqb in qs_matrix_data: m1 = create_m(*m1_data) m2 = create_m(*m2_data) yield m1, m2, nqb yield qs_unit_matrix(4), qs_unit_matrix(4), 3 for i in range(20): nqb = randint(0, 2) yield qs_rand_matrix(2, 0, 3), qs_rand_matrix(2, 0, 3), nqb for cols1 in range(2, 6): for cols2 in range(2, 6): for nqb in range(min(cols1, cols2)): for n in range(2): m1 = qs_rand_matrix(0, cols1, cols1 + 3) rand_mul_scalar(m1) m2 = qs_rand_matrix(0, cols2, cols2 + 3) rand_mul_scalar(m2) yield m1, m2, nqb # Sparse states for cols1 in range(2, 6): for cols2 in range(2, 6): for nqb in range(min(cols1, cols2)): for r in range(3): for n in range(2): m1 = qs_rand_matrix(0, cols1, r) m1.mul_scalar(randint(-8, 8), randint(0, 7)) m2 = qs_rand_matrix(0, cols2, r) m1.mul_scalar(randint(-8, 8), randint(0, 7)) yield m1, m2, nqb
def create_exp_data(): yield qs_unit_matrix(2), 0 yield qs_unit_matrix(4), -3 for n in range(1, 13): for i in range(10): m = rand_unitary_matrix(n) m.mul_scalar(randint(-2, 2)) e = randint(-10000, 10000) yield m, e
def ref_power(m, e): if e > 1: m1 = ref_power(m, e >> 1) m1 = m1 @ m1 return m1 @ m if e & 1 else m1 if e == 1: return m if e == 0: return qs_unit_matrix(m.shape[0]) if e < 0: mi = m.inv() assert m @ mi == qs_unit_matrix(m.shape[0]) return ref_power(mi, -e)
def test_qs_errors(verbose=0): FORMAT_REDUCED = False with pytest.raises(ValueError): QStateMatrix(10000, 10000) with pytest.raises(ValueError): QStateMatrix(1, 1, [0, 0, 0xf]) m1, m2 = qs_unit_matrix(1), qs_unit_matrix(2) with pytest.raises(ValueError): m1 @ m2 with pytest.raises(ValueError): m1 * m2 m = QStateMatrix(3, 3, [0, 0, 0xf], 2) with pytest.raises(ValueError): m.power(-1) FORMAT_REDUCED = True
def rand_unitary_matrix(n, scalar=True): m = qs_unit_matrix(n) e = randint(-16, 16) if scalar else 0 m.mul_scalar(e, randint(0, 7)) if n == 0: return m mask = (1 << n) - 1 for i in range(n + 2): v = randint(0, mask - 1) vc = randint(0, mask) & ~v m.gate_ctrl_not(vc, v) v1 = randint(0, mask) v2 = randint(0, mask) m.gate_ctrl_phi(v1, v2) m.gate_phi(randint(0, mask), 1) m.gate_phi(randint(0, mask), 2) m.gate_h(randint(0, mask)) m.gate_not(randint(0, mask)) for i in range(n + 2): v = randint(0, mask - 1) vc = randint(0, mask) & ~v m.gate_ctrl_not(vc, v) v1 = randint(0, mask) v2 = randint(0, mask) m.gate_ctrl_phi(v1, v2) return m.echelon()
def create_conjugate_data(): yield rand_unitary_matrix(0), [0, 1, 2, 3] yield qs_unit_matrix(1), [0, 1, 2, 3] for n in range(1, 13): for i in range(10): m = rand_unitary_matrix(n) v = rand_pauli_vectors(n, max(10, n)) yield m, v
def test_matrix_power(verbose=0): MAX_ORDER = (2**8 - 1) * (2**6 - 1) * 2**10 """Test matrix exponentiation and commputation of trace""" for ntest, (m, e) in enumerate(create_exp_data()): # Test exponentiation me = m.power(e) me_ref = ref_power(m, e) ok = me == me_ref if verbose or not ok: mm = m.copy() print("\nTest %d: exponent = %d, " % (ntest, e)) print("m =", m.reduce()) print("Result of exponentiation:", me_ref) if not ok: print("Obtained:", me) raise ValueError("Matrix exponentiation failed") nqb = m.shape[0] m.mul_scalar(-m.lb_norm2()) assert m.H == m.inv() # Test computation of trace if nqb > 8: continue tr = m.trace() tr_ref = ref_trace(m) if tr == 0: ok = tr_ref == 0 else: ok = abs(tr_ref / tr - 1) < 1.0e-6 if verbose or not ok: print("\nTrace of m:", tr) if not ok: print("m =", m.reduce()) if nqb < 3: print("m =\n", m.complex()) print("\nTrace expected:", tr_ref) s, f = m._trace_factor() print("Low level trace result:", s, hex(f)) print("Intermediate") m1 = m.copy() for i in range(nqb): m1.gate_ctrl_not(1 << i, 1 << (nqb + i)) print(m1) m1 = m1.restrict(nqb, nqb) print(m1) raise ValueError("Computation of trace failed") # Testing order if nqb > 4: continue order = m.order(MAX_ORDER) if verbose: s = print("Scaled matrix m has order %d" % order) assert m.power(order) == qs_unit_matrix(m.shape[0])
def create_display_testvectors(): """yield instances of class ``QStateMatrix`` for tests """ for rows, cols, factor, data in qs_matrix_data: m = QStateMatrix(rows, cols, data) m.mul_scalar(*factor) yield m yield qs_unit_matrix(4) for i in range(20): yield qs_rand_matrix(2, 0, 3) for i in range(20): yield qs_rand_matrix(1, 0, 2) for rows in range(6): for cols in range(5): for nr in [1, 2] + list(range(rows + cols, rows + cols + 3)): m = qs_rand_matrix(rows, cols, nr) m.mul_scalar(randint(-8, 8), randint(0, 7)) yield m
def create_testmatrices(): """yield instances of class ``QStateMatrix`` for tests """ for m_data in qs_matrix_data: m = create_m(*m_data) yield m yield qs_unit_matrix(4) for i in range(20): yield qs_rand_matrix(2, 2, 4) for cols in range(0,7): for rows in range(0, 7): if rows + cols > 9: break yield QStateMatrix(rows, cols) for data_rows in range(1, rows + cols + 3): for n in range(2): m = qs_rand_matrix(rows, cols, data_rows) rand_mul_scalar(m) yield m
def test_pauli_conjugate(verbose=0): """Test the conjugation of Pauli matrix with unitary matrix""" for ntest, (m, v) in enumerate(create_conjugate_data()): n = m.shape[0] p = [qs_pauli_matrix(n, x) for x in v] pv = [x.pauli_vector() for x in p] ok = pv == v if verbose or not ok: mm = m.copy() print("\nTest %d: v = %s" % (ntest, binary(v[0], 0, 2 * n + 2))) print("m =", mm.reduce_matrix(), mm) print("Pauli matrix of v", p[0]) if not ok: print("Input and recomputed Pauli vectors:") for i, x in enumerate(v): bv = binary(x, 0, 2 * n + 2) bpv = binary(pv[i], 0, 2 * n + 2) print(bv, ",", bpv) if not ok: err = "Error in recomputation of Pauli vector" raise ValueError(err) mi = m.inv() assert m @ mi == qs_unit_matrix(n), (str(m), str(mi), str(m @ mi)) w = m.pauli_conjugate(v) w_ref = [(m @ x @ mi).pauli_vector() for x in p] if verbose or w != w_ref: for i, w_i in enumerate(w): w_i_ref = w_ref[i] if w_i_ref != w_i: s = "Pauli vector: %s, conjugated: %s, obtained: %s" print(s % (hex(v[i]), hex(w_i_ref), hex(w_i))) err = "Pauli vector conjugation error" raise ValueError(err) elif verbose: s = "Pauli vector: %s, conjugated: %s" print(s % (hex(v[i]), hex(w_i))) w_noarg = m.pauli_conjugate(v, arg=False) if verbose: print("Without arg", [hex(x) for x in w_noarg]) mask = (1 << (2 * n)) - 1 assert w_noarg == [x & mask for x in w]
def test_pauli_multiplication(verbose=0): for ntest, (n, v1, v2) in enumerate(create_pauli_vectors()): p1 = qs_pauli_matrix(n, v1) p2 = qs_pauli_matrix(n, v2) # Check product v1 * v2 v3 = pauli_vector_mul(n, v1, v2) p3 = qs_pauli_matrix(n, v3) v3_ref = (p1 @ p2).pauli_vector() ok = v3 == v3_ref if verbose or not ok: print("Test %d, dim = %d" % (ntest, n)) print("v1 = %s, v2 = %s, v1 * v2 = %s" % (hex(v1), hex(v2), hex(v3_ref))) if not ok: print("m1", p1) print("m2", p2) print("m1 * m2", p1 @ p2) print("pauli vector obtained: ", hex(v3)) err = "Pauli vector multiplication failed" raise ValueError(err) # Check powers of v1 p_e_list = [qs_unit_matrix(n), p1, p1 @ p1, p1.H] v_e_ref_list = [m.pauli_vector() for m in p_e_list] v_e_list = [pauli_vector_exp(n, v1, e) for e in range(4)] ok = v_e_list == v_e_ref_list if verbose or not ok: print("v1 = ", hex(v1)) for e, v_ref in enumerate(v_e_ref_list): if ok: print("v1 ** %d = %s" % (e, hex(v_ref))) else: print("v1 ** %d = %s, obtained: %s, v1 = %s" % (e, hex(v_ref), hex(v_e_list[e]), v1)) if not ok: err = "Pauli vector exponentiation failed" raise ValueError(err)