Skip to content

Commit

Permalink
Better QFT Compilation python prototyping (#269)
Browse files Browse the repository at this point in the history
  • Loading branch information
isolatedinformation committed Mar 18, 2022
1 parent 481b699 commit d59f447
Show file tree
Hide file tree
Showing 9 changed files with 234 additions and 4 deletions.
33 changes: 33 additions & 0 deletions debug/debug_compress_approximations.py
Original file line number Diff line number Diff line change
@@ -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
12 changes: 12 additions & 0 deletions debug/debug_to_basic_form_compress.py
Original file line number Diff line number Diff line change
@@ -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))
36 changes: 36 additions & 0 deletions src/lsqecc/gates/compress_rotation_approximations.py
Original file line number Diff line number Diff line change
@@ -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
40 changes: 36 additions & 4 deletions src/lsqecc/pauli_rotations/rotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
Expand Down Expand Up @@ -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):
Expand All @@ -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")
Expand All @@ -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:
Expand All @@ -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
Expand All @@ -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)}}}"
Expand All @@ -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.
Expand Down
76 changes: 76 additions & 0 deletions src/lsqecc/resource_estimation/gate_count_compression_analysis.py
Original file line number Diff line number Diff line change
@@ -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")
21 changes: 21 additions & 0 deletions tests/gates/compress_rotation_approximations_test.py
Original file line number Diff line number Diff line change
@@ -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
18 changes: 18 additions & 0 deletions tests/pauli_rotations/rotation_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
[
Expand Down
Original file line number Diff line number Diff line change
@@ -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]]
Original file line number Diff line number Diff line change
@@ -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]]

0 comments on commit d59f447

Please sign in to comment.