参考了 https://spaces.ac.cn/archives/8679/comment-page-1,有一些增删。

JL 引理

首先下面需要应用马尔可夫不等式的另一个形式:

\[\newcommand \E{\mathbb E}
P(x\ge a)=P(e^{\lambda x}\ge e^{\lambda a})(\lambda >0)\le \min_{\lambda >0}e^{\lambda a}\E[e^{\lambda x}]
\]

主要的贡献是把马尔可夫不等式变成适配于正态分布的 exp 的形式。

单位模引理

单位模引理:对于 \(u\in \R^n\),每一维从 \(N(0,1/n)\) 随机采样,则

\[\newcommand\eps{\epsilon}\newcommand\la{\lambda}\newcommand\par{\parallel}
\forall \eps \in (0,1)\\
P(\big|\par u\par^2-1\big|\ge\eps)\le 2\exp(-\eps^2n/8)
\]

绝对值两边大概是差不多的(?),先看看 \(\par u\par ^2-1>\eps\)。

套用上述结论有:

\[P(\par u\par ^2-1>\eps)\le \min_{\la >0}e^{-\la (\eps+1)}\E[e^{\la\par u\par^2}]\\
\]

化简 \(\E[e^{\la\par u\par^2}]\),将 \(u\) 正交分解为 \(u_{1:n}\)。

\[\E[e^{\la\par u\par^2}]=\prod_{i=1}^n \E[e^{\la u_i^2}]=\E[e^{\la u_i^2}]^n\\
=\left(\int_{-\infty}^{\infty}P(u_i=t)e^{\la t^2}dt\right)^n\\
=\left(\int _{-\infty}^{\infty}\frac{1}{\sqrt{2n\pi}}e^{-\frac{nt^2}{2}}e^{\la t^2}dt\right)^n=\left(\int _{-\infty}^{\infty}\frac{1}{\sqrt{2n\pi}}e^{-(\frac n2-\la)\frac{t^2}2}dt\right)^n
\]

考虑正态分布 \(N(0,\sigma^2)\) 满足 \(\frac{1}{2\sigma^2}=\frac{n-2\la}{2}\),即 \(\sigma=\sqrt{\dfrac{1}{n-2\la}}\)。比较

\[\int_{-\infty}^{\infty}\frac{1}{\sqrt{2\pi}}e^{-\frac{x^2}{2\sigma^2}}dt=1
\]

上式的系数,得到:

\[\E[e^{\la u_i^2}]=\int _{-\infty}^{\infty}\frac{1}{\sqrt{2n\pi}}e^{-(\frac n2-\la)\frac{t^2}2}dt=\frac{\sqrt{n}}{\sqrt{n-2\la}}=\sqrt{\frac{n}{n-2\la}}
\]

那么

\[P(\par u\par ^2-1>\eps)\le \min_{\la >0}e^{-\la (\eps+1)}\left(\frac n{n-2\la}\right)^{n/2}\\
\]

设 \(f(\la)=e^{-\la (\eps+1)}\left(\dfrac n{n-2\la}\right)^{n/2}\)。则(好像有误)

\[f'(\la)=e^{-\la(\eps+1)}\left(\dfrac n{n-2\la}\right)^{n/2-1}\left(\frac{n^2}{(n-2\la)^2}-\frac{n(\eps+1)}{n-2\la}{}\right)
\]

所以不妨取

\[\la=\frac{n\eps}{2(\eps+1)}
\]

所以:

\[P(\par u\par ^2-1>\eps)\le e^{-n\eps/2}e^{n\ln(\eps+1)/2}=e^{n(\ln(1+\eps)-\eps)/2}\\
\]

而设 \(g(\eps)=\ln(\eps+1)-\eps+\eps^2/4\)。

\[g'(\eps)=\frac1{1+\eps}-1+\frac\eps2\le 0(0<\eps<1)
\]

所以 \(g(\eps)\le g(0)=0\),所以:

\[P(\par u\par ^2-1\ge\eps)\le \exp(-n\eps^2/8)
\]

JL 引理

一个压缩版本(遇证明变答辩糕):表示 \(N\) 个向量(维持距离)只需 \(O(\log N)\) 个维数。

对于 \(N\) 个向量 \(v_{1:N}\in \R^m,n>\frac{24\ln N}{\eps^2}\),随机矩阵 \(A\in R^{n\times m}\) 采样于 \(N(0,1/n)\),\(\eps\in (0,1)\),则至少有 \(\frac{N-1}{N}\) 的概率满足:

\[\forall i\neq j,\\
(1-\eps)\par v_i-v_j\par ^2\le \par Av_i-Av_j\par ^2 \le(1+\eps)\par v_i-v_j\par
\]

证明:

容易发现,\(\forall u\in \R^m\),\((Au)_i\) 服从 \(N(0,1/n)\)。

使用 Union Bound,带入 \(u=\frac{v_i-v_j}{\par v_i-v_j\par}\)。那么:

\[P\left(\exists i\neq j,\left| \frac{A(v_i-v_j)}{\par v_i-v_j\par}-1\right|\ge \eps\right)\le 2\binom N2\exp(-\eps^2n/8)
\]

