!git clone --branch qamp-qiskit-demodays https://github.com/qiskit-community/qiskit-qec.git /Users/ruihaoli/qiskit-qec

%cd ../qiskit-qec

!pip install -r requirements.txt

import numpy as np
from qiskit_qec.operators.xp_pauli import XPPauli
from qiskit_qec.operators.xp_pauli_list import XPPauliList

# XPPauli object
a = XPPauli(
    data=np.array([0, 3, 1, 6, 4, 3], dtype=np.int64), phase_exp=11, precision=4
)
unique_a = a.unique_vector_rep()
print(unique_a.matrix)
print(unique_a.x)
print(unique_a.z)
print(unique_a._phase_exp)

# XPPauliList object
b = XPPauliList(
    data=np.array([[1, 0, 1, 1, 5, 3, 5, 4], [1, 0, 1, 0, 1, 5, 2, 0]], dtype=np.int64),
    phase_exp=np.array([4, 7]),
    precision=6,
)
unique_b = b.unique_vector_rep()
print(unique_b.matrix)
print(unique_b._phase_exp)

a = XPPauli(
    data=np.array([1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0]), phase_exp=12, precision=8
)
rescaled_a = a.rescale_precision(new_precision=2, inplace=False)
print(rescaled_a.matrix)
print(rescaled_a._phase_exp)

# Case where it is not possible to rescale
a.rescale_precision(new_precision=3, inplace=False)

a = XPPauli(data=np.array([1, 1, 2, 2, 1, 2, 3, 3]), phase_exp=0, precision=8)
antisym_op = a.antisymmetric_op(int_vec=a.z)
print(antisym_op.matrix)
print(antisym_op._phase_exp)

a = XPPauli(data=np.array([0, 1, 0, 0, 2, 0]), phase_exp=6, precision=4)
b = XPPauli(data=np.array([1, 1, 1, 3, 3, 0]), phase_exp=2, precision=4)
product = a.compose(b, inplace=False)
print(product.matrix)
print(product._phase_exp)

# Multiplying two XPPauliList objects
a = XPPauliList(
    data=np.array([[1, 0, 1, 1, 5, 3, 5, 4], [1, 0, 1, 0, 1, 5, 2, 0]]),
    phase_exp=np.array([4, 7]),
    precision=6,
)
b = XPPauliList(
    data=np.array([[1, 0, 0, 1, 4, 1, 0, 1], [0, 1, 1, 0, 1, 3, 0, 5]]),
    phase_exp=np.array([11, 2]),
    precision=6,
)
product = a.compose(b, inplace=False)
print(product.matrix)
print(product._phase_exp)

a = XPPauliList(
    data=np.array([[1, 0, 1, 1, 5, 3, 5, 4], [1, 0, 1, 1, 5, 4, 1, 5]]),
    phase_exp=[1, 2],
    precision=6,
)
a1 = a.power(n=5)
print(a1.matrix)
print(a1._phase_exp, "\n")

a2 = a.power(n=[3, 4])
print(a2.matrix)
print(a2._phase_exp)

import qiskit_qec.arithmetic.modn as modn

# Quotient of a/b in the ring Z_N
a, b, N = 18, 3, 5
q = modn.quo(a, b, N)
print(q)
print(q == (a % N) // (b % N))

# Divisor of a/b in the ring Z_N
a, b, N = 24, 8, 7
d = modn.div(a, b, N)
print(d)
print((b * d) % N == a % N)

# Annihilator of a in the ring Z/nZ
a, N = 10, 5
ann = modn.ann(a, N)
print(ann)
print((a * ann) % N == 0)

from qiskit_qec.linear.matrix import do_row_op

mat = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
N = 4
print(mat, "\n")

# Swap rows 0 and 1
mat1 = do_row_op(mat, ("swap", [0, 1], []), N)
print(mat1, "\n")

# Append the product of row 0 by a scalar (3) to the end of matrix
mat2 = do_row_op(mat, ("append", [0], [3]), N)
print(mat2)

from qiskit_qec.linear.matrix import howell, howell_complete

mat = np.array([[8, 5, 5], [0, 9, 8], [0, 0, 10]])
N = 12
howell_mat = howell(mat, N)
print(howell_mat, "\n")

howell_mat, transform_mat, kernel_mat = howell_complete(mat, N)
print(howell_mat, "\n")
print(transform_mat, "\n")
print(kernel_mat)