LSH算法:高效相似性搜索的原理与Python实现II

image.png

 局部敏感哈希(LSH)是一种高效的近似相似性搜索技术,广泛应用于需要处理大规模数据集的场景。在当今数据驱动的世界中,高效的相似性搜索算法对于维持业务运营至关重要,它们是许多顶尖公司技术堆栈的核心。

相似性搜索面临的主要挑战在于处理庞大的数据规模。许多企业每天都要处理从百万到数十亿不等的数据点。例如,面对一亿个数据点,逐个进行比较显然是不切实际的。

更进一步,企业的需求远不止单次搜索。以谷歌为例,它每分钟处理的搜索请求超过380万次。这种高频率的搜索需求,再加上数据点的规模,构成了一个巨大的技术挑战。

此外,还没有涉及到数据的维度问题或相似性函数的复杂性。在这些因素的共同作用下,对于大型数据集进行全面的搜索变得不可行。

那么,如何在如此难以想象的大规模数据集上进行有效搜索呢?答案就是近似搜索。通过近似搜索,不必对每一对数据点进行详尽的比较。相反,采用LSH技术,它通过近似方法筛选出潜在的匹配项,从而大幅减少了需要进行详尽比较的数据点数量。

通过这种方式,LSH不仅提高了搜索效率,还保持了搜索结果的准确性,使其成为大规模数据集相似性搜索的理想解决方案。

局部敏感哈希(LSH)

局部敏感哈希(LSH)是一种广泛使用的近似最近邻搜索(ANNS)方法。它依赖于一种特殊的哈希函数,这种函数设计用来将相似的项目映射到同一个哈希桶中。面对大规模数据集,LSH通过哈希函数将项目分配到不同的桶,从而简化搜索过程。

LSH算法的一个关键特点是它与常规哈希函数不同。传统哈希函数致力于最小化哈希冲突,而LSH算法则有意增加哈希冲突的概率,目的是将相似的项目聚集在一起。

image.png

哈希函数对比:上图展示了两种哈希函数的效果。顶部(蓝色)的哈希函数致力于最小化哈希冲突,而底部(品红色)的哈希函数则是LSH使用的,它旨在最大化相似项之间的哈希冲突。

在LSH中,相似的向量倾向于产生相同的哈希值,并因此被分到同一个桶里。相对地,不相似的向量则希望不会被分到同一个桶中。

使用LSH进行搜索

LSH搜索过程包括以下三个步骤:

  1. 索引向量:首先,将所有向量通过LSH哈希函数处理,并将它们索引到对应的哈希桶中。
  2. 哈希查询向量:当引入一个查询向量时,使用相同的LSH哈希函数对其进行处理。
  3. 桶比较:然后,通过比较汉明距离来识别查询向量与哪些哈希桶中的向量最近。

这些步骤构成了LSH方法论的基础,将在后续的文章中对这些概念进行更深入的探讨和详细说明。

近似效果

在深入研究LSH技术之前,重要的是要认识到,通过将向量映射到低分辨率的哈希向量中,实际上是在进行一种近似处理。这种方法意味着搜索过程可能不会详尽无遗地比较每个向量,因此预期搜索的精确度会有所降低。

image.png

将可能非常大的密集向量压缩成高度压缩的二进制向量,以实现更快的搜索速度。虽然这种压缩牺牲了一定的搜索质量,但它显著提高了搜索效率。

方法选择

LSH有多种实现方式,每种方法使用不同的哈希构建技术和距离或相似度度量。在这里不深入细节,因为不同的版本适用于不同的应用场景。

最受欢迎的两种LSH实现方法是:

  • 文档分片、MinHashing和带状LSH:这是一种较为传统的LSH方法,适用于特定类型的数据集和查询。
  • 随机超平面与点积和汉明距离:这种方法使用随机超平面来构建哈希函数,并通过点积和汉明距离来衡量向量间的相似性。