若 \(n>\dfrac{24\ln N}{\eps^2}\),有:

\[1-N(N-1)\exp(-\eps^2n/8)>1-\frac{N(N-1)}{N^3}>\frac{N-1}{N}
\]

结束。

但是在计算中,\(24\ln N/\eps^2\) 并不是非常小的值,如果不使用一些更加高级的降维算法的话,差不多只有在 \(\eps>0.5\),并且数量很多的时候才能发挥作用了(悲)。

题外话- Box-Muller

假如我就要朴素的实现,不要其他降维算法(感觉再往后都是机器学习的内容,跟 OI 没有什么关系。。。)!我就需要快速生成正态分布随机数。

这里直接给公式:设 \(x,y\) 是 \((0,1)\) 的随机数:

\[x_0=\sigma \sqrt{-2\ln x}\cos(2\pi y)+\mu
\]
\[y_0=\sigma \sqrt{-2\ln x}\sin(2\pi y)+\mu
\]

\((x_0,y_0)\) 就是要求的正态分布的点啦。

chatgpt 魅力时刻

我们用博特的代码来感受一下正确性!

#include <iostream>
#include <vector>
#include <cmath>
#include <random> // Box-Muller 生成正态分布随机数
double boxMuller() {
static std::random_device rd;
static std::mt19937 gen(rd());
static std::uniform_real_distribution<> dis(0, 1); double u = dis(gen);
double v = dis(gen);
return sqrt(-2.0 * log(u)) * cos(2.0 * M_PI * v);
} // 计算两个向量的欧氏距离
double euclideanDistance(const std::vector<double>& a, const std::vector<double>& b) {
double sum = 0.0;
for (size_t i = 0; i < a.size(); ++i) {
sum += (a[i] - b[i]) * (a[i] - b[i]);
}
return sqrt(sum);
} // 随机生成 N 个 K 维向量
std::vector<std::vector<double>> generateRandomVectors(int N, int K) {
std::vector<std::vector<double>> vectors(N, std::vector<double>(K));
for (int i = 0; i < N; ++i) {
for (int j = 0; j < K; ++j) {
vectors[i][j] = boxMuller();
}
}
return vectors;
} // 使用 JL 引理降维
std::vector<std::vector<double>> jlTransform(const std::vector<std::vector<double>>& vectors, int D) {
int N = vectors.size();
int K = vectors[0].size(); std::vector<std::vector<double>> transformed(N, std::vector<double>(D)); for (int i = 0; i < N; ++i) {
for (int j = 0; j < D; ++j) {
transformed[i][j] = 0;
for (int k = 0; k < K; ++k) {
transformed[i][j] += vectors[i][k] * boxMuller();
}
transformed[i][j] /= sqrt(D);
}
} return transformed;
} // 计算所有向量之间的欧氏距离和
double totalEuclideanDistance(const std::vector<std::vector<double>>& vectors) {
double totalDistance = 0.0;
int N = vectors.size(); for (int i = 0; i < N; ++i) {
for (int j = i + 1; j < N; ++j) {
totalDistance += euclideanDistance(vectors[i], vectors[j]);
}
} return totalDistance;
} int main() {
int N, K;
std::cin >> N >> K; double epsilon = 0.5;
int D = static_cast<int>(24 * log(N) / (epsilon * epsilon)); std::cerr<<"新维度 = "<<D<<std::endl; auto vectors = generateRandomVectors(N, K);
auto transformedVectors = jlTransform(vectors, D); double originalDistanceSum = totalEuclideanDistance(vectors);
double transformedDistanceSum = totalEuclideanDistance(transformedVectors); std::cout << "Real: " << originalDistanceSum << std::endl;
std::cout << "Calc: " << transformedDistanceSum << std::endl; return 0;
}

输入 100 2000,得到的结果是

Real: 312086
Calc: 312885

把上文代码的 \(24\) 改为 \(12\) 的结果也是较为精确的。

Real: 313473
Calc: 310509

具体来说,当那个值取 \(24\) 的时候把 \(2000\) 维降到了 \(447\) 维,可谓表现相当不错(至少在我们的随机数据情况下)。

