通过 Cholesky 分解生成高斯 Copula 相关样本
Gaussian-Copula Correlated Samples via Cholesky Factorisation
开始编码实现 solution(z_independent: list[list[float]], correlation: list[list[float]]) -> list[list[float]]。某衍生品风险口对一只多资产结构化产品做估值,其收益依赖多个标的(一个权益因子、一个利率因子、一个 FX 因子)的联合走势。每条蒙特卡洛路径需要符合给定相关矩阵的相关标准正态抽样,矩阵由历史收益标定。教科书做法是高斯 Copula 采样:先抽独立 N(0, 1) 向量 z,再左乘相关矩阵的下三角 Cholesky 因子 L 得到相关标准正态。本函数完成确定性的"Cholesky + 矩阵-向量积"步骤——调用方已经抽好独立 z,函数本身不生成随机数。对每个样本 s in 0..S-1,返回 Z_corr[s] = L @ z_independent[s],其中 L 是 correlation 的下三角 Cholesky 因子(满足 L @ L.T == correlation)。
下三角 vs 上三角 与 矩阵-向量积方向 都很关键。输出是 L @ z(列向量),L 是唯一对角非负的下三角因子,使得 L @ L.T == correlation。若错写为 U @ z(U 上三角),等同于做了协方差等于 U @ U.T 的不同变换——不等于输入相关矩阵。若错写为 z @ L(行向量乘矩阵),实际算的是 L.T @ z,也是错的。两种 bug 在第一分量上都恰好与正确答案部分一致,因此判别测试需要查非对称样本的第二行。
例
solution([[1.0, 1.0]], [[1.0, 0.5], [0.5, 1.0]]) 返回 [[1.0, 1.3660254037844386]]。逐步算 Cholesky:L[0][0] = sqrt(1.0) = 1.0。L[1][0] = correlation[1][0] / L[0][0] = 0.5 / 1.0 = 0.5。L[1][1] = sqrt(correlation[1][1] - L[1][0]^2) = sqrt(1 - 0.25) = sqrt(0.75) = 0.8660254...。所以 L = [[1, 0], [0.5, 0.8660254]]。单一样本 z = [1.0, 1.0],下三角矩阵-向量积给出 Z_corr[0] = L[0][0] * z[0] = 1 * 1 = 1.0,Z_corr[1] = L[1][0] * z[0] + L[1][1] * z[1] = 0.5 + 0.8660254 = 1.3660254。输出 [[1.0, 1.3660254037844386]]。
下三角与上三角的对照算例:correlation = [[1.0, 0.5], [0.5, 1.0]]、z = [2.0, 1.0],正确下三角答案 [2.0, 0.5 * 2 + sqrt(0.75) * 1] = [2.0, 1.8660254]。若构造上三角因子 U = [[1, 0.5], [0, sqrt(0.75)]] 再做 U @ z,得 [1 * 2 + 0.5 * 1, sqrt(0.75) * 1] = [2.5, 0.8660254]——第一分量就已经不同,bug 在第 0 行就能暴露。Matvec 方向 bug(z @ L 写法)更隐蔽——从第 1 行起才偏离,因此测试集两种 bug 的判别样例都包含。
需要明确的细节:S = 0(空 z_independent)返回 []——函数不抛异常。D = 1:correlation = [[1.0]]、L = [[1.0]],输出等于输入。Identity 相关矩阵:L = I,输出等于输入。负相关(如 -0.7):标准 Cholesky 递推天然处理——L[1][0] 直接成为负数。Spec 保证矩阵严格正定,每个 L[i][i]^2 > 0,参考实现不需要校验或处理非正定输入。
期望算法 O(D^3 + S * D^2):Cholesky 分解是一次性的三次步(D <= 6,常数极小);每个样本的矩阵-向量积是 O(D^2),因为 L 下三角,内层求和只跑 k in 0..i 而不是 k in 0..D-1。内积索引含对角:Z_corr[s][i] = sum_{k=0..i} L[i][k] * z[k]。写成 k in 0..i-1(不含对角)会丢掉 L[i][i] * z[i] 这一项,导致系统性错误。
实现细节由 stubs/stub.py 提供。
实践背景
某衍生品风险口对一只多资产结构化产品做估值,其收益依赖多个标的(譬如一个权益因子、一个利率因子、一个 FX 因子)的联合走势。从历史收益标定的目标相关矩阵出发,需要抽出联合分布与该矩阵一致的蒙特卡洛路径。教科书做法是高斯 Copula 采样:(1)抽独立 N(0, 1) 向量 z,维度 D;(2)左乘目标相关矩阵的下三角 Cholesky 因子 L,得到相关标准正态 L @ z;(3)每个分量再走目标边际分布的逆 CDF 得到"均匀→边际"抽样。第 2 步——本函数 solution(...)——是确定性的线性代数核,剥离出来便于在没有随机性的前提下做单元测试。solution(...) 输出的是一批相关标准正态样本,下游会被交易台的工具库再走边际逆 CDF(同 cell 中的姊妹题)。下三角的约定有意义:Cholesky 因子满足 L @ L.T == correlation(不是 L.T @ L),左乘列向量保留标准正态分布的同时施加目标协方差:Cov(L @ z) = L * I * L.T = L @ L.T = correlation。
约束条件
- 1 <= D == len(correlation) <= 6(相关矩阵维度)
- 0 <= S == len(z_independent) <= 50(独立样本数)
- 每个 z_independent[s] 是长度为 D 的有限浮点数列表,|z| <= 5.0
- correlation 严格对称(correlation[i][j] == correlation[j][i] 完全相等),correlation[i][i] == 1.0,且严格正定(调用方负责)
- 输出为形状 (S, D) 的 list[list[float]];每项按 rel_tol=1e-9、abs_tol=1e-9 比对;行序与输入一致
样例
Case 1 · statement-example: D=2 rho=0.5 z=[[1.0,1.0]] yields [1, 1.366]
输入: [[[1,1]],[[1,0.5],[0.5,1]]]
期望: [[1,1.3660254037844386]]
L=[[1,0],[0.5,sqrt(0.75)]]; Z_corr=L@z=[1, 0.5+sqrt(0.75)]≈[1, 1.366]。
Case 2 · visible: identity correlation passes z through unchanged
输入: [[[0.5,-0.3,1.2]],[[1,0,0],[0,1,0],[0,0,1]]]
期望: [[0.5,-0.3,1.2]]
Identity 相关矩阵的 Cholesky 因子 L 仍为 identity,Z_corr = z。
Case 3 · visible: S=0 empty samples returns empty list (don't crash)
输入: [[],[[1,0.5],[0.5,1]]]
期望: []
S=0 时返回 [] 不要崩。
Case 4 · visible: D=1 trivial 1x1 correlation, output equals input
输入: [[[0.7],[-1.5],[0]],[[1]]]
期望: [[0.7],[-1.5],[0]]
D=1 时 L=[[1]],输出等于输入。
Case 5 · visible: negative correlation rho=-0.7 produces negative L off-diagonal
输入: [[[1,1]],[[1,-0.7],[-0.7,1]]]
期望: [[1,0.01414284285428502]]
L=[[1,0],[-0.7,sqrt(0.51)]]; Z_corr=[1, -0.7+sqrt(0.51)]≈[1, 0.0141]。
最近提交
还没有提交记录。
编码区
实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。
默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。
Case 1 · statement-example: D=2 rho=0.5 z=[[1.0,1.0]] yields [1, 1.366]
输入: [[[1,1]],[[1,0.5],[0.5,1]]]
期望: [[1,1.3660254037844386]]
L=[[1,0],[0.5,sqrt(0.75)]]; Z_corr=L@z=[1, 0.5+sqrt(0.75)]≈[1, 1.366]。
Case 2 · visible: identity correlation passes z through unchanged
输入: [[[0.5,-0.3,1.2]],[[1,0,0],[0,1,0],[0,0,1]]]
期望: [[0.5,-0.3,1.2]]
Identity 相关矩阵的 Cholesky 因子 L 仍为 identity,Z_corr = z。
Case 3 · visible: S=0 empty samples returns empty list (don't crash)
输入: [[],[[1,0.5],[0.5,1]]]
期望: []
S=0 时返回 [] 不要崩。
Case 4 · visible: D=1 trivial 1x1 correlation, output equals input
输入: [[[0.7],[-1.5],[0]],[[1]]]
期望: [[0.7],[-1.5],[0]]
D=1 时 L=[[1]],输出等于输入。
Case 5 · visible: negative correlation rho=-0.7 produces negative L off-diagonal
输入: [[[1,1]],[[1,-0.7],[-0.7,1]]]
期望: [[1,0.01414284285428502]]
L=[[1,0],[-0.7,sqrt(0.51)]]; Z_corr=[1, -0.7+sqrt(0.51)]≈[1, 0.0141]。