本文将专注于介绍随机超平面方法,它不仅更常用,而且在多个流行库中得到了实现,例如Faiss。这种方法因其高效性和易于实现的特点,在工业界和学术界都受到了广泛的关注。

随机超平面(Random Hyperplanes)

随机超平面方法,尽管听起来简单,实际上是一种高效的技术,用于在高维空间中进行近似最近邻搜索。这种方法可能难以理解,但通过以下示例,将深入探讨其工作原理。

这里使用Sift1M数据集进行示例。假设我们有一个查询向量xq,目标是从数组xb中识别出前k个最近邻。

image.png

返回查询向量xq的三个最近邻

创建超平面

在随机超平面方法中,通过构建超平面来分割数据点。每个超平面由一个法向量定义,数据点根据与法向量的点积结果被分配为0或1。

image.png

位于超平面正侧的数据点分配值1,为负侧的数据点分配值0

确定数据点位于超平面哪一侧的关键在于超平面的法向量。点积的结果告诉数据点位于超平面的哪一侧。如果两个向量方向相同,点积结果为正。如果它们方向不同,结果为负。

image.png

当超平面法向量与另一个向量产生 +ve 点积时,可以将该向量视为位于超平面前面。对于产生 -ve 点积的向量来说,情况正好相反

在两个向量完全垂直(位于超平面边缘)的极少数情况下,点积为0——将这种情况归入负方向向量。

单个二进制值并不能告诉太多关于向量相似性的信息,但当添加更多超平面时,编码的信息量会迅速增加。

image.png

添加更多超平面来增加二进制向量中存储的位置信息量。

通过使用这些超平面将向量投影到低维空间中,产生新的哈希向量。

在上图中,使用了两个超平面,实际上可能需要更多——这个特性通过nbits参数定义。如果使用四个超平面,通过将nbits设置为4。

在Python中创建超平面的法向量。

 

python

复制代码

nbits = 4 # 超平面的数量 d = 2 # 向量的维度 import numpy as np # 创建一组随机法向量 plane_norms = np.random.rand(nbits, d) - .5 plane_norms

 

lua

复制代码

array([[-0.26623211, 0.34055181], [ 0.3388499 , -0.33368453], [ 0.34768572, -0.37184437], [-0.11170635, -0.0242341 ]])

通过 np.random.rand 创建了一组 0 → 1 范围内的随机值。然后添加-.5使数组值以原点 (0, 0) 为中心。可视化这些向量:

image.png

定义超平面位置的法向量,均以原点 (0, 0) 为中心

哈希向量

给定几个向量,可以使用这些法向量来计算它们的哈希值。

 

python

复制代码

a = np.asarray([1, 2]) b = np.asarray([2, 1]) c = np.asarray([3, 1]) # 计算点积 a_dot = np.dot(a, plane_norms.T) b_dot = np.dot(b, plane_norms.T) c_dot = np.dot(c, plane_norms.T) a_dot # array([ 0.41487151, -0.32851916, -0.39600301, -0.16017455]) a_dot = a_dot > 0 b_dot = b_dot > 0 c_dot = c_dot > 0 a_dot # array([ True, False, False, False]) # 将点积结果转换为二进制值 a_dot = a_dot.astype(int) b_dot = b_dot.astype(int) c_dot = c_dot.astype(int) a_dot # array([1, 0, 0, 0]) b_dot # array([0, 1, 1, 0]) c_dot # array([0, 1, 1, 0])

再次可视化,得到了三个向量 a、b 和 c,以及四个超平面(垂直于它们各自的法向量)。分别取 +ve 和 -ve 点积值得出:

image.png

0表示矢量位于平面后面(-ve 点积),1表示矢量位于平面前面(+ve 点积),组合起来创建二进制向量

LSH使用哈希向量来创建桶,每个桶包含具有相同哈希值的向量。

 

python

复制代码

