Baby-Step Giant-Step Homomorphic DFT

参考文献:

  1. [CT65] Cooley J W, Tukey J W. An algorithm for the machine calculation of complex Fourier series[J]. Mathematics of computation, 1965, 19(90): 297-301.
  2. [Shoup95] Shoup V. A new polynomial factorization algorithm and its implementation[J]. Journal of Symbolic Computation, 1995, 20(4): 363-397.
  3. [CHKKS18] Cheon J H, Han K, Kim A, et al. Bootstrapping for approximate homomorphic encryption[C]//Advances in Cryptology–EUROCRYPT 2018: 37th Annual International Conference on the Theory and Applications of Cryptographic Techniques, Tel Aviv, Israel, April 29-May 3, 2018 Proceedings, Part I 37. Springer International Publishing, 2018: 360-384.
  4. [CHH18] Cheon J H, Han K, Hhan M. Faster homomorphic discrete fourier transforms and improved fhe bootstrapping[J]. Cryptology ePrint Archive, 2018.
  5. Nussbaumer Transform 以及 Amortized FHEW bootstrapping
  6. Chimera:混合的 RLWE-FHE 方案
  7. 快速乘法技巧:Karatsuba, Toom, Good, Schonhage, Strassen, Nussbaumer
  8. Paterson-Stockmeyer 多项式求值算法

文章目录

  • Baby-Step Giant-Step
    • Shoup95
    • CT65
    • CHKKS18
  • Faster Homomorphic DFT
    • Sparse-Diagonal matrix Factorization
    • Radix-r
    • Hybrid method
    • Result

Baby-Step Giant-Step

Shoup95

文章 [Shoup95] 研究并实现了 BSGS factoring method,用于将单变元多项式分解为不可约因子。其中使用了 CRT 和 FFT 来表示多项式(比 GHS12 的 Doube-CRT 更早) ,并且实现了多项式的快速乘法、除法、逆元、平方、GCD 等等运算。

多项式分解可以分为三步,

  1. square-free factorization:将多项式分解为 f = ∏ i f i f = \prod_i f_i f=ifi,其中的 f i f_i fi 是平方自由的
  2. distinct-degree factorization:将平方自由多项式分解为 f i = ∏ j f i , j f_i = \prod_j f_{i,j} fi=jfi,j,其中的 f i , j f_{i,j} fi,j 是一些度数都为 j j j 的不可约因式的乘积
  3. equal-degree factorization:将不可约因式都是相同度数的平方自由多项式 f i , j f_{i,j} fi,j,分解为这些不可约多项式

主要步骤集中在 step 2,[Shoup95] 观察到事实:对于任意的非负整数 a , b ∈ Z + a,b \in \mathbb Z^+ a,bZ+,多项式 h a , b ( x ) = x p a − x p b ∈ G F ( p ) [ x ] h_{a,b}(x) = x^{p^a} - x^{p^b} \in GF(p)[x] ha,b(x)=xpaxpbGF(p)[x] 以所有的满足 deg ⁡ f ∣ ( a − b ) \deg f|(a-b) degf(ab) 的不可约多项式 f f f 为因式。

对于 deg ⁡ f ≤ n \deg f \le n degfn 的平方自由多项式,它的真因子度数不超过 n / 2 n/2 n/2,我们令 f d , 1 ≤ d ≤ n f_d,1 \le d \le n fd,1dn 是它的全部 d d d 次不可约因子的乘积。我们可以枚举全部的 1 ≤ a − b ≤ n 1\le a-b\le n 1abn,计算出 h a , b ( x ) h_{a,b}(x) ha,b(x),再计算 gcd ⁡ ( h a , b , f ) \gcd(h_{a,b},f) gcd(ha,b,f) 从而获得这些 f d f_d fd

