Large-Scale Curve Time Series with Common Stochastic Trends¶
讲者: Degui Li
会场: Econometrics
报告题目: Large-Scale Curve Time Series with Common Stochastic Trends
链接: arXiv
来源: JCSDS 2026 · 返回会议总览
一、领域脉络与小综述¶
这个方向是什么¶
本文研究的核心问题是:如何对大规模(高维)非平稳曲线时间序列进行建模与推断。具体来说,我们观测到 \(N\) 条曲线时间序列(如不同气象站的温度曲线、不同股票的日内价格曲线),每条曲线 \(Z_{it}(u)\) 随时间 \(t\) 演化。这些曲线可能被少数几个潜在的、非平稳的(含单位根)共同因子所驱动。本文的目标是:在 \(N\) 和 \(T\) 都趋于无穷的高维设定下,估计这些共同随机趋势(common stochastic trends)及其函数因子载荷(functional factor loadings),并建立相应的极限分布理论。该方向当前处于从“单条非平稳曲线”向“大规模非平稳曲线面板”过渡的阶段,本文是首个系统处理该问题的理论工作。
发展脉络(history)¶
-
奠基工作:经典因子模型与非平稳时间序列
- Chamberlain & Rothschild (1983):定义了“近似因子模型”(approximate factor model),为高维面板数据的因子分析奠定了理论基础。他们证明了当协方差矩阵只有 \(K\) 个无界特征值时,存在一个近似因子结构,且主成分分析(PCA)可用于估计因子载荷。
- Bai & Ng (2002):提出了基于信息准则的因子个数选择方法,并建立了PCA估计的渐近理论,是后续所有高维因子模型研究的基石。
- Bai (2004):将因子模型推广到非平稳面板数据,提出了“PANIC”方法(通过差分处理单位根),并建立了共同随机趋势估计的极限分布理论。这是本文最直接的理论前身。
- Bai & Ng (2004):进一步发展了PANIC方法,用于检验面板数据中的单位根和协整关系。
-
主要进展:从标量到函数型时间序列
- 单条非平稳曲线时间序列:Horváth, Kokoszka & Rice (2014) 提出了函数型KPSS检验;Chang, Kim & Park (2016) 研究了状态密度曲线的非平稳性;Beare, Seo & Seo (2017) 和 Franchi & Paruolo (2020) 建立了Hilbert空间中I(1)和I(d)自回归过程的Granger-Johansen表示定理;Li, Robinson & Shang (2023) 引入了长记忆函数时间序列框架。这些工作都只处理单条曲线。
- 高维平稳函数因子模型:Tavakoli, Nisol & Hallin (2023a,b) 提出了一个高维函数因子模型,其中因子是标量的,因子载荷是函数的。他们建立了表示定理和估计理论,但假设曲线是平稳的。Guo, Qiao & Wang (2021) 提出了另一种设定(函数因子、标量载荷),同样假设平稳性。Leng et al. (2024) 引入了“双函数因子模型”(dual functional factor model),允许因子和载荷都是函数的,但仍然限于平稳设定。
-
当前Frontier与本文位置
- 当前的前沿是:如何将高维因子模型与函数型非平稳时间序列结合起来。作者明确指出:“As far as we know, there is no literature on high-dimensional factor models for nonstationary curve time series.” 本文正是填补这一空白,将Bai (2004) 的经典非平稳因子模型理论从标量面板推广到函数型面板,并允许因子个数 \(q\) 缓慢发散。
子线索聚类¶
- 经典高维因子模型(标量面板):Chamberlain & Rothschild (1983), Bai & Ng (2002), Bai (2004), Bai & Ng (2004), Barigozzi, Lippi & Luciani (2021)。这一簇关注标量时间序列的因子模型,是本文的方法论基础。
- 单条非平稳函数时间序列:Horváth, Kokoszka & Rice (2014), Chang, Kim & Park (2016), Beare, Seo & Seo (2017), Franchi & Paruolo (2020), Li, Robinson & Shang (2023), Nielsen, Seo & Seong (2023)。这一簇关注单条曲线的非平稳性,是本文的应用背景和理论延伸对象。
- 高维平稳函数因子模型:Tavakoli, Nisol & Hallin (2023a,b), Guo, Qiao & Wang (2021), Leng et al. (2024)。这一簇是本文最直接的竞争/前驱路线,但都假设平稳性。本文通过引入共同随机趋势,将其推广到非平稳情形。
这个方向在追问的核心问题¶
- 识别与估计:如何从高维非平稳曲线面板中识别并估计出潜在的共同随机趋势和函数因子载荷?
- 极限分布:估计量的渐近分布是什么?如何构造统计推断(如置信区间)?
- 因子个数选择:如何一致地估计共同随机趋势的个数 \(q\)?
- 协整:当非平稳因子之间存在协整关系时,如何调整估计方法?
⚠️ 作者的 framing¶
- 作者把缺口 frame 成什么:作者将缺口明确表述为“there is no literature on high-dimensional factor models for nonstationary curve time series”。他们将自己的工作定位为“the main focus of the present paper centers on the interaction of recent advances in nonstationary curve time series and large-dimensional approximate factor models”。通过引入一个“双函数因子模型”(dual functional factor model),他们声称提供了一个“more flexible structure than those in Guo, Qiao and Wang (2021) and Tavakoli, Nisol and Hallin (2023a,b)”,因为他们的模型允许因子和载荷都是函数的。
- 哪些竞争路线被他淡化或回避了:
- 纯非参数方法:作者完全回避了不依赖因子结构的纯非参数方法(如直接对协方差算子进行谱分解)。他们的方法本质上是参数/半参数的,依赖于因子模型结构。
- 计算复杂性:作者没有讨论当 \(N\) 和 \(T\) 都很大时,函数PCA的计算成本(如 \(T \times T\) 矩阵的特征分解)。对于研究者关心的“统计-计算权衡”,这是一个明显的空白。
- 更一般的非平稳性:作者只考虑了I(1)过程(单位根)。对于I(2)或更一般的分数阶积分过程,他们只是引用了Beare & Seo (2020)和Franchi & Paruolo (2020),但没有将其纳入自己的框架。
- 什么明显该被引 / 该存在、却没出现在 intro 里?
- 关于“统计-计算权衡”的文献:对于研究者而言,这是一个明显的缺失。本文的估计方法(PCA)是多项式时间可计算的,但作者没有讨论是否存在更快的算法,或者是否存在信息-计算缺口(即,是否存在统计上可识别但计算上困难的问题)。例如,在稀疏PCA或张量PCA中,存在已知的统计-计算权衡。本文的设定(函数型、非平稳)可能也存在类似现象,但作者完全没有提及。
- 关于“高维函数型主成分分析”的文献:虽然引用了Happ & Greven (2018),但作者没有深入讨论当 \(N\) 和 \(T\) 都很大时,函数型PCA的相合性条件(如特征函数的光滑性、特征值的衰减速度)与本文假设之间的关系。
张力¶
未见明显对立引用。所有被引工作都在各自的子领域内被接受,没有发现彼此矛盾或在略不同条件下得相反结论的情况。
二、最核心、最简单的例子 / 数学问题¶
第一步:把符号、模型、可观测数据交代清楚¶
-
符号:
- \(Z_{it}(u)\): 可观测的曲线时间序列。\(i = 1, \dots, N\) 是横截面个体(如气象站),\(t = 1, \dots, T\) 是时间点,\(u \in \mathcal{C}_i\) 是函数定义域(如一年中的天数)。这是可观测数据。
- \(\chi_{it}(u)\): 共同成分(common component),由潜在因子驱动。不可观测。
- \(\varepsilon_{it}(u)\): 异质成分(idiosyncratic component),允许横截面和时序上的弱相关。不可观测。
- \(F_{jt}(u)\): 第 \(j\) 个潜在函数因子(functional factor),\(j = 1, \dots, k\)。不可观测。
- \(\mathcal{B}_{ij}\): 从第 \(j\) 个函数因子到第 \(i\) 个观测曲线的线性积分算子,其核为 \(B_{ij}(u, v)\)。不可观测。
- \(G_t\): \(q\) 维实值非平稳因子向量(common stochastic trends)。这是本文的核心估计对象。不可观测。
- \(\Phi_j(u)\): \(q\) 维确定性基函数向量,用于对函数因子 \(F_{jt}\) 进行级数展开。已知(由研究者选择)。
- \(\Lambda_i(u)\): \(q\) 维函数因子载荷向量,由 \(\Lambda_i(u) = \sum_{j=1}^k \mathcal{B}_{ij} \Phi_j(u)\) 定义。不可观测。
- \(\eta_{jt}(u)\): 级数近似误差。不可观测。
- \(q\): 共同随机趋势的个数。未知,需要估计。
- \(k\): 函数因子的个数。未知,但假设为有限正整数。
-
模型:
- 观测方程:\(Z_{it}(u) = \chi_{it}(u) + \varepsilon_{it}(u)\)。
- 共同成分结构:\(\chi_{it}(u) = \sum_{j=1}^k \mathcal{B}_{ij} F_{jt}(u) = \sum_{j=1}^k \int_{\mathcal{C}_j^*} B_{ij}(u, v) F_{jt}(v) dv\)。这是一个“双函数因子模型”,因子和载荷都是函数的。
- 函数因子的低维表示:\(F_{jt}(u) = \Phi_j(u)^\top G_t + \eta_{jt}(u)\)。这个“低维因子模型”将无限维的函数因子 \(F_{jt}\) 用有限维的实值非平稳因子 \(G_t\) 和基函数 \(\Phi_j\) 来近似。
- 非平稳因子生成过程:\(\Delta G_t = G_t - G_{t-1} = \xi_t\),其中 \(\{\xi_t\}\) 是平稳的I(0)过程。这意味着 \(G_t\) 是I(1)过程(单位根过程)。
-
可观测数据:
- 研究者实际能观测到的是 \(N\) 条曲线时间序列 \(\{Z_{it}(u): i=1,\dots,N, t=1,\dots,T\}\)。
- 想要但观测不到的是:函数因子 \(F_{jt}\),积分算子 \(\mathcal{B}_{ij}\),实值非平稳因子 \(G_t\),函数载荷 \(\Lambda_i\),以及误差项 \(\varepsilon_{it}\) 和 \(\eta_{jt}\)。所有推断都依赖于模型假设。
第二步:讲最小内核¶
本文的核心思路是:通过一个“双函数因子模型”结构,将无限维的非平稳函数时间序列问题,转化为一个有限维的、经典的“非平稳因子模型”问题,然后应用函数PCA进行估计。
最简特例:假设 \(k=1\)(只有一个函数因子),\(q=1\)(只有一个共同随机趋势),且级数近似误差 \(\eta_{jt} \equiv 0\)。那么模型退化为: 1. \(Z_{it}(u) = \chi_{it}(u) + \varepsilon_{it}(u)\)。 2. \(\chi_{it}(u) = \int B_{i1}(u, v) F_{1t}(v) dv\)。 3. \(F_{1t}(u) = \phi_1(u) G_t\),其中 \(\phi_1(u)\) 是一个已知的基函数,\(G_t\) 是一个标量的I(1)过程(如随机游走)。 4. 代入得:\(Z_{it}(u) = \left[ \int B_{i1}(u, v) \phi_1(v) dv \right] G_t + \varepsilon_{it}(u) = \Lambda_i(u) G_t + \varepsilon_{it}(u)\)。
在这个特例下,问题简化为:从 \(N\) 条曲线时间序列 \(\{Z_{it}(u)\}\) 中,估计一个共同的标量I(1)趋势 \(G_t\) 和 \(N\) 个函数载荷 \(\Lambda_i(u)\)。
核心思路:函数PCA通过构造一个 \(T \times T\) 的矩阵 \(\tilde{\Omega}\),其元素 \(\tilde{\Omega}_{ts} = \frac{1}{N} \sum_{i=1}^N \int Z_{it}(u) Z_{is}(u) du\)。这个矩阵是观测曲线之间“内积”的样本均值。在模型下,\(\tilde{\Omega}_{ts} \approx G_t G_s \cdot \frac{1}{N} \sum_{i=1}^N \int \Lambda_i(u)^2 du\)。因此,\(\tilde{\Omega}\) 近似于一个秩为1的矩阵(由 \(G_t\) 张成)。对 \(\tilde{\Omega}\) 进行特征分解,其最大特征值对应的特征向量(乘以 \(T\))就是 \(G_t\) 的估计 \(\tilde{G}_t\)。然后,通过最小二乘回归 \(\tilde{\Lambda}_i(u) = \frac{1}{T^2} \sum_{t=1}^T Z_{it}(u) \tilde{G}_t\) 来估计载荷。
这个特例清晰地展示了本文方法的本质:利用横截面平均(\(N\) 很大)来消除异质成分 \(\varepsilon_{it}\) 的噪声,从而从观测曲线的协方差结构中提取出共同的时间趋势。一般情形(\(k>1, q>1\))只是将这个秩为1的矩阵推广到秩为 \(q\) 的矩阵。
三、这篇论文做了什么¶
三句话¶
- 研究了什么问题:本文研究了大规模(高维)非平稳曲线时间序列的因子模型,旨在估计其中的共同随机趋势(common stochastic trends)和函数因子载荷(functional factor loadings)。
- 核心工具/方法:采用一个“双函数因子模型”结构,并通过函数主成分分析(functional PCA) 进行估计。对于因子存在协整或异质成分非平稳的情况,提出了一个函数型PANIC方法。
- 主要结论:建立了函数PCA估计量的均方收敛速度和极限分布理论(允许 \(N, T, q\) 联合发散),证明了所提信息准则对因子个数 \(q\) 选择的一致性,并通过模拟和两个真实数据例子(澳大利亚温度曲线、S&P 500股票价格曲线)验证了方法的有效性。
关键设定与假设¶
- 模型设定:双函数因子模型(公式2.1-2.6)。关键创新在于通过级数展开(公式2.3)将无限维的函数因子 \(F_{jt}\) 与有限维的非平稳实值因子 \(G_t\) 联系起来。
- 识别条件(公式3.1):\(\frac{1}{T^2} \sum_{t=1}^T G_t G_t^\top = I_q\) 和 \(\frac{1}{N} \sum_{i=1}^N \int \Lambda_i(u) \Lambda_i(u)^\top du\) 为对角矩阵。这是PCA估计的标准旋转归一化条件,与Bai (2004) 类似,但归一化速率是 \(T^2\) 而非 \(T\),因为 \(G_t\) 是I(1)过程。
- 关键假设:
- Assumption 1 (因子与载荷):要求载荷算子一致有界(1(i)),载荷矩阵 \(\Lambda_i\) 的样本协方差收敛到一个正定矩阵 \(\Sigma_\Lambda\)(1(ii)),非平稳因子 \(G_t\) 满足泛函中心极限定理(1(iii)),并对特征值及其间隙施加了允许其随 \(q\) 发散或收缩的条件(1(iv))。相比Bai (2004) 中固定 \(q\) 且特征值有界,本文的假设更弱,允许 \(q\) 发散。
- Assumption 2 (误差项):要求异质成分 \(\varepsilon_{it}\) 是弱相关的(横截面和时序),并满足一些矩条件(2(i)(iii)(iv))。级数近似误差 \(\eta_{jt}\) 的均方收敛到0(2(ii))。这些假设与Bai & Ng (2002) 和 Bai (2004) 中的条件类似,但被推广到了函数型设定。
- Assumption 3 & 4 (极限分布):为推导极限分布,需要更强的条件,包括 \(N\) 和 \(T\) 的相对速率(如 \(N = o(T^3)\)),以及关于 \(\langle \Lambda_i, \varepsilon_{it} \rangle\) 和 \(\sum_t G_t \varepsilon_{it}(u)\) 的泛函中心极限定理。
主要结果¶
- Proposition 3.1 (均方收敛):函数PCA估计的共同趋势 \(\tilde{G}_t\) 的均方误差为 \(O_P\left( \nu_q^{-2} q (T^{-2} + q \nu_q N^{-1} + q \nu_q \delta_q^2) \right)\)。当 \(q\) 固定且特征值有界时,该速率退化为 \(O_P(T^{-2} + N^{-1})\),与Bai (2004) 一致。关键点:由于 \(G_t\) 是I(1)过程,收敛速率中的 \(T^{-2}\) 项比平稳情形下的 \(T^{-1}\) 更快。
- Theorem 3.2 (\(\tilde{G}_t\) 的极限分布):\(\sqrt{N} R \Psi_t^{-1/2} Q_{NT}^{-1} (\tilde{G}_t - H_{NT} G_t) \rightsquigarrow N(0, \Upsilon)\)。这是一个混合正态分布,与Bai (2004) 的Theorem 2类似,但推广到了函数型设定和发散 \(q\) 的情形。关键点:收敛速率是 \(\sqrt{N}\),而不是 \(\sqrt{T}\),因为横截面信息是估计共同趋势的主要来源。
- Theorem 3.3 (\(\tilde{\Lambda}_i\) 的极限分布):\(T R H_{NT}^{-1} [\tilde{\Lambda}_i(u) - (H_{NT}^{-1})^\top \Lambda_i(u)] \rightsquigarrow \int_0^1 B_\xi^R(r) dB_\varepsilon^{(i)}(r, u)\)。这是一个泛函形式的极限分布,收敛速率是 \(T\)(超快收敛),因为 \(G_t\) 是I(1)过程。关键点:载荷估计的收敛速度比趋势估计更快,且其极限分布与已知 \(G_t\) 时的极限分布相同(即“oracle”性质)。
- Theorem 4.2 (因子个数选择一致性):所提信息准则(公式4.3)在适当条件下能一致地估计共同随机趋势的个数 \(q\)。条件(4.4)要求惩罚项 \(\rho_{NT}\) 介于0和特征值 \(\nu_q\) 之间,且大于估计误差。
证明路线与技术技巧¶
- 整体路线:
- 矩阵分解:将观测曲线的内积矩阵 \(\tilde{\Omega}\) 分解为信号部分(由 \(G_t\) 和 \(\Lambda_i\) 构成)和噪声部分(由 \(\varepsilon_{it}\) 和 \(\eta_{jt}\) 构成)。
- PCA与旋转:利用PCA得到 \(\tilde{G}_t\) 的初步估计,并通过一个旋转矩阵 \(H_{NT}\) 将其与真实因子 \(G_t\) 联系起来。证明的关键是控制旋转矩阵的误差。
- 误差控制:将 \(\tilde{G}_t - H_{NT} G_t\) 表示为若干项之和(公式A.3),然后逐项证明这些项是 \(o_P(1)\)。这需要用到:
- 引理B.1-B.3:证明由噪声项(\(\varepsilon_{it}, \eta_{jt}\))构成的交叉项在均方意义下是可忽略的。
- 引理B.5-B.6:证明旋转矩阵 \(H_{NT}\) 及其相关量(\(V_{NT}, Q_{NT}\))的相合性。
- 极限分布:在均方收敛的基础上,进一步证明主导项(由 \(\langle \Lambda_i, \varepsilon_{it} \rangle\) 构成)满足中心极限定理,从而得到 \(\tilde{G}_t\) 的渐近正态性。对于 \(\tilde{\Lambda}_i\),则利用 \(\tilde{G}_t\) 的收敛性,将其误差表示为 \(\sum_t \varepsilon_{it} G_t\) 加上可忽略项,然后应用泛函中心极限定理。
- 关键跳跃点:
- 从标量到函数型的跳跃:将标量面板中的内积 \(Z_{it} Z_{is}\) 替换为函数型内积 \(\int Z_{it}(u) Z_{is}(u) du\)。这要求处理函数型数据的积分和算子范数,而非简单的矩阵乘法。
- 处理发散 \(q\):允许因子个数 \(q\) 发散给证明带来了显著困难。作者通过引入关于特征值 \(\nu_q, \bar{\nu}_q\) 及其间隙 \(\iota_q\) 的假设(Assumption 1(iv)),并利用强逼近理论(如Csörgő & Révész, 1981)来控制高维随机矩阵的谱性质。
- 处理级数近似误差 \(\eta_{jt}\):通过假设其均方收敛(Assumption 2(ii)),并将其影响吸收到误差项中,从而证明其不影响主项。
- 技术技巧点名:
- 强逼近(Strong Approximation):用于证明Assumption 1(iii)中的高维泛函中心极限定理(公式3.4-3.6),将部分和过程逼近为布朗运动。
- sinθ定理(Davis & Kahan, 1970):用于证明特征向量(即 \(\tilde{G}_t\))的相合性(引理B.5的证明中)。
- 鞅收敛方法(Martingale Convergence Methods):用于证明 \(\sum_t G_t \varepsilon_{it}(u)\) 收敛到随机积分(Assumption 4(ii)的证明中,引用Ibragimov & Phillips, 2008)。
- BN分解(Beveridge-Nelson Decomposition):用于处理线性过程 \(\xi_t\) 的部分和(公式3.6的证明中)。
真实例子与应用¶
- 数据/场景:
- 澳大利亚最低温度曲线:36个气象站,80年(1943-2022)的年最低温度曲线。数据来自澳大利亚气象局。
- S&P 500股票对数价格曲线:209只股票,209个交易日(2023年1月3日至11月1日)的日内5分钟对数价格曲线。
- 方法应用:
- 温度数据:使用函数PCA(Section 3)。信息准则(公式4.3)选择了 \(q=2\) 个共同随机趋势。第一个趋势呈上升趋势,其载荷函数反映了澳大利亚的温度特征(年初和年末温度较高),被解释为全球变暖的随机趋势。第二个趋势在1943年和1973-1993年间有显著波动,其载荷函数捕捉了站点特定的年内温度动态。
- 股票价格数据:使用函数PANIC(Section 5),因为股票价格数据很可能存在非平稳的异质成分。信息准则(公式5.8)选择了 \(q=3\) 个共同随机趋势。BIC准则选择了协整秩 \(q^\ddagger = 0\),表明这三个趋势之间不存在协整关系,这与有效市场假说一致。进一步,将三个趋势的增量对Fama-French五因子进行回归,发现只有第一个趋势与市场因子显著相关。
- 结果与说明:
- 温度例子验证了函数PCA在非平稳函数面板中的有效性,并展示了其在实际气候数据分析中的应用价值。
- 股票价格例子展示了函数PANIC在处理可能含有非平稳异质成分的金融数据时的必要性,并得出了与金融理论(有效市场)一致的结论。两个例子共同说明了本文方法在不同数据特性下的适用性。
🔎 结论是否比证明窄¶
- 是的,存在一些泛化声明。例如,作者在引言和结论中声称模型“allows both the factors and factor loadings to be functional”,但在理论部分,他们实际上是通过级数展开(公式2.3)将函数因子 \(F_{jt}\) 与有限维的 \(G_t\) 联系起来的。严格来说,他们证明的是在级数近似下的估计理论,而非对任意无限维函数因子的直接估计。级数近似误差 \(\eta_{jt}\) 被假设为可忽略的(Assumption 2(ii)),但其在实际中的影响(如基函数的选择、截断参数 \(q\) 的选择)并未在理论中完全刻画。
- 另一个窄化:Theorem 3.2 和 3.3 的极限分布依赖于强假设(Assumption 3 & 4),如 \(N = o(T^3)\) 和关于 \(\langle \Lambda_i, \varepsilon_{it} \rangle\) 的CLT。这些条件在实际应用中可能难以验证。作者在Remark 3中承认了这一点,并指出当 \(q\) 固定时,条件可以简化。
四、开放问题¶
- 更一般的积分算子:本文的模型假设共同成分 \(\chi_{it}\) 通过一个线性积分算子 \(\mathcal{B}_{ij}\) 与函数因子 \(F_{jt}\) 相连。一个开放问题是,当这个算子是非线性或更一般的(如卷积算子)时,如何识别和估计?这扎根于本文的公式(2.2)及其对线性算子的依赖。
- 非参数因子模型:本文通过级数展开(公式2.3)将函数因子参数化。一个更一般的设定是允许函数因子 \(F_{jt}\) 本身就是一个非参数的非平稳过程,而不依赖于有限维的 \(G_t\)。这扎根于本文的公式(2.3)及其对基函数展开的依赖。作者在结论中未提及这种可能性。
- 计算效率与统计-计算权衡:本文的方法需要对一个 \(T \times T\) 矩阵进行特征分解,当 \(T\) 很大时计算成本很高。是否存在更快的算法(如随机化SVD、在线PCA)?更重要的是,是否存在统计上可识别但计算上困难(如需要指数时间)的问题设定?这扎根于本文未讨论的计算复杂性,以及研究者对“统计-计算权衡”的兴趣。
- 更复杂的非平稳性:本文只考虑了I(1)过程。将模型推广到I(2)或分数阶积分过程(如Li, Robinson & Shang, 2023),并建立相应的估计和推断理论,是一个自然但非平凡的扩展。这扎根于本文引言中引用的Beare & Seo (2020)和Franchi & Paruolo (2020)的工作,以及作者在结论中未提及的局限性。
Maintained by 陈星宇 · Homepage · Source on GitHub