vectors = [a_dot, b_dot, c_dot] buckets = {} i = 0 for i in range(len(vectors)): hash_str = ''.join(vectors[i].astype(str)) if hash_str not in buckets.keys(): buckets[hash_str] = [] buckets[hash_str].append(i) print(buckets) # {'1000': [0], '0110': [1, 2]}

现在搜索过程中,使用查询向量0111的哈希值来快速定位到相关的桶,然后通过比较汉明距离来找到最近的匹配。

使用这个向量,与LSH索引中的每个桶进行比较——在这个例子中只有两个值——1000和0110。使用汉明距离找到最近的匹配,这实际上是0110。

image.png

汉明距离,第一个两个向量之间有四个不匹配,汉明距离为4,接下来的两个只包含一个不匹配,汉明距离为1

使用LSH进行近似搜索意味着可能会牺牲一些搜索质量,但这是换取速度的代价。通过分组到桶中,显著减少了搜索所需的计算量。

平衡质量与速度

在相似性搜索中,一个关键的挑战是在搜索质量和速度之间找到合适的平衡点。

质量与速度的平衡

以我们的小规模示例为起点,注意到随机投影可能导致一些向量难以区分,例如,三个向量中的两个被映射到了相同的哈希值。现在,设想将这种情况放大到一个包含一百万个向量的大型数据集。

当引入查询向量xq并计算其哈希值(例如0111)时,发现它与两个桶(10000110)的汉明距离非常短。这种方法的速度非常快,因为它只需要两次距离计算就完成了搜索,但准确性却大大降低,因为可能返回了大约70万个哈希值为0110的样本。

桶的数量

在现实中,如果使用nbits值为4,将得到16个可能的桶:

 

python

复制代码

nbits = 4 # 计算nbits值的二进制组合数 1 << nbits # 16 # 打印给定nbits值的所有可能桶 for i in range(1 << nbits): # 获取整数的二进制表示,并格式化为nbits位 b = bin(i)[2:] b = '0' * (nbits - len(b)) + b print(b, end=' | ')

 

yaml

复制代码

0000 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 | 1000 | 1001 | 1010 | 1011 | 1100 | 1101 | 1110 | 1111 |

即使有16个桶,一百万个向量被分成的桶数量仍然很少,导致每个桶内的样本非常不精确。

提高分辨率

为了提高搜索质量,可以通过增加超平面的数量来增加分辨率。更多的超平面意味着更高的分辨率二进制向量,从而产生更精确的向量表示。 通过nbits值来控制这种分辨率。一个更高的nbits值通过增加哈希向量的分辨率来提高搜索质量,但同时也可能增加搜索的计算成本。

image.png

增加nbits参数会增加用于构建二进制向量表示的超平面的数量

 

python

复制代码

for nbits in [2, 4, 8, 16]: print(f"nbits: {nbits}, buckets: {1 << nbits}")

 

yaml

复制代码

nbits: 2, buckets: 4 nbits: 4, buckets: 16 nbits: 8, buckets: 256 nbits: 16, buckets: 65536

通过调整nbits值,可以在搜索质量和速度之间进行权衡。在实际应用中,选择合适的nbits值是实现高效相似性搜索的关键。

Faiss中的LSH

回顾Faiss

Faiss(Facebook AI Similarity Search)是一个开源框架,专门用于高效实现相似性搜索。它提供了多种索引类型,包括IndexLSH,这是之前讨论过的局部敏感哈希(LSH)的高效实现。

初始化LSH索引

在Faiss中初始化LSH索引并添加数据集的示例代码如下:

 

python

复制代码

import faiss d = wb.shape[1] # 向量维度 nbits = 4 # 控制哈希向量的分辨率 # 初始化LSH索引 index = faiss.IndexLSH(d, nbits) # 添加数据集 index.add(wb)

执行搜索

一旦索引准备好,可以使用index.search(xq, k)方法进行搜索,其中xq是查询向量,k是希望返回的最近匹配数量。

 

python

复制代码

