janus.encode.utils 源代码

"""
编码工具函数模块

提供所有编码方法所需的辅助函数
"""
import numpy as np
from math import log2, ceil, floor, pi, acos, sqrt
from typing import Dict, List, Union

from janus.circuit import Circuit

QComplex = complex


[文档] def _build_state_dict(data: Union[List[float], List[complex], np.ndarray]) -> Dict[str, complex]: """ 将振幅列表转换为状态字典 将一维的振幅列表转换为状态向量的字典表示。 参数: data: 振幅值列表或数组 返回: Dict[str, complex]: 状态字典,格式为 {'binary_string': amplitude} """ if isinstance(data, np.ndarray): if data.size == 0: return {} data_list = data.tolist() else: if not data: return {} data_list = data n_qubits = int(ceil(log2(len(data_list)))) if len(data_list) > 0 else 1 state_dict: Dict[str, complex] = {} for cnt, amp in enumerate(data_list): amp_complex = complex(amp) # 跳过接近零的幅度 if abs(amp_complex)**2 < 1e-14: continue binary_string = format(cnt, f'0{n_qubits}b') state_dict[binary_string] = amp_complex return state_dict
[文档] def _schmidt(circuit: Circuit, qubits: List[int], data: List[float], cutoff: float): """ Schmidt 分解 对量子态进行 Schmidt 分解并生成对应的电路。 参数: circuit: Janus 量子电路对象 qubits: 量子比特索引列表 data: 量子态振幅列表 cutoff: 奇异值截断阈值 """ data_temp = np.array(data, dtype=float) n_qubits = len(qubits) # 特殊情况:单个量子比特 if n_qubits == 1: a0 = data_temp[0] if len(data_temp) > 0 else 0.0 clamped_a0 = max(-1.0, min(1.0, a0)) if clamped_a0 < 0: angle = 2 * pi - 2 * acos(clamped_a0) else: angle = 2 * acos(clamped_a0) circuit.ry(angle, qubits[0]) return # 补充数据到 2^n 的大小 size = 1 << n_qubits if len(data_temp) < size: padding = np.zeros(size - len(data_temp)) data_temp = np.concatenate((data_temp, padding)) # 计算矩阵形状 r = n_qubits % 2 row = 1 << (n_qubits >> 1) col = 1 << ((n_qubits >> 1) + r) # 重塑为矩阵 eigen_matrix = data_temp.reshape((row, col), order='C') # 奇异值分解 U, S, Vh = np.linalg.svd(eigen_matrix, full_matrices=False) V = Vh # 确定截断长度 A = S length = 0 while length < len(A) and (A[length] >= A[0] * cutoff or length == 0): length += 1 A_cut = A[:length] PartU = U[:, :length] PartV = V[:length, :] # 分割量子比特 A_qubits_size = int(floor(n_qubits / 2)) + r A_qubits = qubits[:A_qubits_size] B_qubits = qubits[A_qubits_size:] bit = int(log2(length)) if length > 0 else 0 # 递归编码奇异值 if bit > 0 and len(B_qubits) >= bit: reg_tmp = B_qubits[:bit] A_cut_normalized = A_cut / np.linalg.norm(A_cut) _schmidt(circuit, reg_tmp, A_cut_normalized.tolist(), cutoff) # 应用 CNOT 门 for i in range(bit): if i < len(B_qubits) and i < len(A_qubits): circuit.cx(B_qubits[i], A_qubits[i]) # 应用旋转(简化处理) # 从 PartU 和 PartV 中提取旋转参数 for i in range(min(len(B_qubits), PartU.shape[1])): val = max(-1.0, min(1.0, PartU[0, i].real())) angle = 2 * acos(val) circuit.ry(angle, B_qubits[i]) for i in range(min(len(A_qubits), PartV.shape[0])): val = max(-1.0, min(1.0, PartV[i, 0].real())) angle = 2 * acos(val) circuit.ry(angle, A_qubits[i])
def _merging_procedure(state: Dict[str, complex], circuit: Circuit, reverse_q: List[int]) -> Dict[str, complex]: """ 合并程序 通过应用量子门来合并量子态。 参数: state: 状态字典 circuit: 量子电路 reverse_q: 反向的量子比特索引列表 返回: Dict: 合并后的状态 """ new_state: Dict[str, complex] = {} if not state: return new_state n_qubits = len(list(state.keys())[0]) prefix_length = n_qubits - 1 q_index_to_operate = reverse_q[prefix_length] # 按前缀分组 groups: Dict[str, Dict[str, complex]] = {} for key, amp in state.items(): prefix = key[:prefix_length] suffix = key[prefix_length:] if prefix not in groups: groups[prefix] = {'0': 0.0 + 0.0j, '1': 0.0 + 0.0j} groups[prefix][suffix] = amp # 处理每个前缀组 for prefix, amps in groups.items(): amp0 = amps['0'] amp1 = amps['1'] new_amp = sqrt(abs(amp0)**2 + abs(amp1)**2) # 跳过接近零的情况 if abs(new_amp) < 1e-14: continue # 计算相位 relative_phase = 0.0 if abs(amp0) > 1e-14: relative_phase = np.angle(amp1 / amp0) # 计算 RY 旋转角 ry_angle = 0.0 if abs(amp0) > 1e-14: ry_angle = 2 * acos(min(1.0, abs(amp0) / new_amp)) elif abs(amp1) > 1e-14: ry_angle = pi # 获取控制比特索引 control_qubits_indices = [reverse_q[i] for i in range(n_qubits) if i != prefix_length] # 应用旋转门 if not control_qubits_indices: circuit.ry(-ry_angle, q_index_to_operate) circuit.rz(-relative_phase, q_index_to_operate) else: # 应用受控旋转(简化处理) # 先应用控制的 X 门以匹配控制状态 for i, ctrl_idx in enumerate(control_qubits_indices): if prefix[i] == '1': circuit.x(ctrl_idx) # 应用旋转 circuit.ry(-ry_angle, q_index_to_operate) circuit.rz(-relative_phase, q_index_to_operate) # 恢复控制比特 for i, ctrl_idx in enumerate(control_qubits_indices): if prefix[i] == '1': circuit.x(ctrl_idx) new_state[prefix] = new_amp return new_state def compute_norm(data: Union[List[float], List[complex]]) -> float: """ 计算范数 参数: data: 数据列表 返回: float: L2 范数 """ total = 0.0 for item in data: if isinstance(item, complex): total += item.real**2 + item.imag**2 else: total += item**2 return sqrt(total)
[文档] def _complete_to_unitary(matrix: np.ndarray, target_num_qubits: int) -> np.ndarray: """ 完成矩阵为幺正矩阵(已弃用,仅保留以兼容) 此函数在 Janus 框架中不使用,因为我们不需要显式的幺正操作。 """ target_dim = 2**target_num_qubits rows, cols = matrix.shape if rows == target_dim and cols == target_dim: return matrix if rows == target_dim and cols < target_dim: # 使用 QR 分解补全矩阵 Q, _ = np.linalg.qr(matrix) if Q.shape != (target_dim, target_dim): # 如果 QR 返回的矩阵大小不对,进行调整 if Q.shape[0] == target_dim: return Q[:target_dim, :target_dim] return Q raise ValueError(f"Unexpected matrix shape {matrix.shape} for target_num_qubits {target_num_qubits}")
[文档] def _apply_unitary(circuit: Circuit, qubits: List[int], matrix: np.ndarray, cutoff: float = None): """ 应用幺正操作(已弃用,仅保留以兼容) 此函数在 Janus 框架中已被简化实现替代。 使用单比特旋转门来近似幺正操作。 """ # 使用 cutoff 参数(即使不使用,保持兼容性) _ = cutoff if not qubits: return # 简化处理:对矩阵进行简单的分解 target_num_qubits = len(qubits) # 对矩阵的对角元素应用旋转 for i in range(min(target_num_qubits, matrix.shape[0])): if i < matrix.shape[1]: val = max(-1.0, min(1.0, matrix[i, i].real)) angle = 2 * acos(val) circuit.ry(angle, qubits[i])