diff --git a/debug/debug_compress_approximations.py b/debug/debug_compress_approximations.py new file mode 100644 index 00000000..4c0fb8c1 --- /dev/null +++ b/debug/debug_compress_approximations.py @@ -0,0 +1,33 @@ +from cProfile import label +from lsqecc.gates.compress_rotation_approximations import partition_gate_sequence +from lsqecc.pauli_rotations.rotation import CachedRotationApproximations +from lsqecc.gates.pi_over_2_to_the_n_rz_gate_approximations import get_pi_over_2_to_the_n_rz_gate +import numpy as np +import matplotlib.pyplot as plt + +# test_sequence_1 = "SSSXHSTHTHSTHTH" +# test_sequence_2 = "SHSSXH" +# test_sequence_3 = "HSSTTSHSH" +test_sequence = CachedRotationApproximations.get_pi_over_2_to_the_n_rz_gate(3) +sequences_Z = partition_gate_sequence(test_sequence) +sequences_X = partition_gate_sequence("H" + test_sequence + "H") + +print("The gate for a Z rotation are:\n") +print(f"The number of gates without compression in Gate Frame of is {len(test_sequence)} ") +print( + f"Number of gates without compressiopn in Pauli Frame is {len(test_sequence) + 2*test_sequence.count('H')}" +) +print(f"The number of partitions (Compressed list of gates) is {len(sequences_Z)}") + +print("The gate for a X rotation are:\n") +print(f"The number of gates without compression in Gate Frame of is {len(test_sequence)+2} ") +print( + f"Number of gates without compressiopn in Pauli Frame is {len(test_sequence) + 2*test_sequence.count('H') + 6}" +) +print(f"The number of partitions (Compressed list of gates) is {len(sequences_X)}") + + +# for seq in sequences: +# print(f"{seq}") + +# Most common ones are HTH and HSTH diff --git a/debug/debug_to_basic_form_compress.py b/debug/debug_to_basic_form_compress.py new file mode 100644 index 00000000..3bc85d9c --- /dev/null +++ b/debug/debug_to_basic_form_compress.py @@ -0,0 +1,12 @@ +from lsqecc.pauli_rotations.rotation import PauliRotation, PauliOperator +from fractions import Fraction + +Z = PauliOperator.Z +uncompressed_list = PauliRotation.from_list([Z], Fraction(1, 16)).to_basic_form_decomposition( + compress_rotations=False +) +print(len(uncompressed_list)) +compressed_list = PauliRotation.from_list([Z], Fraction(1, 16)).to_basic_form_decomposition( + compress_rotations=True +) +print(len(compressed_list)) diff --git a/src/lsqecc/gates/compress_rotation_approximations.py b/src/lsqecc/gates/compress_rotation_approximations.py new file mode 100644 index 00000000..ffa6f66f --- /dev/null +++ b/src/lsqecc/gates/compress_rotation_approximations.py @@ -0,0 +1,36 @@ +def partition_gate_sequence(gate_approximation: str): + partitioned_sequence = list() + partition = "" + in_x_basis = False + + # note: The sequence 'HXH' is not covered by this function. + # But this also not encountered in the cached rotations + for index, gate in enumerate(gate_approximation): + if gate in {"S", "T"}: + partition += gate + elif gate == "X": + if not len(partition): # empty partition + pass + elif partition[0] == "H": + partitioned_sequence.append(partition[0]) + partitioned_sequence.append(partition[1:]) + else: + partitioned_sequence.append(partition) + partitioned_sequence.append(gate) + partition = "" + + elif gate == "H": + if not in_x_basis: + if not len(partition) == 0: + partitioned_sequence.append(partition) + partition = gate + if index == len(gate_approximation) - 1: + partitioned_sequence.append(partition) + in_x_basis = True + else: + partition += gate + in_x_basis = False + partitioned_sequence.append(partition) + partition = "" + + return partitioned_sequence diff --git a/src/lsqecc/pauli_rotations/rotation.py b/src/lsqecc/pauli_rotations/rotation.py index 38e89c48..0b3b2bac 100644 --- a/src/lsqecc/pauli_rotations/rotation.py +++ b/src/lsqecc/pauli_rotations/rotation.py @@ -23,6 +23,7 @@ from typing import Dict, List, Tuple import lsqecc.simulation.conditional_operation_control as coc +from lsqecc.gates.compress_rotation_approximations import partition_gate_sequence from lsqecc.gates.pi_over_2_to_the_n_rz_gate_approximations import ( get_pi_over_2_to_the_n_rz_gate, ) @@ -234,7 +235,9 @@ def __eq__(self, other) -> bool: def __hash__(self) -> int: return hash(hash(self.rotation_amount) + hash(tuple(self.ops_list))) - def to_basic_form_approximation(self) -> List["PauliRotation"]: + def to_basic_form_approximation( + self, compress_rotations: bool = False + ) -> List["PauliRotation"]: """Get an approximation in terms of pi/2, pi/4 and pi/8""" if not is_power_of_two(self.rotation_amount.denominator): @@ -247,7 +250,6 @@ def to_basic_form_approximation(self) -> List["PauliRotation"]: int(math.log2(self.rotation_amount.denominator)) - 1 ) - axis_list = list(filter(lambda op: op != PauliOperator.I, self.ops_list)) if len(axis_list) != 1: raise Exception("Can only approximate single qubit rotations") @@ -260,6 +262,8 @@ def to_basic_form_approximation(self) -> List["PauliRotation"]: else: raise Exception(f"Unsupported axis of rotation {axis}") + if compress_rotations: + approximation_gates = partition_gate_sequence(approximation_gates) rotations = [] qubit_idx = self.ops_list.index(axis) for gate in approximation_gates: @@ -271,13 +275,24 @@ def to_basic_form_approximation(self) -> List["PauliRotation"]: rotations.append(PauliRotation.from_x_gate(self.qubit_num, qubit_idx)) elif gate == "H": rotations.extend(PauliRotation.from_hadamard_gate(self.qubit_num, qubit_idx)) + elif len(gate) > 1: + rotations.append(PauliRotation.from_gate_string(self.qubit_num, qubit_idx, gate)) else: raise Exception(f"Cannot decompose gate: {gate}") # Note that it might be possible to simplify these a little further return rotations - def to_basic_form_decomposition(self) -> List["PauliRotation"]: + @staticmethod + def count_s_and_t_to_phase(gate_string: str) -> Fraction: + s_count = gate_string.count("S") + t_count = gate_string.count("T") + phase = s_count * Fraction(1, 2) + t_count * Fraction(1, 4) + return phase + + def to_basic_form_decomposition( + self, compress_rotations: bool = False + ) -> List["PauliRotation"]: """Express in terms of pi/2, pi/4 and pi/8""" if self.rotation_amount.denominator == 1: return [] # don't need to do anything because exp(-i*pi*P) = I @@ -292,7 +307,7 @@ def to_basic_form_decomposition(self) -> List["PauliRotation"]: output_rotations.append(new_rotation) return output_rotations else: - return self.to_basic_form_approximation() + return self.to_basic_form_approximation(compress_rotations) def to_latex(self) -> str: return f"{super().to_latex()}_{{{phase_frac_to_latex(self.rotation_amount)}}}" @@ -307,6 +322,23 @@ def from_list(pauli_ops: List[PauliOperator], rotation: Fraction) -> "PauliRotat r.change_single_op(i, op) return r + @staticmethod + def from_gate_string(num_qubits: int, target_qubit: int, gate_string: str): + if gate_string.startswith("H") and gate_string.endswith("H"): + return PauliRotation.from_r_gate( + num_qubits, + target_qubit, + PauliOperator.X, + phase=PauliRotation.count_s_and_t_to_phase(gate_string), + ) + else: + return PauliRotation.from_r_gate( + num_qubits, + target_qubit, + PauliOperator.Z, + phase=PauliRotation.count_s_and_t_to_phase(gate_string), + ) + @staticmethod def from_r_gate(num_qubits: int, target_qubit: int, phase_type: PauliOperator, phase: Fraction): """Note that the convention for rz and rx is different from our pauli rotation convention. diff --git a/src/lsqecc/resource_estimation/gate_count_compression_analysis.py b/src/lsqecc/resource_estimation/gate_count_compression_analysis.py new file mode 100644 index 00000000..c67c65e4 --- /dev/null +++ b/src/lsqecc/resource_estimation/gate_count_compression_analysis.py @@ -0,0 +1,76 @@ +import matplotlib.pyplot as plt +import numpy as np + +from lsqecc.gates.compress_rotation_approximations import partition_gate_sequence +from lsqecc.gates.pi_over_2_to_the_n_rz_gate_approximations import ( + get_pi_over_2_to_the_n_rz_gate, +) + +gate_counts_Z = np.zeros((len(get_pi_over_2_to_the_n_rz_gate[3:]), 3)) +for index, gate_sequence in enumerate(get_pi_over_2_to_the_n_rz_gate[3:]): + compressed_sequence = partition_gate_sequence(gate_sequence) + gate_counts_Z[index, 0] = len(gate_sequence) + gate_counts_Z[index, 1] = len(gate_sequence) + 2 * gate_sequence.count("H") + gate_counts_Z[index, 2] = len(compressed_sequence) + +gate_counts_X = np.zeros((len(get_pi_over_2_to_the_n_rz_gate[3:]), 3)) +for index, gate_sequence in enumerate(get_pi_over_2_to_the_n_rz_gate[3:]): + compressed_sequence = partition_gate_sequence("H" + gate_sequence + "H") + gate_counts_X[index, 0] = len(gate_sequence) + gate_counts_X[index, 1] = len(gate_sequence) + 2 * gate_sequence.count("H") + 6 + gate_counts_X[index, 2] = len(compressed_sequence) + + +compression_ratio_mean_Z = np.mean(np.divide(gate_counts_Z[:, 1], gate_counts_Z[:, 2])) +compression_ratio_mean_X = np.mean(np.divide(gate_counts_X[:, 1], gate_counts_X[:, 2])) + + +plt.figure(figsize=(16, 9)) +plt.plot( + np.arange(0, len(get_pi_over_2_to_the_n_rz_gate[3:])), + gate_counts_Z[:, 0], + label="Uncompressed Gate Count: Gate Frame", +) +plt.plot( + np.arange(0, len(get_pi_over_2_to_the_n_rz_gate[3:])), + gate_counts_Z[:, 1], + label="Uncompressed Gate Count: Pauli Frame", +) +plt.plot( + np.arange(0, len(get_pi_over_2_to_the_n_rz_gate[3:])), + gate_counts_Z[:, 2], + label="Compressed Gate Count: Pauli Frame", +) +plt.xlabel("Rotation amount (in powers of 2)") +plt.ylabel("Gate Count") +plt.title( + "Compression of Z Rotation gates in Pauli Frame \n" + + f" Mean Compression Ratio = ={compression_ratio_mean_Z}" +) +plt.legend() +# plt.savefig("assets/compression_Z_rotations.png") + +plt.figure(figsize=(16, 9)) +plt.plot( + np.arange(0, len(get_pi_over_2_to_the_n_rz_gate[3:])), + gate_counts_X[:, 0], + label="Uncompressed Gate Count: Gate Frame", +) +plt.plot( + np.arange(0, len(get_pi_over_2_to_the_n_rz_gate[3:])), + gate_counts_X[:, 1], + label="Uncompressed Gate Count: Pauli Frame", +) +plt.plot( + np.arange(0, len(get_pi_over_2_to_the_n_rz_gate[3:])), + gate_counts_X[:, 2], + label="Compressed Gate Count: Pauli Frame", +) +plt.xlabel("Rotation amount (in powers of 2)") +plt.ylabel("Gate Count") +plt.title( + "Compression of X Rotation gates in Pauli Frame \n" + + f"Mean Compression Ratio = ={compression_ratio_mean_X}" +) +plt.legend() +# plt.savefig("assets/compression_X_rotations.png") diff --git a/tests/gates/compress_rotation_approximations_test.py b/tests/gates/compress_rotation_approximations_test.py new file mode 100644 index 00000000..12ba9a8c --- /dev/null +++ b/tests/gates/compress_rotation_approximations_test.py @@ -0,0 +1,21 @@ +from typing import List + +import pytest + +from lsqecc.gates.compress_rotation_approximations import partition_gate_sequence + + +class TestGateCompression: + @pytest.mark.parametrize( + "gate_string, partitioned_gates", + [ + ("SSSXHSTHTHSTHTH", ["SSS", "X", "HSTH", "T", "HSTH", "T", "H"]), + ("SHSSXH", ["S", "H", "SS", "X", "H"]), + ("HSSTTSHSX", ["HSSTTSH", "S", "X"]), + ("STXH", ["ST", "X", "H"]), + ], + ) + def test_partition_gate_sequence(self, gate_string: str, partitioned_gates: List[str]): + func_output = partition_gate_sequence(gate_string) + assert len(partitioned_gates) == len(func_output) + assert func_output == partitioned_gates diff --git a/tests/pauli_rotations/rotation_test.py b/tests/pauli_rotations/rotation_test.py index b59f5199..c682d6a2 100644 --- a/tests/pauli_rotations/rotation_test.py +++ b/tests/pauli_rotations/rotation_test.py @@ -215,6 +215,24 @@ def test_to_basic_form_decomposition_with_approximation(self, snapshot): "list_repr.txt", ) + def test_to_basic_form_decomposition_with_approximation_and_compression(self, snapshot): + snapshot.assert_match( + repr( + PauliRotation.from_list([Z], Fraction(1, 16)).to_basic_form_decomposition( + compress_rotations=True + ) + ), + "list_repr_Z.txt", + ) + snapshot.assert_match( + repr( + PauliRotation.from_list([X], Fraction(1, 16)).to_basic_form_decomposition( + compress_rotations=True + ) + ), + "list_repr_X.txt", + ) + @pytest.mark.parametrize( "rotation", [ diff --git a/tests/pauli_rotations/snapshots/rotation_test/test_to_basic_form_decomposition_with_approximation_and_compression/list_repr_X.txt b/tests/pauli_rotations/snapshots/rotation_test/test_to_basic_form_decomposition_with_approximation_and_compression/list_repr_X.txt new file mode 100644 index 00000000..5291896a --- /dev/null +++ b/tests/pauli_rotations/snapshots/rotation_test/test_to_basic_form_decomposition_with_approximation_and_compression/list_repr_X.txt @@ -0,0 +1 @@ +[1/4: [Z], 1/4: [X], 1/4: [Z], 3/4: [Z], 1/2: [X], 1/4: [Z], 1/4: [X], 1/4: [Z], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/4: [Z], 1/4: [Z], 1/4: [X], 1/4: [Z]] \ No newline at end of file diff --git a/tests/pauli_rotations/snapshots/rotation_test/test_to_basic_form_decomposition_with_approximation_and_compression/list_repr_Z.txt b/tests/pauli_rotations/snapshots/rotation_test/test_to_basic_form_decomposition_with_approximation_and_compression/list_repr_Z.txt new file mode 100644 index 00000000..cad9dda5 --- /dev/null +++ b/tests/pauli_rotations/snapshots/rotation_test/test_to_basic_form_decomposition_with_approximation_and_compression/list_repr_Z.txt @@ -0,0 +1 @@ +[3/4: [Z], 1/2: [X], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 3/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 1/8: [Z], 3/8: [X], 3/8: [Z], 3/8: [X], 1/8: [Z], 1/8: [X], 3/8: [Z], 1/8: [X], 3/8: [Z]] \ No newline at end of file