xq0 = xq[0].reshape(1, d) # 查询向量 # 搜索k个最近邻 D, I = index.search(xq0, k=10) # 返回最近邻的索引和距离 print("Indexes:", I) # 索引位置 print("Distances:", D) # 距离

测量性能

使用返回的索引,可以从数据集中检索原始向量,并计算它们与查询向量之间的余弦相似度。

 

python

复制代码

# 检索原始向量 retrieved_vectors = wb[I[0]] # 计算余弦相似度 cosine_sim = cosine_similarity(retrieved_vectors, xq0) print("Cosine Similarity:", cosine_sim)

 

ini

复制代码

array([[0.7344476 ], [0.6316513 ], [0.6995599 ], [0.20448919], [0.3054034 ], [0.25432232], [0.30497947], [0.341374 ], [0.6914262 ], [0.26704744]], dtype=float32)

从那些原始向量中,可以看到LSH索引是否返回了相关结果。通过测量查询向量xq0与前k个匹配之间的余弦相似性来进行这一操作。这个索引中有向量应该返回大约0.8的相似度分数,但返回的向量相似度分数仅为0.2,反映出性能低下。

诊断性能问题

如果返回的相似度分数较低,需要诊断性能问题。nbits值决定了索引中潜在桶的数量。如果nbits设置得太低,可能导致大量向量被分配到少数几个桶中,从而降低搜索质量。 如果尝试将1M个向量塞进只有16个哈希桶中,每个桶很可能包含10-100K+个向量。 所以,当哈希搜索查询时,它完美地匹配了这16个桶中的一个——但是索引无法区分被塞进那个单个桶中的大量向量——它们都有相同的哈希向量。可以通过检查距离D来确认这一点:

 

python

复制代码

print(D) # array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]], dtype=float32)

返回每个项目的完美距离分数为零,汉明距离只有在完美匹配时才能为零——这意味着所有的这些哈希向量必须是相同的。 如果所有的这些向量都返回完美匹配,它们必须都有相同的哈希值。因此,上述生成的索引无法区分它们——就LSH索引而言,它们都共享相同的位置。 如果增加k直到返回一个非零的距离值,应该能够推断出有多少个向量被分桶了这个相同的哈希码。

 

python

复制代码

k = 100 xq0 = xq[0].reshape(1, d) while True: D, I = index.search(xq0, k=k) if D.any() != 0: print(k) break k += 100 print(D) print(D[:, 172039:172041])

 

lua

复制代码

172100 array([[0., 0., 0., ..., 1., 1., 1.]], dtype=float32) array([[0., 1.]], dtype=float32)

一个包含172,039个向量的单个桶,这意味着是在从这172K个向量中随机选择前k个值。显然,需要减少桶的大小。 对于1M个样本,哪个nbits值有足够的桶以实现向量的更稀疏分布,通过计算平均值进行估计:

 

python

复制代码

for nbits in [2, 4, 8, 16, 24, 32]: buckets = 1 << nbits print(f"nbits == {nbits}") print(f"{wb.shape[0]} / {buckets} = {wb.shape[0]/buckets}")

 

ini

复制代码

nbits == 2 1000000 / 4 = 250000.0 nbits == 4 1000000 / 16 = 62500.0 nbits == 8 1000000 / 256 = 3906.25 nbits == 16 1000000 / 65536 = 15.2587890625 nbits == 24 1000000 / 16777216 = 0.059604644775390625 nbits == 32 1000000 / 4294967296 = 0.00023283064365386963

使用nbits值为16时,仍然在每个桶中得到大约15.25个向量——这看起来比实际情况要好。必须考虑到,有些桶会比其他桶大得多,因为不同的区域会包含更多的向量。 实际上,nbits值为24和32可能是实现真正有效桶大小的转折点。

 

python

复制代码