[Shoup95] 使用 BSGS 算法来计算这些 h a , b h_{a,b} ha,b,设置真因子的度数上界 B B B,将它分为 B = l ⋅ m B=l \cdot m B=lm,Baby-Step 就是 { i : 1 ≤ i ≤ l } \{i:1 \le i \le l\} {i:1il},Giant-Step 就是 { l ⋅ j : 1 ≤ j ≤ m } \{l \cdot j:1 \le j \le m\} {lj:1jm}

在这里插入图片描述

然而,如果简单地直接计算 h i , H j h_i,H_j hi,Hj,上述算法依旧是不实用的。[Shoup95] 以迭代的方式计算它们: h i + 1 = h i ( h 1 ) ( m o d f ) h_{i+1} = h_i(h_1) \pmod f hi+1=hi(h1)(modf) H j + 1 = H j ( H 1 ) ( m o d f ) H_{j+1} = H_j(H_1) \pmod f Hj+1=Hj(H1)(modf),现在的问题是如何快速计算这些 modular-composition,形如 g ( h ) ( m o d f ) g(h) \pmod f g(h)(modf)

[Shoup95] 依旧采取 BSGS 算法(类似于 [PS73] 多项式求值算法),选取参数 t ≈ n t \approx \sqrt n tn ,预计算 h i ( m o d f ) , 0 ≤ i ≤ t h^i \pmod f, 0 \le i \le t hi(modf),0it 表格,那么:
g ( x ) = ∑ j = 0 n / t g j ( x ) ⋅ y j ,    y = x t ,    deg ⁡ g j < t g(x) = \sum_{j=0}^{n/t} g_j(x) \cdot y^j,\,\, y=x^t,\,\, \deg g_j < t g(x)=j=0n/tgj(x)yj,y=xt,deggj<t
于是,直接使用预计算表的内容,简单计算加法(以及数乘),
g j ( h ) = ∑ i = 0 t g j , i ⋅ h i ( m o d f ) g_j(h) = \sum_{i=0}^t g_{j,i} \cdot h^i \pmod f gj(h)=i=0tgj,ihi(modf)
接着,采取 Horner 法则,计算出
g ( x ) = ( ( g n / t ⋅ h t + ⋯   ) ⋅ h t + g 1 ) ⋅ h t + g 0 g(x) = ((g_{n/t} \cdot h^t + \cdots)\cdot h^t +g_1)\cdot h^t + g_0 g(x)=((gn/tht+)ht+g1)ht+g0
其中的多项式运算都是以 Double-CRT 方式计算的,总的复杂度为 O ( n 2.5 + n log ⁡ n log ⁡ log ⁡ n log ⁡ p ) O(n^{2.5}+n \log n \log\log n\log p) O(n2.5+nlognloglognlogp)

CT65