闲话 6.30 -JL 引理的更多相关文章

  1. 【洛谷P1463】反素数

    题目大意:给定 \(N < 2e9\),求不超过 N 的最大反素数. 题解: 引理1:不超过 2e9 的数的质因子分解中,最多有 10 个不同的质因子,且各个质因子的指数和不超过30. 引理2: ...

  2. BZOJ 1053 反素数 题解

    题面 引理1:  1~n中的最大反质数,就是1~n中约数个数最多的数中最小的一个(因为要严格保证g(x)>g(i)): 引理2:1~n中任何数的不同因子不会超过10个,因为他们的乘积大于2,00 ...

  3. 「学习笔记」倍增思想与lca

    目录 ST表 算法 预处理 查询 关于 log2 Code 预处理 查询 例题 P2880 P2048 lca 树上 RMQ 前置知识:欧拉序列 算法 Code 离线 Tarjan 算法 Code 倍 ...

  4. swing编程

    在界面中放入图片:路径以项目路径为准  img包一般放在项目文件夹下 package adapter;import java.awt.Color;import java.awt.Dimension;i ...

  5. julia与python中的列表解析.jl

    julia与python中的列表解析.jl #=julia与python中的列表解析.jl 2016年3月16日 07:30:47 codegay julia是一门很年轻的科学计算语言 julia文档 ...

  6. POJ 2888 Magic Bracelet(Burnside引理,矩阵优化)

    Magic Bracelet Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 3731   Accepted: 1227 D ...

  7. 【微信小程序项目实践总结】30分钟从陌生到熟悉

    前言 我们之前对小程序做了基本学习: 1. 微信小程序开发07-列表页面怎么做 2. 微信小程序开发06-一个业务页面的完成 3. 微信小程序开发05-日历组件的实现 4. 微信小程序开发04-打造自 ...

  8. 小白必读:闲话HTTP短连接中的Session和Token

    本文引用了刘欣的文章,感谢原作者的分享. 1.引言 Http协议在现今主流的IM系统中拥有无可替代的重要性(在IM系统中用HTTP发起的连接被大家简称为http短连接),但Http作为传统互联网信息交 ...

  9. 【微信小程序项目实践总结】30分钟从陌生到熟悉 web app 、native app、hybrid app比较 30分钟ES6从陌生到熟悉 【原创】浅谈内存泄露 HTML5 五子棋 - JS/Canvas 游戏 meta 详解,html5 meta 标签日常设置 C#中回滚TransactionScope的使用方法和原理

    [微信小程序项目实践总结]30分钟从陌生到熟悉 前言 我们之前对小程序做了基本学习: 1. 微信小程序开发07-列表页面怎么做 2. 微信小程序开发06-一个业务页面的完成 3. 微信小程序开发05- ...

  10. 【BZOJ 1004】 1004: [HNOI2008]Cards (置换、burnside引理)

    1004: [HNOI2008]Cards Description 小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有多少种染色方案,Sun很 ...

随机推荐

  1. kafka之介绍

    Kafka 由于高吞吐量.可持久化.分布式.支持流数据处理等特性而被广泛应用.但当前关于Kafka原理及应用的相关资料较少,在我打算编写本文时,还没有见到中文版本的Kafka相关书籍,对于初学者甚至是 ...

  2. pikachu文件上传_2024-11-26

    什么是文件上传漏洞 文件上传功能在web应用系统很常见,比如很多网站注册的时候需要上传头像.上传附件等等.当用户点击上传按钮后,后台会对上传的文件进行判断 比如是否是指定的类型.后缀名.大小等等,然后 ...

  3. PDF 图书

    我找到的深入介绍 PDF 结构的图书主要有 2 本: PDF Explained,这本书比较早,首发于 2011 年11 月 30 日 Developing with PDF,首发于 2013年10月 ...

  4. swagger 文件上传以及requestbody参数传递

    swagger用来做普通的API测试很方便,在实际开发过程中,经常会有文件上传,或者通过reuestbody传递数据等方式. 这个时候swagger的配置就有一些特殊了 . swagger reque ...

  5. 从 $PGDATA 到文件组:深入解析 PostgreSQL 与 SQL Server 的存储策略

    从 $PGDATA 到文件组:深入解析 PostgreSQL 与 SQL Server 的存储策略 在数据库领域,数据存储和管理的效率与可靠性是决定系统性能.可扩展性和易于管理的关键因素.Postgr ...

  6. Fastadmin框架,服务器搭建环境

    FastAdmin 基于ThinkPHP和Bootstrap的极速后台开发框架 https://www.fastadmin.net 安装node.js 1.获取node.js资源 V8.x: curl ...

  7. Qt/C++音视频开发59-使用mdk-sdk组件/原qtav作者力作/性能凶残/超级跨平台

    一.前言 最近一个月一直在研究mdk-sdk音视频组件,这个组件是原qtav作者的最新力作,提供了各种各样的示例demo,不仅限于支持C++,其他各种比如java/flutter/web/androi ...

  8. Qt编写视频监控系统79-四种界面导航栏的设计

    一.前言 最初视频监控系统按照二级菜单的设计思路,顶部标题栏一级菜单,左侧对应二级菜单,最初采用图片在上面,文字在下面的按钮方式展示,随着功能的增加,二级菜单越来越多,如果都是这个图文上下排列的按钮, ...

  9. 《Bootstrap4Web设计与开发实战》源代码下载

    <Bootstrap4Web设计与开发实战>源代码下载: 链接:https://pan.baidu.com/s/1GaIo390c-l-gsT6-6RaaJA 提取码:fgiq 版权声明: ...

  10. 前端学习openLayers配合vue3(圆形形状的绘制)

    上节课我们学了加载了矢量图片,这节我们来学绘制圆形 关键代码,第一段呢是设置圆点的操作,第二步是点击地图获取地图位置来设置圆点,ol还有很多类,各种形状的 //设置圆点 // let anchorLa ...