xq0 = xq[0].reshape(1, d) k = 100 for nbits in [2, 4, 8, 16, 24, 32]: index = faiss.IndexLSH(d, nbits) index.add(wb) D, I = index.search(xq0, k=k) cos = cosine_similarity(wb[I[0]], xq0) print(np.mean(cos))

 

复制代码

0.5424448 0.560827 0.6372647 0.6676912 0.7162514 0.7048228

看起来估计是正确的——前100个向量的整体相似度在每个nbits值增加之前突然上升,在𝑛𝑏𝑖𝑡𝑠==24nbits==24点之前稳定下来。

image.png

随着nbits值增加向量分辨率,结果将变得更加精确——可以看到更大的nbits值导致结果中余弦相似度更高。

提取二进制向量

Faiss允许提取向量的二进制表示,这有助于直接分析桶中的向量分布。

 

python

复制代码

# 提取二进制代码 arr = faiss.vector_to_array(index.codes) arr # array([ 5, 12, 5, ..., 15, 13, 12], dtype=uint8) arr.shape # (1000000,) # 将整数转换为二进制向量格式 (((arr[:, None] & (1 << np.arange(nbits)))) > 0).astype(int)

 

css

复制代码

array([[1, 0, 1, 0], [0, 0, 1, 1], [1, 0, 1, 0], ..., [1, 1, 1, 1], [1, 0, 1, 1], [0, 0, 1, 1]])

通过这个,可以可视化这些16个桶中向量的分布——显示使用最多的桶和一些空的桶。

image.png

当nbits == 4时,不同桶中向量的分布

通过调整nbits值,可以在搜索质量和速度之间找到平衡。在Faiss中使用LSH时,理解不同参数如何影响性能对于优化搜索结果至关重要。

使用LSH

局部敏感哈希(LSH)提供了一种快速的索引机制,尽管它可能不如平面(Flat)索引准确。在Sift1M数据集上,通过逐渐增加数据集的大小,发现在nbits值设定为768时,可以实现最佳的召回率——尽管这需要牺牲一些搜索时间来获得更高的召回率。

image.png

召回率与索引向量数量的关系:召回率是衡量搜索结果与使用IndexFlatL2进行详尽搜索的匹配程度的指标。

值得注意的是,即使使用nbits值为768,LSH的搜索速度也只是略快于平面Flat索引。

image.png

搜索时间的比较:展示了不同索引大小和nbits值下,IndexFlatL2的搜索时间相对于其自身在不同条件下的变化。

在实际应用中,一个更现实的召回率目标是接近40%,同时保持合理的速度提升。数据集的大小和维度对LSH的性能有显著影响。随着维度的增加,为了保持准确性,可能需要使用更高的nbits值,但这仍有可能实现更快的搜索速度。关键在于为每个用例和数据集找到正确的平衡点。向量相似性搜索是一个多样化的领域,Flat索引和LSH只是众多选择中的两种。选择正确的索引策略需要结合实验和专业知识。

在相似性搜索中,始终需要在不同的索引选项和参数设置之间寻找最佳解决方案,这是一种平衡的行为。

总结

选择正确的相似性搜索算法取决于多种因素,包括数据集的大小和维度、搜索性能的要求,以及准确性的容忍度。LSH是众多工具中的一个,它在某些情况下表现出色,但也可能需要与其他技术相结合以达到最佳效果。除了LSH,还有许多其他算法适合于高效的相似性搜索,例如:

  • HNSW(Hierarchical Navigable Small World):提供在大规模数据集上进行近似最近邻搜索的能力。
  • IVF(Inverted File Index):通过聚类和索引减少搜索范围,提高了搜索速度。
  • PQ(Product Quantization):一种量化技术,通过将向量空间划分为较小的子空间来加速搜索。

鼓励读者根据本文提供的信息,进行实验和探索,以找到最适合自己特定需求的搜索算法。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

去掉window11设备和驱动器中的百度网盘图标

