|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
Arithmetic Utilities
|
|
"""
|
|
|
|
from typing import List, Tuple
|
|
import numpy as np
|
|
|
|
|
|
def normalize_vector(vector):
|
|
"""
|
|
Normalize the input state vector.
|
|
"""
|
|
return vector / np.linalg.norm(vector)
|
|
|
|
|
|
def is_power_of_2(num):
|
|
"""
|
|
Check if the input number is a power of 2.
|
|
"""
|
|
return num != 0 and ((num & (num - 1)) == 0)
|
|
|
|
|
|
def log2(num):
|
|
"""
|
|
Compute the log2 of the input number. Use bit operation if the input is a power of 2.
|
|
"""
|
|
if is_power_of_2(num):
|
|
ret = 0
|
|
while True:
|
|
if num >> ret == 1:
|
|
return ret
|
|
else:
|
|
ret += 1
|
|
else:
|
|
return np.log2(num)
|
|
|
|
|
|
def is_power(num, return_decomposition=False):
|
|
"""
|
|
Check if num is a perfect power in O(n^3) time, n=ceil(logN)
|
|
"""
|
|
b = 2
|
|
while (2**b) <= num:
|
|
a = 1
|
|
c = num
|
|
while (c - a) >= 2:
|
|
m = int((a + c) / 2)
|
|
|
|
if (m**b) < (num + 1):
|
|
p = int(m**b)
|
|
else:
|
|
p = int(num + 1)
|
|
|
|
if int(p) == int(num):
|
|
if return_decomposition:
|
|
return True, int(m), int(b)
|
|
else:
|
|
return True
|
|
|
|
if p < num:
|
|
a = int(m)
|
|
else:
|
|
c = int(m)
|
|
b = b + 1
|
|
if return_decomposition:
|
|
return False, num, 1
|
|
else:
|
|
return False
|
|
|
|
|
|
def next_power_of_2_base(n):
|
|
"""
|
|
Return the base of the smallest power of 2 no less than the input number
|
|
"""
|
|
base = 0
|
|
if n and not (n & (n - 1)):
|
|
return log2(n)
|
|
|
|
while n != 0:
|
|
n >>= 1
|
|
base += 1
|
|
|
|
return base
|
|
|
|
|
|
def transpositions(permutation: List[int]) -> List[Tuple[int, int]]:
|
|
"""Return a sequence of transpositions, corresponding to the permutation.
|
|
|
|
Args:
|
|
permutation: The ``List[int]`` defining the permutation. An element at index ``j`` should be
|
|
permuted to index ``permutation[j]``.
|
|
|
|
Returns:
|
|
List of transpositions, corresponding to the permutation. For permutation = [3, 0, 2, 1],
|
|
returns [(0,1), (0,3)]
|
|
"""
|
|
unchecked = [True] * len(permutation)
|
|
cyclic_form = []
|
|
for i in range(len(permutation)):
|
|
if unchecked[i]:
|
|
cycle = [i]
|
|
unchecked[i] = False
|
|
j = i
|
|
while unchecked[permutation[j]]:
|
|
j = permutation[j]
|
|
cycle.append(j)
|
|
unchecked[j] = False
|
|
if len(cycle) > 1:
|
|
cyclic_form.append(cycle)
|
|
cyclic_form.sort()
|
|
res = []
|
|
for x in cyclic_form:
|
|
len_x = len(x)
|
|
if len_x == 2:
|
|
res.append((x[0], x[1]))
|
|
elif len_x > 2:
|
|
first = x[0]
|
|
for y in x[len_x - 1 : 0 : -1]:
|
|
res.append((first, y))
|
|
return res
|
|
|
|
|
|
def triu_to_dense(triu: np.ndarray) -> np.ndarray:
|
|
"""Converts upper triangular part of matrix to dense matrix.
|
|
|
|
Args:
|
|
triu: array in the form [[A, B, C], [D, E], [F]]
|
|
|
|
Returns:
|
|
Array [[A, B, C], [B, D, E], [C, E, F]]
|
|
"""
|
|
dim = len(triu)
|
|
matrix = np.empty((dim, dim), dtype=complex)
|
|
for i in range(dim):
|
|
for j in range(dim - i):
|
|
matrix[i, i + j] = triu[i][j]
|
|
if j != 0:
|
|
matrix[i + j, i] = triu[i][j]
|
|
|
|
return matrix
|
|
|