def qsvt_solver(
mat_raw_scr,
b_raw,
poly_degree,
be_method="banded",
preferences=Preferences(),
constraints=Constraints(),
):
scale = 0.5
b_norm = np.linalg.norm(b_raw) # b normalization
b_normalized = b_raw / b_norm
# Define block encoding
if be_method == "pauli":
data_size, block_size, be_scaling_factor, be_qfunc = get_pauli_be(
mat_raw_scr, PAULI_TRIM_REL_TOL
)
print(
f"Pauli block encoding with block size {block_size} and scaling factor {be_scaling_factor}"
)
elif be_method == "banded":
data_size, block_size, be_scaling_factor, be_qfunc = get_banded_diags_be(
mat_raw_scr
)
print(
f"Banded diagonal block encoding with block size {block_size} and scaling factor {be_scaling_factor}"
)
class BlockEncodedState(QStruct):
data: QNum[data_size]
block: QNum[block_size]
# Get SVD range
w_min, w_max = get_svd_range(mat_raw_scr / be_scaling_factor)
# Get Chebyshev polynomial and the corresponding QSVT angles
c, m = poly_inversion(poly_degree, 1 / w_min, "relative")
pcoefs, poly_scale = scale * c / m, scale / m
inv_phases = qsvt_phases(pcoefs)
# Define QSVT projector
@qfunc
def projector(be: BlockEncodedState, res: QBit):
res ^= be.block == 0
@qfunc
def main(
qsvt_aux: Output[QBit],
data: Output[QNum[data_size]],
block: Output[QNum[block_size]],
):
allocate(qsvt_aux)
allocate(block)
prepare_amplitudes(b_normalized.tolist(), 0, data)
be_state = BlockEncodedState()
within_apply(
lambda: bind([data, block], be_state),
lambda: qsvt_inversion(
inv_phases,
lambda aux: projector(be_state, aux),
lambda: be_qfunc(be_state.block, be_state.data),
qsvt_aux,
),
)
start_time_syn = time.time()
qprog = synthesize(main, preferences=preferences, constraints=constraints)
print("time to syn:", time.time() - start_time_syn)
start_time_exe = time.time()
sv = calculate_state_vector(qprog, filters={"block": 0, "qsvt_aux": 0})
proj_statevector = np.zeros(2**data_size, dtype=complex)
proj_statevector[sv["data"].to_numpy()] = sv["amplitude"].to_numpy()
indices = np.where(np.abs(proj_statevector) > 1e-13)[0]
if len(indices) > 0:
global_phase = np.angle(proj_statevector[indices[0]])
resulting_state = np.real(proj_statevector / np.exp(1j * global_phase))
else:
resulting_state = np.zeros(2**data_size)
print("time to exe:", time.time() - start_time_exe)
normalization_factor = (be_scaling_factor * poly_scale) / b_norm
return resulting_state / normalization_factor, qprog