背景 window系统设备驱动器中显示百度网盘图标&#xff0c;个人强迫症&#xff0c;要去掉&#xff01;&#xff01;&#xff01; 去掉window11->设备和驱动器->百度网盘 的图标 登录百度网盘点击”同步“ 点击设置 在基本设置里面去掉勾选“在我的电脑中显示百度网盘…

麒麟桌面操作系统上使用命令行添加软件图标到任务栏

原文链接&#xff1a;麒麟桌面操作系统上使用命令行添加软件图标到任务栏 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇在麒麟桌面操作系统上使用命令行添加软件图标到任务栏的文章。通过命令行添加软件图标到任务栏&#xff0c;可以快速、便捷地将常用的软件固定…

当大模型开始「考上」一本

参加 2024 河南高考&#xff0c;豆包和文心 4.0 过了一本线&#xff0c;但比 GPT-4o 还差点。 今天的大模型&#xff0c;智力水平到底如何&#xff1f; 2024 年高考陆续出分&#xff0c;我们想要解开这个过去一年普罗大众一直争论不休的话题。高考是衡量人类智力和学识水平的…

聚力教研共成长!思腾合力携手昇腾AI打造人工智能云平台

高校作为科研和创新的前沿阵地&#xff0c;不断推动科学技术的发展与进步。多元化的学科背景和丰富的科研课题使高校在科研创新中具有独特的竞争力&#xff0c;能够引领科技的发展和进步。人工智能技术快速迭代&#xff0c;高校在人才培养上往往偏重于理论知识的传授&#xff0…

如何获取阿里云盘的 token

方法一、通过 alist 便携获取 Token 一、访问&#xff1a;阿里云盘/分享 | AList文档 二、找到 刷新令牌 &#xff0c;点击 获取Token&#xff0c;并通过阿里云APP扫码登录后获取&#xff0c;取到之后将 Token 粘贴至软件内 方法二、通过 网页登录 自行获取 token 我这里用的…

Sora:探索AI视频模型的无限可能

随着人工智能技术的飞速发展&#xff0c;AI在视频处理和生成领域的应用正变得越来越广泛。Sora&#xff0c;作为新一代AI视频模型&#xff0c;展示了前所未有的潜力和创新能力。本文将深入探讨Sora的功能、应用场景以及它所带来的革命性变化。 一、Sora的核心功能 1.1 视频生…

Pandas中的数据转换[细节]

今天我们看一下Pandas中的数据转换&#xff0c;话不多说直接开始&#x1f387; 目录 一、⭐️apply函数应用 apply是一个自由度很高的函数 对于Series&#xff0c;它可以迭代每一列的值操作&#xff1a; 二、⭐️矢量化字符串 为什么要用str属性 替换和分割 提取子串 …

three.js基础环境搭建

three.js three.js介绍安装threejs文件资源目录介绍本地静态服务器vscode配置live-server插件nodejs配置本地静态服务器项目的开发环境引入threejs 基础知识右手坐标系程序结构 three.js介绍 three.js官网 Three.js是一款基于WebGL的JavaScript 3D库&#xff0c;它使得开发者能…

go语言day2 配置

使用cmd 中的 go install &#xff1b; go build 命令出现 go cannot find main module 错误怎么解决&#xff1f; go学习-问题记录(开发环境)go: cannot find main module&#xff1b; see ‘go help modules‘_go: no flags specified (see go help mod edit)-CSDN博客 在本…

文字实录|Checkout.com大中华区总经理项尧:品牌全球化发展中的支付运营策略

大家好&#xff0c;很高兴在此次【品牌全球化营销增长峰会】与大家一起分享和交流。 我叫项尧&#xff0c;是 Checkout.com 大中华区的总经理&#xff0c;在支付领域有将近15年的经验。 我们 Checkout.com 是一家总部位于英国的支付公司&#xff0c;专注于线上收单&#xff0…

Charles 忽略IP授权 Allow 弹窗