[CT65] 给出了递归形式的 DFT 分解,其实也是可以视为一种 BSGS 版本的 FFT 算法。DFT 公式为:
A j : = ∑ k = 0 N − 1 a k ⋅ ζ j k A_j := \sum_{k=0}^{N-1} a_k \cdot \zeta^{jk} Aj:=k=0N1akζjk
采取 BSGS 算法,分解为 N = N 1 ⋅ N 2 N=N_1 \cdot N_2 N=N1N2,设置索引
j : = N 1 ⋅ j 1 + j 0 ,    j 0 ∈ [ N 1 ] , j 1 ∈ [ N 2 ] k : = N 2 ⋅ k 1 + k 0 ,    k 0 ∈ [ N 2 ] , k 1 ∈ [ N 1 ] \begin{aligned} j &:= N_1 \cdot j_1 + j_0,\,\, j_0 \in [N_1], j_1 \in [N_2]\\ k &:= N_2 \cdot k_1 + k_0,\,\, k_0 \in [N_2], k_1 \in [N_1]\\ \end{aligned} jk:=N1j1+j0,j0[N1],j1[N2]:=N2k1+k0,k0[N2],k1[N1]
那么有
A j 1 , j 0 : = ∑ k 0 ∈ [ N 2 ] ∑ k 1 ∈ [ N 1 ] a k 1 , k 0 ⋅ ζ j k = ∑ k 0 ∈ [ N 2 ] ( ∑ k 1 ∈ [ N 1 ] a k 1 , k 0 ⋅ ζ N 2 j k 1 ) ⋅ ζ j k 0 = ∑ k 0 ∈ [ N 2 ] ( ∑ k 1 ∈ [ N 1 ] a k 1 , k 0 ⋅ ζ N 2 j k 1 ) ⋅ ζ j 0 k 0 ⋅ ζ N 1 j 1 k 0 \begin{aligned} A_{j_1,j_0} &:= \sum_{k_0 \in [N_2]} \sum_{k_1 \in [N_1]} a_{k_1,k_0} \cdot \zeta^{jk}\\ &= \sum_{k_0 \in [N_2]} \left(\sum_{k_1 \in [N_1]} a_{k_1,k_0} \cdot \zeta^{N_2jk_1}\right) \cdot \zeta^{jk_0}\\ &= \sum_{k_0 \in [N_2]} \left(\sum_{k_1 \in [N_1]} a_{k_1,k_0} \cdot \zeta^{N_2jk_1}\right) \cdot \zeta^{j_0k_0} \cdot \zeta^{N_1j_1k_0}\\ \end{aligned} Aj1,j0:=k0[N2]k1[N1]ak1,k0ζjk=k0[N2] k1[N1]ak1,k0ζN2jk1 ζjk0=k0[N2] k1[N1]ak1,k0ζN2jk1 ζj0k0ζN1j1k0
于是,将 a N a_N aN 按照行主序,排列为形状 N 1 × N 2 N_1 \times N_2 N1×N2 的矩阵 a N 1 × N 2 a_{N_1 \times N_2} aN1×N2

  1. 对于每一个 k 0 k_0 k0,利用形状 N 1 × N 1 N_1 \times N_1 N1×N1 的矩阵
    W 1 : = { ζ j 0 k 1 } j 0 , k 1 W_1:=\{\zeta^{j_0k_1}\}_{j_0,k_1} W1:={ζj0k1}j0,k1
    计算长度为 N 1 N_1 N1 的各个列矢 a k 0 a_{k_0} ak0NTT 变换(单位根为 { ζ N 1 j 0 , j 0 ∈ [ N 1 ] } \{\zeta_{N_1}^{j_0},j_0 \in [N_1]\} {ζN1j0,j0[N1]}),得到形状 N 1 × N 2 N_1 \times N_2 N1×N2 的矩阵
    W 1 × a N 1 × N 2 = { A j 0 , k 0 ′ : = ∑ k 1 ∈ [ N 1 ] a k 1 , k 0 ⋅ ζ N 2 j k 1 } j 0 , k 0 W_1 \times a_{N_1 \times N_2} = \left\{A_{j_0,k_0}' := \sum_{k_1 \in [N_1]} a_{k_1,k_0} \cdot \zeta^{N_2jk_1}\right\}_{j_0,k_0} W1×aN1×N2= Aj0,k0:=k1[N1]ak1,k0ζN2jk1 j0,k0

  2. 利用形状 N 1 × N 2 N_1 \times N_2 N1×N2 的矩阵
    W 2 : = { ζ j 0 k 0 } j 0 , k 0 W_2 := \{\zeta^{j_0k_0}\}_{j_0,k_0} W2:={ζj0k0}j0,k0
    对它做 Hadamard 乘积,扭曲矩阵 A ′ A' A 使得接下来的运算是标准 NTT(否则就需要恰当的扭曲后续 NTT 采用的单位根),此时的结果是形状 N 1 × N 2 N_1 \times N_2 N1×N2 的矩阵
    W 2 ⊙ A N 1 × N 2 ′ = { A j 0 , k 0 ′ ′ : = ζ j 0 k 0 ⋅ ∑ k 1 ∈ [ N 1 ] a k 1 , k 0 ⋅ ζ N 2 j k 1 } j 0 , k 0 W_2 \odot A_{N_1 \times N_2}' = \left\{A_{j_0,k_0}'' := \zeta^{j_0k_0} \cdot\sum_{k_1 \in [N_1]} a_{k_1,k_0} \cdot \zeta^{N_2jk_1}\right\}_{j_0,k_0} W2AN1×N2= Aj0,k0′′:=ζj0k0k1[N1]ak1,k0ζN2jk1 j0,k0

  3. 对于每一个 j 1 j_1 j1,利用形状 N 2 × N 2 N_2 \times N_2 N2×N2 的矩阵
    W 3 : = { ζ N 2 j 1 k 0 } j 1 , k 0 W_3 := \{\zeta_{N_2}^{j_1k_0}\}_{j_1,k_0} W3:={ζN2j1k0}j1,k0
    计算长度为 N 2 N_2 N2 的各个行矢 A j 0 ′ ′ A_{j_0}'' Aj0′′NTT 变换(单位根为 { ζ N 2 j 1 , j 1 ∈ [ N 2 ] } \{\zeta_{N_2}^{j_1},j_1 \in [N_2]\} {ζN2j1,j1[N2]}),得到形状 N 2 × N 1 N_2 \times N_1 N2×N1 的矩阵
    W 3 × ( A N 1 × N 2 ′ ′ ) T = { A j 1 , j 0 } j 1 , j 0 W_3 \times (A_{N_1 \times N_2}'')^T = \{A_{j_1,j_0}\}_{j_1,j_0} W3×(AN1×N2′′)T={Aj1,j0}j1,j0

对于形状 N 2 × N 1 N_2 \times N_1 N2×N1 的矩阵 A N 2 × N 1 A_{N_2 \times N_1} AN2×N1,按照行主序读取为 A N = N T T ( a N ) A_N = NTT(a_N) AN=NTT(aN)

总之, a N , A N a_N, A_N aN,AN 都按照行主序排列为矩阵(形状不同),那么有:
A N 2 × N 1 = W 3 × ( W 2 ⊙ ( W 1 × a N 1 × N 2 ) ) T A_{N_2 \times N_1} = W_3 \times \Big(W_2 \odot \big(W_1 \times a_{N_1 \times N_2}\big)\Big)^T AN2×N1=W3×(W2(W1×aN1×N2))T
其实,这个过程可以用 Nussbaumer Transform 的环同态表示
F [ x ] / ( x N − 1 ) ≅ ( F [ y ] / ( y N 1 − 1 ) ) [ x ] / ( x N 2 − y ) ≅ ( F [ y ] / ( y N 1 − 1 ) ) [ z ] / ( z N 2 − 1 ) \mathbb F[x]/(x^N-1) \cong \Big(\mathbb F[y]/(y^{N_1}-1)\Big)[x]/(x^{N_2}-y) \cong \Big(\mathbb F[y]/(y^{N_1}-1)\Big)[z]/(z^{N_2}-1) F[x]/(xN1)(F[y]/(yN11))[x]/(xN2y)(F[y]/(yN11))[z]/(zN21)

CHKKS18

[CHKKS18] 利用 SIMD 技术的 HadamardRotate 运算,实现同态的线性运算,它也采取了 BSGS 技巧。 我们默认 index 都是自动 ( m o d n ) \pmod n (modn) 的,基本符号:

  • 对于任意的线性变换 M ∈ C n × n M \in \mathbb C^{n \times n} MCn×n,简记 d i a g i ( M ) = [ M 0 , i , M 1 , i + 1 , ⋯   , M n , i + n ] diag_i(M) = [M_{0,i}, M_{1,i+1},\cdots,M_{n,i+n}] diagi(M)=[M0,i,M1,i+1,,Mn,i+n] 是第 i ∈ Z i \in \mathbb Z iZ 条对角线(可以是负数 − i -i i,就是第 n − i n-i ni 条对角线)
  • 对于任意的矢量 v ∈ C n v \in \mathbb C^{n} vCn,简记 r o t i ( v ) = [ v i , v i + 1 , ⋯   , v i + n − 1 ] rot_i(v) = [v_i,v_{i+1},\cdots,v_{i+n-1}] roti(v)=[vi,vi+1,,vi+n1] 是循环左移 i ∈ Z i \in \mathbb Z iZ 距离(可以是负数 − i -i i,循环右移 i i i 距离)

采取 BSGS 算法,分解 n = l × k n=l \times k n=l×k,线性变换可以表示为:

在这里插入图片描述

最优化时选取 k ≈ n k \approx \sqrt n kn ,计算复杂度为: O ( n ) O(\sqrt n) O(n ) 次 Rotate 运算(关于 v v v 的密文), O ( n ) O(n) O(n) 次 Hadamard 运算。对于公开的固定矩阵 M M M,其中的 r o t − k i ( d i a g k i + j ( M ) ) rot_{-ki}(diag_{ki+j}(M)) rotki(diagki+j(M)) 是预计算的常数多项式(用 InvDFT 编码),它不需要 CKKS 密文下的 Rotate 运算。

在这里插入图片描述

[CHKKS18] 将上述的线性变换转换到 slot-packing CKKS 下同态计算,并利用它来实现 coeff-to-slot,从而批处理 CKKS 自举。用到的线性变换是 DFT 和 InvDFT,[CHKKS18] 将它们视为通用的线性变换,利用这个同态矩阵乘法来实现。

不过,对于公开的线性变换,直接使用 TFHE 提出的那种 Functional Key-Switch,效率要高得多。对于秘密的线性变换,TFHE 也提出了根据 M M M 来构造 KS-Key for M,从而支持 Private Functional Key-Switch。但是如果没有提供这种特殊的 KS-Key for M,而是将 M M M 加密为一般的 CKKS 密文,那么就只能使用上面的同态矩阵乘法,利用 Rotate 和 Hadamard 慢慢计算。

Faster Homomorphic DFT

[CHH18] 观察到 DFT 矩阵拥有稀疏分解(也就是蝴蝶算法),因此对于这种特殊的线性变换,可以比 [CHKKS18] 的通用矩阵乘法,复杂度降低一个 n n n 因子。它可以应用在 [CHKKS18] 的 CKKS 批自举上,计算速度提高了数百倍。

Sparse-Diagonal matrix Factorization

[CHH18] 它说根据 [CT65] 的递归式 FFT,可以将 DFT 矩阵做如下的稀疏分解:

在这里插入图片描述

继续迭代地分解前者,最终可以获得:

在这里插入图片描述

容易看出, d i a g i ( D 2 i ( n ) ) ≠ 0 ⃗    ⟺    k ∈ { 0 , ± n 2 i } diag_i(D_{2^i}^{(n)}) \neq \vec 0 \iff k\in \{0,\pm \dfrac{n}{2^i}\} diagi(D2i(n))=0 k{0,±2in},只有 3 条对角线是非零的,因此采取斜线乘法来计算是十分高效的,
D 2 i ( n ) ⋅ v = ∑ k ∈ { 0 , ± n / 2 i } d i a g k ( D 2 i ( n ) ) ⊙ r o t k ( v ) D_{2^i}^{(n)} \cdot v = \sum_{k\in \{0,\pm n/2^i\}} diag_k(D_{2^i}^{(n)}) \odot rot_{k}(v) D2i(n)v=k{0,±n/2i}diagk(D2i(n))rotk(v)
算法为:

在这里插入图片描述

注意到 r o t 0 ( v ) = v rot_0(v)=v rot0(v)=v 不必计算,对于特殊情况 i = 1 i=1 i=1 根据 r o t n / 2 i ( v ) = r o t − n / 2 i ( v ) rot_{n/2^i}(v)=rot_{-n/2^i}(v) rotn/2i(v)=rotn/2i(v) 可节约计算。最终, D F T ⋅ v = ∏ i = 0 log ⁡ 2 n D 2 i ( n ) ⋅ v DFT \cdot v = \prod_{i=0}^{\log_2 n} D_{2^i}^{(n)} \cdot v DFTv=i=0log2nD2i(n)v 的复杂度为 O ( log ⁡ 2 n ) O(\log_2 n) O(log2n)

对于逆变换,由于 DFT 的逆矩阵恰好是其厄米,

在这里插入图片描述
因此很明显 CT 蝴蝶和上述的 GS 蝴蝶一样,也是稀疏对角的,从而也存在类似的快速矩阵乘法。

Radix-r

不过虽然上述的操作次数很小,但是计算深度为 log ⁡ 2 ( n ) \log_2(n) log2(n),需要多层 Rotate 和 CMult 串行,可能导致噪声控制的问题。我们可以合并某些连续的 k k k 个矩阵,那么深度就降低为 log ⁡ r n , r = 2 k \log_r n, r=2^k logrn,r=2k,代价是计算复杂度的上升。

在这里插入图片描述

根据对角阵的乘法性质:两个对角阵的乘积,依旧是对角阵,
d i a g i ( a ) ⋅ d i a g j ( b ) = d i a g i + j ( a ⊙ r o t i ( b ) ) diag_i(a) \cdot diag_j(b) = diag_{i+j}(a \odot rot_i(b)) diagi(a)diagj(b)=diagi+j(aroti(b))
可以证明,连续 k k k 个矩阵的合并
D k , s = D 2 s + k ( n ) ⋯ D 2 s + 2 ( n ) ⋅ D 2 s + 1 ( n ) D_{k,s} = D_{2^{s+k}}^{(n)} \cdots D_{2^{s+2}}^{(n)} \cdot D_{2^{s+1}}^{(n)} Dk,s=D2s+k(n)D2s+2(n)D2s+1(n)
的非零对角线的索引为
e 1 ⋅ n 2 s + 1 + e 2 ⋅ n 2 s + 2 + ⋯ + e t ⋅ n 2 s + k e_1 \cdot \dfrac{n}{2^{s+1}} + e_2 \cdot \dfrac{n}{2^{s+2}} + \cdots + e_t \cdot \dfrac{n}{2^{s+k}} e12s+1n+e22s+2n++et2s+kn
其中 e i ∈ { 0 , ± 1 } e_i \in \{0,\pm1\} ei{0,±1},易知这些 index 都是 n 2 s + k \dfrac{n}{2^{s+k}} 2s+kn 的倍数,绝对值上界为 ( 2 k − 1 ) n 2 s + k \dfrac{(2^k-1)n}{2^{s+k}} 2s+k(2k1)n,这些 index 的个数至多为 2 k + 1 − 1 2^{k+1}-1 2k+11

此时的 DFT 的复杂度为: O ( r log ⁡ r n ) O(r \log_r n) O(rlogrn) 次 Rotate 和 Hadamard,深度为 O ( log ⁡ r n ) O(\log_r n) O(logrn)

Hybrid method

由于上述分解的非零 index 呈现算术级数(都是 n 2 s + k \dfrac{n}{2^{s+k}} 2s+kn 的倍数),因此可以采取 BSGS 技巧,提取出公共的计算部分,进一步提高计算效率。

在这里插入图片描述

最优化设置 k 2 ≈ t k_2 \approx \sqrt t k2t ,此时 DFT 的复杂度为:依旧 O ( r log ⁡ r n ) O(r \log_r n) O(rlogrn) 次 Hadamard,但是只需 O ( r log ⁡ r n ) O(\sqrt r \log_r n) O(r logrn) 次 Ratate(但 r r r 是常数),深度也还是 O ( log ⁡ r n ) O(\log_r n) O(logrn)

Result

同态 DFT 的执行时间:秒的量级

在这里插入图片描述

CKKS 自举时间:2 分钟延迟,均摊 4 毫秒

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/196350.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode Hot100 84.柱状图中最大的矩形

题目&#xff1a; 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 方法&#xff1a; 代码&#xff1a; class Solution {public int largestRectang…

WIFI HaLow技术引领智能互联,打破通信限制

在过去十年里&#xff0c;WIFI技术已在家庭和企业中建立起了庞大的网络&#xff0c;连接了数十亿智能互联设备&#xff0c;促进了信息的迅速传递。然而&#xff0c;当前的WIFI标准存在一些挑战&#xff0c;包括协议范围的限制和整体功能的受限&#xff0c;导致在较远距离进行通…

工艺系统所管理数字化实践

摘要 本文介绍了上海核工程设计研究院在数字化转型方面的实践&#xff0c;包括业务数字化和管理数字化两个方面。业务数字化方面&#xff0c;该院通过开发小工具改进工作流程。管理数字化方面&#xff0c;该院采用零代码平台集中管理管道力学信息相关模型和数据&#xff0c;并…

写了个数据查询为空的 Bug,你会怎么办?

大家在开发时&#xff0c;遇到的一个典型的 Bug 就是&#xff1a;为什么数据查询为空&#xff1f; 对应的现象就是&#xff1a;前端展示不出数据、或者后端查询到的数据列表为空。 遇到此类问题&#xff0c;其实是有经典的解决套路的&#xff0c;下面鱼皮给大家分享如何高效解决…

Python基础语法之学习print()函数

Python基础语法之学习print函数 1、代码2、效果 1、代码 print("Hello World") print("Hello World1","Hello World2") print("Hello World1\n","Hello World2") print("Hello World",end" 默认结束符是行号…

2.ORB-SLAM3中如何从二进制文件中加载多地图、关键帧、地图点等数据结构

目录 1 为什么保存&加载(视觉)地图 1.1 加载多地图的主函数 1.2 加载各个地图 Atlas::PostLoad 1.3 加载关键帧及地图点Map::PostLoad 1.4 恢复地图点信息 MapPoint::PostLoad 1.5 恢复关键帧信息KeyFrame::PostLoad 1 为什么保存&加载(视觉)地图 因为我们要去做导…

如何写好产品软文?软文撰写指南!

针对某种产品写一篇软文&#xff0c;我们应该怎么构思&#xff0c;怎么提笔去写&#xff0c;怎么写得让用户认可我们的产品&#xff0c;并产生消费的冲动&#xff0c;这是需要讲究技巧的。 今天伯乐网络传媒来给大家分享三个步骤&#xff0c;教你轻轻松松撰写一篇爆文&#xf…

记一次域控迁移并升级

域环境&#xff1a; 域控级别&#xff1a;windows server2008R2 主域控&#xff1a;win server 2008R2 辅域控&#xff1a;win server 2016 需求&#xff1a;新购一台win server 2022&#xff0c;需要将主域控迁移到新服务器中&#xff0c;并升级域控级别为最新 检查域控 …

什么软件能去水印?分享三款实用去水印工具

什么软件能去水印&#xff1f;去水印你还在担心会损伤画质或处理不干净&#xff1f;今天分享三款好用的图片去水印工具&#xff0c;手机和电脑软件都有&#xff0c;操作简单&#xff0c;去水印速度快&#xff0c;而且去水印后几乎看不水印痕迹&#xff01; 1、水印云 一款图片编…

贪心算法策略实现

贪心算法 贪心算法&#xff1a;基于某种情况进行一个排序。 贪心算法得到的是优良解&#xff0c;而非全局最优解。需要证明局部最优解 全局最优解 经典贪心算法 —— 会议问题 对于这个问题 &#xff0c;我们提出贪心策略&#xff1a; 策略1&#xff1a;按照会议的持续时间长…

函数声明与函数表达式

函数声明 一个标准的函数声明&#xff0c;由关键字function 、函数名、形参和代码块组成。 有名字的函数又叫具名函数。 举个例子&#xff1a; function quack(num) { for (var i 0; i < num; i) {console.log("Quack!")} } quack(3)函数表达式 函数没有名称…

前端代码提交gitlab出现语法错误无法提交

错误 找到项目里面的.git文件夹 下面有一个hooks 删除pre-commit文件&#xff08;git语法校验代码&#xff09;

人工智能即将彻底改变你使用计算机的方式

文章目录 每个人的私人助理“Clippy 是一个机器人&#xff0c;而不是特工。”卫生保健“一半需要心理健康护理的美国退伍军人没有得到治疗。”教育生产率娱乐和购物科技行业的冲击波技术挑战隐私和其他重大问题 今天我仍然像保罗艾伦和我创办微软时一样热爱软件。但是&#xff…

Nodejs+Vue校园餐厅外卖订餐点餐系统 PHP高校食堂 微信小程序_0u4hl 多商家

对于校园订餐小程序将是又一个传统管理到智能化信息管理的改革&#xff0c;对于传统的校园订餐管理&#xff0c;所包括的信息内容比较多&#xff0c;对于用户想要对这些数据进行管理维护需要花费很大的时间信息&#xff0c;而且对于数据的存储比较麻烦&#xff0c;想要查找某一…

Elasticsearch:向量搜索 (kNN) 实施指南 - API 版

作者&#xff1a;Jeff Vestal 本指南重点介绍通过 HTTP 或 Python 使用 Elasticsearch API 设置 Elasticsearch 以进行近似 k 最近邻 (kNN) 搜索。 对于主要使用 Kibana 或希望通过 UI 进行测试的用户&#xff0c;请访问使用 Elastic 爬虫的语义搜索入门指南。你也可以参考文章…

【嵌入式】开源shell命令行的移植和使用(2)——letter-shell

目录 一 背景说明 二 移植准备 三 移植过程 四 自定义命令 五 实际使用 一 背景说明 之前使用过一款开源shell工具 nr_micro_shell &#xff08;【嵌入式】开源shell命令行的移植和使用&#xff08;1&#xff09;——nr_micro_shell-CSDN博客&#xff09;&#xff0c;感觉…

【Linux】了解进程的基础知识

进程 1. 进程的概念1.1 进程的理解1.2 Linux下的进程1.3 查看进程属性1.4 getpid和getppid 2. 创建进程3. 进程状态4. 进程优先级5. 进程切换6. 环境变量7. 本地变量与内建命令 1. 进程的概念 一个已经加载到内存中的程序&#xff0c;叫做进程&#xff08;也叫任务&#xff09…

echarts点击事件

有这么个需求要点击叶片的时候跳转页面 代码&#xff1a;点击之后 报错了 解决办法 1、使用箭头函数&#xff08;箭头函数没有自己的 this&#xff0c;所以在箭头函数中使用 this 时&#xff0c;其指向与外层作用域相同。&#xff09;或者使用闭包来解决上下文的问题。 2、使…

QT基础实践之QQ登录界面

文章目录 QQ登录界面源码分享演示图代码分析 QQ登录界面 源码分享 链接&#xff1a;https://pan.baidu.com/s/1v_J4WQjZoSAoMrIpx88PbA 提取码&#xff1a;qwer 记得把图片放入Debug文件 演示图 代码分析 已注释 较为详细 widget.h #ifndef WIDGET_H #define WIDGET_H#inc…

Leetcode98 验证二叉搜索树

题意理解&#xff1a; 首先明确二叉树的定义&#xff0c;对于所有节点&#xff0c;根节点的值大于左子树所有节点的值&#xff0c;小于右子树所有节点的值。 注意一个误区&#xff1a; 根节点简单和左孩子&#xff0c;右孩子比大小是不够的&#xff0c;要和子树比&#xff0c;…