当有新的设备连接到 Charles 时&#xff0c;会出现如下弹框确认是否允许&#xff0c;如果希望允许所有客户端连接不再有提示&#xff0c;可以通过添加模糊IP规则来实现。 配置方法&#xff1a;Proxy > Access Control Settings 中添加 0.0.0.0/0 和 ::/0 即可&#xff0c;…

数字孪生如何赋能智慧加油站?

在当今数字化转型的浪潮中&#xff0c;智慧城市的构建正以前所未有的速度推进&#xff0c;而智慧加油站作为智慧城市生态系统的重要组成部分&#xff0c;其升级转型显得尤为重要。随着国家“十四五”规划对智慧城市和数字化建设的明确指引&#xff0c;以及“碳达峰、碳中和”目…

08 元组和集合

目录 一、元组&#xff08;tuple&#xff09; 1. 什么是元组 2. 查操作 3. 函数和方法 二、集合&#xff08;set&#xff09; 1. 什么是集合 2. 数学集合运算 一、元组&#xff08;tuple&#xff09; 1. 什么是元组 元组是容器型数据类型&#xff0c;将( )作为容器的标…

考研数学(3/9):一元函数积分学

目录 一元函数积分学 1. 不定积分 1.1 不定积分的定义 1.2 不定积分的性质 1.3 不定积分的计算方法 2. 定积分 2.1 定积分的定义 2.2 定积分的性质 2.3 定积分的计算方法 3. 定积分的应用 3.1 求平面图形的面积 3.2 求旋转体的体积 3.3 求曲线的弧长 3.4 求曲面的…

【数据建模】微分方程与动力系统

文章目录 微分方程与动力系统1. 微分方程的理论基础1.1 函数、导数与微分1.2 一阶线性微分方程的解1.3 二阶常系数线性微分方程的解 2. 使用python求解微分方程2.1 求解微分2.2 求解定积分2.2.1 quad函数求解2.2.2 梯型法则求解 3. 使用Scipy和Sympy解微分方程3.1 使用sympy求解…

MATLAB中findall用法

目录 语法 说明 示例 查找具有可见或隐藏句柄的图窗 查找句柄处于隐藏状态的对象 查找 Text 对象 提示 findall的功能是查找所有图形对象。 语法 h findall(objhandles) h findall(objhandles,prop1,value1,...,propN,valueN) 说明 h findall(objhandles) 返回 ob…

ubuntu22.04 设置双屏

一 概述 最近把ubuntu18.04 升级到 22.04 双屏显示出来问题&#xff0c;在此记录下解决问题方案。二 解决方案 1 使用命令查看能检测到显示器 xrandr根据输出的信息&#xff0c;我们可以知道 HDMI-0 与 DP-0 是connected 。检测到两个显示器 2 设置输出显示器分辨率 由于我…

关于Vite+Vue+Ts WebStorm路径别名的问题

一、准备一个项目 二、在 vite.config.js 中添加 resolve: {alias: {: /src}} 三、tsconfig.app.json中添加代码 //添加代码"baseUrl": ".","paths": {"/*": ["src/*"]}把src的一个文件修改路径为开头 四、安装插件 npm i …

来给大家推荐得10个有效磁力导航链接(好用搜资料找资源)

都2024现在网上找资源像流水得鱼一样&#xff0c;抓一大把结果很难吃&#xff0c;我通宵特意整理的网站&#xff0c;网上有许多磁力导航网站可以提供海量的磁力链接资源&#xff0c;以下是一些有效的磁力导航网站推荐&#xff1a; 磁力搜索 网站地址&#xff1a;www.chiliso…

安装软件时出现风险警告——代码签名证书帮您解决(申请与优惠)

您开发的软件在用户下载安装时是否有以下弹窗提醒&#xff1f; 如何让用户信任软件并下载软件&#xff0c;是众多软件开发公司需要迫切去解决的问题&#xff0c;由此代码签名证书应运而生。 一 什么是代码签名证书 代码签名证书是一种提供给软件开发者&#xff0c;对其开发的…