diff --git a/_config.yml b/_config.yml
index e9f6b67..97cf2e0 100644
--- a/_config.yml
+++ b/_config.yml
@@ -84,7 +84,7 @@ pageviews:
# light — Use the light color scheme
# dark — Use the dark color scheme
#
-theme_mode: dark
+theme_mode:
# The CDN endpoint for media resources.
# Notice that once it is assigned, the CDN url
diff --git a/_includes/metadata-hook.html b/_includes/metadata-hook.html
new file mode 100644
index 0000000..c49e35b
--- /dev/null
+++ b/_includes/metadata-hook.html
@@ -0,0 +1,13 @@
+
+
+
diff --git a/_plugins/reliable-mathjax-loading.rb b/_plugins/reliable-mathjax-loading.rb
new file mode 100644
index 0000000..cc1de10
--- /dev/null
+++ b/_plugins/reliable-mathjax-loading.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+# Chirpy loads both the MathJax configuration and runtime with `async`.
+# That makes their execution order nondeterministic: the runtime can start
+# before the configuration that enables `$...$` inline delimiters.
+module ReliableMathJaxLoading
+ CONFIG_PATTERN = %r{}
+ POLYFILL_PATTERN = %r{}
+ RUNTIME_PATTERN = %r{}
+
+ def self.rewrite(html)
+ html
+ .sub(CONFIG_PATTERN, '')
+ .sub(POLYFILL_PATTERN, '')
+ .sub(RUNTIME_PATTERN, '')
+ end
+end
+
+Jekyll::Hooks.register %i[pages documents], :post_render do |document|
+ next unless document.output_ext == '.html' && document.data['math']
+
+ document.output = ReliableMathJaxLoading.rewrite(document.output)
+end
diff --git a/_posts/ai-auto-note/paper-reading/2026-07-30-int-vs-fp-fine-grained-low-bit-quantization-formats.md b/_posts/ai-auto-note/paper-reading/2026-07-30-int-vs-fp-fine-grained-low-bit-quantization-formats.md
new file mode 100644
index 0000000..8568c2b
--- /dev/null
+++ b/_posts/ai-auto-note/paper-reading/2026-07-30-int-vs-fp-fine-grained-low-bit-quantization-formats.md
@@ -0,0 +1,700 @@
+---
+title: "INT v.s. FP"
+date: 2026-07-30 16:02:41 +0800
+categories: ["ai-auto-note", "paper-reading"]
+tags: ["ai-auto-note", "paper-reading", "quantization", "low-bit", "int", "fp"]
+math: true
+---
+
+## 背景
+
+我在为量化库加入 rotation 接口时,使用了 rotation + NVFP4 作为例子。做消融实验时发现,rotation 几乎没有带来提升,甚至出现了负优化。于是想起了以前别人对我的指点:
+
+> 低精度量化里 int 比 fp 好是好在和旋转算法更亲和。实际上到了低精度阶段例如 4bit,fp 和 int 相差不大,而且低精度都是 per-group 量化,粒度很细,fp 的稠密区已经很难和小块内的分布匹配上了,int 和 fp 都差不多,更多的是每个芯片上会有自己的商业决策,有什么用什么。int 和 fp 的区别在 8bit 才比较明显,动态范围和精度甜区差得多。
+
+因此,我计划通过这篇论文系统学习 fine-grained 量化下 INT 和 FP 的误差差异,并解释自己的实验现象。
+
+## 论文信息
+
+- 标题:[INT v.s. FP: A Comprehensive Study of Fine-Grained Low-bit Quantization Formats](https://arxiv.org/pdf/2510.25602)
+- 代码:[ChenMnZ/INT_vs_FP](https://github.com/ChenMnZ/INT_vs_FP)
+
+### TL;DR
+
+在论文采用的 block size、AbsMax scaling、模型和量化流程范围内,主要结论是:
+
+- **8-bit:MXINT8 > MXFP8。** MXINT8 在 10,752 个真实 tensor 实例上的平均 QSNR 更高,并且在论文测试的 12 个模型上都取得了更小的 direct-cast 推理偏差。
+- **4-bit MX:MXFP4 > MXINT4。** 即使使用 random Hadamard rotation,MXINT4 在论文的张量和模型实验中仍未超过 MXFP4。
+- **4-bit NV:NVINT4 + Hadamard rotation > NVFP4。** 未旋转时二者平均 QSNR 接近,但 NVINT4 略低;rotation 降低 crest factor 后,NVINT4 才明确反超。
+- **INT对 Rotate 亲和性更好。** INT 的均匀量化步长直接受 block 最大值影响;FP 的非均匀码点本身已经能够缓解一部分动态范围问题,因此 rotation 对 FP 的收益通常较小,甚至可能略微降低 QSNR。
+- **在论文的硬件成本模型中,INT 更便宜。** 在 matched-throughput 的 gate-level 模型下,MXINT8 和 NVINT4 的面积、能耗均低于对应 FP 格式;但这不等同于真实 GPU 的端到端吞吐或功耗测试。
+
+论文使用 crest factor $ \kappa $ 表示 block 内 outlier 相对 RMS 的突出程度,并求出 INT 和 FP 理论 QSNR 的交点:
+
+| 格式比较 | INT 理论胜出的条件 |
+| --- | --- |
+| MXINT8 vs MXFP8 | κ < 7.55 |
+| MXINT6 vs MXFP6 | κ < 1.96 |
+| MXINT4 vs MXFP4 | κ < 2.04 |
+| NVINT4 vs NVFP4 | κ < 2.39 |
+
+block 越小,或者 Hadamard rotation 越能抑制离群值,$ \kappa $ 通常越低,INT 越有优势。不过,4-bit INT 的均匀码点较少,MXINT 还要承受 UE8M0 scale overhead;FP4 则利用 exponent 提供非均匀动态范围,因此 INT4 需要比 INT8 更低的 $ \kappa $ 才能胜出。
+
+ **rotation + NVFP4 没有提升,甚至略有负优化** 的原因:
+
+1. group-wise=16 是很细的粒度,并且 nvfp4 的 exponent 已经能够覆盖大部分 block 内的动态范围,因此 rotation 对 NVFP4 的提升有限,甚至没有提升;
+2. rotation 本身并不会偏向某一种 dtype,但它会改变 block 内的幅值分布。对 NVINT4 而言,outlier 被平滑后,AbsMax scale 和均匀量化步长会直接缩小;对 NVFP4 而言,E2M1 的 exponent 动态范围优势随之减弱,而 1-bit mantissa 的局部精度限制开始占主导。旋转后的 crest factor 低于 NVINT4/NVFP4 的 crossover point,因此 NVINT4 能够在相同的旋转后张量上系统性地超过 NVFP4。
+
+因此,rotation 并不是与所有低比特格式都能正交叠加的通用增益项。它更像是在降低数据分布对均匀量化器的不友好程度:对于 INT4,rotation 可能决定能否越过 crossover point;对于 NVFP4,则可能没有收益。
+
+### 具体实验
+
+论文比较的都是较细粒度的 block-wise 格式:
+
+| Format | Block Size | Max Value | Min Value | Dynamic Range | Scale-1 | Scale-2 |
+| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
+| MXFP8(E4M3) | 32 | $ \pm448 $ | $ 2^{-9} $ | $ 1.75\times2^{17} $ | UE8M0 | - |
+| MXINT8 | 32 | $ \pm127 $ | $ 1 $ | 127 | UE8M0 | - |
+| MXFP6(E2M3) | 32 | $ \pm7.5 $ | $ 0.125 $ | 60 | UE8M0 | - |
+| MXINT6 | 32 | $ \pm31 $ | $ 1 $ | 31 | UE8M0 | - |
+| MXFP4(E2M1) | 32 | $ \pm6 $ | $ 0.5 $ | 12 | UE8M0 | - |
+| MXINT4 | 32 | $ \pm7 $ | $ 1 $ | 7 | UE8M0 | - |
+| NVFP4 | 16 | $ \pm6 $ | $ 0.5 $ | 12 | E4M3 | FP32 |
+| NVINT4 | 16 | $ \pm7 $ | $ 1 $ | 7 | E4M3 | FP32 |
+
+表中的动态范围只描述元素 codebook,不包含 block scale 扩展后的整体动态范围。
+
+| 理论 QSNR | 实测 QSNR |
+| --- | --- |
+|
|
|
+
+- **QSNR:** 越高表示相对量化误差越小。
+- **crest factor:** 峰值因子,用于衡量一组数中的最大绝对值相对整体典型大小有多突出;在这里用于表征离群值严重程度。
+- **Figure 4 的数据来源:** Figure 4 不是先用低精度模型完成推理再采集数据,而是先运行 BF16 模型采集真实张量,再对这些张量做离线 fake quantization。
+- Figure 4(a) 是原始张量结果;Figure 4(b) 在量化前对 INT 和 FP 张量都应用了 random Hadamard rotation。**NVINT4 相对 NVFP4 的 tensor-wise win rate 从 64.3% 提升到 99.3%**;平均 QSNR 从 20.55 dB 提升到 21.65 dB。NVFP4 的平均 QSNR 则从 20.60 dB 小幅降至 20.35 dB,这与我的实验现象一致。
+- Figure 4 中的每个点对应一个完整 tensor 实例:横坐标是该 tensor 内所有 block 的平均 crest factor,纵坐标是整个 tensor 的 QSNR。因此它不是逐 block 的散点图,平均 crest factor 相同的 tensor 仍可能具有不同 QSNR。
+- direct-cast inference 使用 Qwen3 和 Llama 3 系列共 12 个模型,覆盖 dense 和 MoE 架构,并以量化模型相对 BF16 模型 top-25 logits 的 KL divergence 衡量偏差。加入 rotation 后,MXINT8 和 NVINT4 均在 12/12 个模型上胜出,MXINT4 仍为 0/12。
+- 训练实验只比较 8-bit:论文在 1B/100B tokens 和 3B/200B tokens 的训练中发现,MXINT8、MXFP8 与 BF16 的 loss 曲线接近;对 INT 使用对称范围 $ [-127,127] $,可以避免 two's-complement 非对称范围引入的梯度负偏。
+
+实测的 QSNR–crest factor 关系与理论曲线的整体趋势较为一致。
+
+### 理论误差是如何计算的
+
+#### TL;DR
+
+Figure 3 不是通过真实模型实验得到的,而是由理论量化误差公式计算出来的。整体流程是:
+
+> 假设 block 内数据近似服从高斯分布
+> → 使用 crest factor κ 描述 block 内的离群程度
+> → 推导 INT 和 FP 的相对量化误差
+> → 转换为 QSNR
+> → 扫描不同的 κ
+> → 找到 INT 和 FP 曲线的交点
+
+对于 INT,实际 block scale 同时也是均匀量化步长。使用 round-to-nearest 且不发生 clipping 时:
+
+$$
+\mathbb{E}[e^2]
+\approx
+\frac{\Delta^2}{12}
+$$
+
+最终得到:
+
+$$
+\mathrm{QSNR}_{\mathrm{INT}}
+\approx
+4.78
++
+6.02b
+-
+20\log_{10}\rho
+-
+20\log_{10}\kappa
+$$
+
+因此,bit 数 $ b $ 越高,INT 的 QSNR 越高;crest factor $ \kappa $ 或 UE8M0 scale overhead $ \rho $ 越大,INT 的 QSNR 越低。
+
+对于 FP,误差主要分为 normal 和 subnormal 两部分。数据主要位于 normal 区域时,FP 的精度上限主要由 mantissa bit 数 $ M $ 决定:
+
+$$
+\mathrm{QSNR}_{\mathrm{FP}}
+\approx
+13.80+6.02M
+$$
+
+因此,FP 的 QSNR 更接近一条由 mantissa 精度决定的水平线,而 INT 的 QSNR 会随着 $ \kappa $ 增大而下降。令两种格式的理论 QSNR 相等,就能得到 crossover point。
+
+#### 1. 数据分布假设
+
+论文假设一个包含 $ g $ 个元素的量化 block:
+
+$$
+X=(X_1,\ldots,X_g)
+$$
+
+block 中的元素独立同分布:
+
+$$
+X_i\sim\mathcal{N}(0,\sigma^2)
+$$
+
+在这个假设下,block 的 RMS 可以近似为 $ \sigma $。
+
+crest factor 定义为:
+
+$$
+\kappa
+=
+\frac{
+\max_i |X_i|
+}{
+\sqrt{
+\frac{1}{g}
+\sum_{i=1}^{g}X_i^2
+}
+}
+\approx
+\frac{\max_i |X_i|}{\sigma}
+$$
+
+因此:
+
+$$
+\max_i |X_i|
+\approx
+\kappa\sigma
+$$
+
+$ \kappa $ 越大,表示 block 中的峰值相对普通数值越突出,也就是离群值越严重。
+
+#### 2. Scale 的计算
+
+对于 AbsMax 量化,理想 scale 为:
+
+$$
+s
+=
+\frac{\max_i |X_i|}{Q_{\max}}
+=
+\frac{\kappa\sigma}{Q_{\max}}
+$$
+
+其中,$ Q_{\max} $ 是目标数据格式的最大正数值。例如,对称 INT4 的表示范围是 $ [-7,7] $,所以:
+
+$$
+Q_{\max}=7
+$$
+
+通过 AbsMax 计算得到的理想 scale 是高精度实数,但实际格式需要使用指定的低精度 scale dtype 表示。论文使用 $ \rho $ 建模 low-precision scale overhead:
+
+$$
+s'=\rho s
+$$
+
+其中:
+
+- $ s $ 是通过 AbsMax 计算得到的高精度理想 scale;
+- $ s' $ 是按照目标 scale dtype 表示后实际使用的 scale;
+- $ \rho $ 是低精度 scale 表示相对理想 scale 引入的放大比例。
+
+对于 MX 格式,scale 使用 UE8M0,只能表示 2 的整数次幂。为了避免 clipping,论文将理想 scale 向上舍入:
+
+$$
+s'
+=
+2^{\left\lceil\log_2s\right\rceil}
+=
+\rho s
+$$
+
+因此:
+
+$$
+1\leq\rho<2
+$$
+
+Figure 3 为了画出一条代表性的理论曲线,对 MX 格式固定采用:
+
+$$
+\rho=1.5
+$$
+
+论文没有给出 $ 1.5 $ 的真实数据拟合或统计推导;它是用于模拟 UE8M0 scale overhead 的启发式代表值。实际量化时,每个 block 的 $ \rho $ 会随理想 scale 改变,因此 crossover point 也会相应移动。
+
+对于使用 E4M3 block scale 的 NV 格式,论文在理论分析中近似令 $ \rho=1 $。
+
+#### 3. INT 的理论 QSNR
+
+INT 使用均匀量化,所有相邻量化值之间的间隔相同。实际使用的 block scale 同时也是相邻反量化码点之间的量化步长:
+
+$$
+\Delta
+=
+s'
+=
+\frac{\rho\kappa\sigma}{Q_{\max}}
+$$
+
+对于论文采用的对称 $ b $ bit INT:
+
+$$
+Q_{\max}=2^{b-1}-1
+$$
+
+所以精确地写为:
+
+$$
+\Delta
+=
+\frac{\rho\kappa\sigma}{2^{b-1}-1}
+$$
+
+理论推导为了得到更简洁的表达式,使用:
+
+$$
+2^{b-1}-1
+\approx
+2^{b-1}
+$$
+
+从而得到:
+
+$$
+\Delta
+\approx
+\frac{\rho\kappa\sigma}{2^{b-1}}
+$$
+
+在经典的高分辨率均匀量化假设下,如果 quantizer 使用 round-to-nearest 且不发生 clipping,量化误差近似均匀分布在:
+
+$$
+\left[
+-\frac{\Delta}{2},
+\frac{\Delta}{2}
+\right]
+$$
+
+$ \Delta/2 $ 是最大绝对舍入误差;QSNR 使用的是误差平方的平均值。对该均匀分布求均方值可得:
+
+$$
+\mathbb{E}[e^2]
+\approx
+\frac{\Delta^2}{12}
+$$
+
+代入量化步长:
+
+$$
+\mathbb{E}[e^2]
+\approx
+\frac{
+\rho^2\kappa^2\sigma^2
+}{
+12\cdot2^{2(b-1)}
+}
+$$
+
+由于 $ X\sim\mathcal{N}(0,\sigma^2) $ 且均值为 0,原始数据的均方值为:
+
+$$
+\mathbb{E}[X^2]=\sigma^2
+$$
+
+这里的“signal power”不是物理功率,而是原始张量元素的平均平方值,也就是 RMS 的平方。用量化误差的均方值除以原始数据的均方值,得到相对均方误差:
+
+$$
+\frac{\mathbb{E}[e^2]}{\sigma^2}
+\approx
+\frac{
+(\rho\kappa)^2
+}{
+12\cdot2^{2(b-1)}
+}
+$$
+
+根据 QSNR 的定义:
+
+$$
+\mathrm{QSNR}_{\mathrm{INT}}
+=
+-10\log_{10}
+\left(
+\frac{\mathbb{E}[e^2]}{\sigma^2}
+\right)
+$$
+
+代入展开得到:
+
+$$
+\boxed{
+\mathrm{QSNR}_{\mathrm{INT}}
+\approx
+4.78
++
+6.02b
+-
+20\log_{10}\rho
+-
+20\log_{10}\kappa
+}
+$$
+
+这个公式表明:
+
+- 位宽 $ b $ 每增加 1 bit,QSNR 大约提高 $ 6.02\,\mathrm{dB} $;
+- crest factor $ \kappa $ 越大,INT 的 QSNR 越低;
+- $ \kappa $ 每翻倍,INT 的 QSNR 大约下降 $ 6.02\,\mathrm{dB} $;
+- scale overhead $ \rho $ 越大,INT 的 QSNR 越低;
+- block 越小,局部 crest factor 通常越低,因此 INT 越有优势。
+
+INT 对 crest factor 敏感的原因是,整个 block 使用固定的均匀量化步长:
+
+$$
+\ldots,-2\Delta,-\Delta,0,\Delta,2\Delta,\ldots
+$$
+
+如果某个离群值将 block 的最大绝对值拉大,量化步长 $ \Delta $ 也会随之增大,导致大量普通数值被量化到相同的码点。
+
+对于使用高精度 E4M3 block scale 的 NVINT,论文给出的近似公式为:
+
+$$
+\mathrm{QSNR}_{\mathrm{NVINT}}
+\approx
+4.78
++
+6.02b
+-
+20\log_{10}\kappa
++
+10\log_{10}
+\left(
+\frac{g}{g-1}
+\right)
+$$
+
+其中,$ g $ 是 block size;对 NVINT4 而言,$ g=16 $。额外的修正项:
+
+$$
+10\log_{10}
+\left(
+\frac{g}{g-1}
+\right)
+$$
+
+来自 block 最大值可以被较准确表示这一性质。
+
+#### 4. FP 的理论 QSNR
+
+FP 的量化间隔不是固定的,而是随着 exponent 变化。论文将 FP 的量化误差分成两个区域:
+
+- **normal 区域:** 有效数字包含隐含的前导 $ 1 $,量化间隔会随着 exponent 增大而扩大,因此具有近似固定的相对精度。
+- **subnormal 区域:** 用于表示靠近 $ 0 $、但小于最小 normal number 的非零数。此时不再使用隐含的前导 $ 1 $,量化间隔固定,因此不再具有固定的相对精度。
+
+以 E2M1 为例:
+
+- zero:$ 0 $;
+- subnormal:$ \pm0.5 $;
+- normal:$ \pm1 $、$ \pm1.5 $、$ \pm2 $、$ \pm3 $、$ \pm4 $、$ \pm6 $。
+
+经过 block scale 缩放后,最小 normal number 在原始数据域中的阈值为:
+
+$$
+T_N
+=
+s'2^{1-B}
+$$
+
+论文定义:
+
+$$
+p_{\mathrm{sub}}
+=
+\mathbb{P}(|X| .container {
+ width: 100%;
+ max-width: 1600px;
+ }
+ }
+
+ main.col-12,
+ #tail-wrapper {
+ width: 100%;
+ max-width: 100%;
+ }
+
+ #sidebar-trigger i::before {
+ content: '\f054';
+ }
+ }
+}
+
+@media (min-width: 1200px) {
+ html[data-sidebar-collapsed] {
+ main.col-xl-9,
+ #tail-wrapper.col-xl-9 {
+ width: 100%;
+ max-width: 1280px;
+ margin-right: auto;
+ margin-left: auto;
+ }
+
+ #panel-wrapper.col-xl-3 {
+ display: none;
+ }
+ }
+}
+
+#sidebar .sidebar-bottom #mode-toggle {
+ min-width: 44px;
+ min-height: 44px;
+ cursor: pointer;
+}
+
+#sidebar .sidebar-bottom #mode-toggle:focus-visible {
+ outline: 2px solid var(--link-color);
+ outline-offset: 2px;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ #sidebar,
+ #main-wrapper {
+ transition: none;
+ }
+}
diff --git a/_sass/warm-light-theme.scss b/_sass/warm-light-theme.scss
new file mode 100644
index 0000000..c87c72d
--- /dev/null
+++ b/_sass/warm-light-theme.scss
@@ -0,0 +1,101 @@
+@mixin warm-light-colors {
+ color-scheme: light;
+
+ /* Warm, paper-like surfaces */
+ --main-bg: #f5f0e3;
+ --main-border-color: #ded5c2;
+ --mask-bg: #a79f91;
+ --card-bg: #faf7ef;
+ --card-hovor-bg: #ebe2cf;
+ --button-bg: #faf7ef;
+
+ /* Warm neutral typography */
+ --text-color: #3d3931;
+ --text-muted-color: #6d665a;
+ --text-muted-highlight-color: #514b41;
+ --heading-color: #29261f;
+ --label-color: #514b41;
+ --post-list-text-color: #625c51;
+
+ /* Muted terracotta accents */
+ --link-color: #8a492c;
+ --link-underline-color: #cdbca7;
+ --toc-highlight: #8a492c;
+ --checkbox-checked-color: #9b5635;
+ --btn-share-hover-color: #8a492c;
+
+ /* Sidebar and top bar */
+ --site-title-color: #4c463c;
+ --site-subtitle-color: #746c5e;
+ --sidebar-bg: #ece5d5;
+ --sidebar-border-color: #d8ceba;
+ --sidebar-muted-color: #625b4f;
+ --sidebar-active-color: #2f2b24;
+ --sidebar-hover-bg: #ded4c1;
+ --sidebar-btn-bg: #f7f2e7;
+ --sidebar-btn-color: #6d6558;
+ --avatar-border-color: #faf7ef;
+ --topbar-bg: rgb(245, 240, 227, 0.88);
+ --topbar-text-color: #514b41;
+ --search-border-color: #d8ceba;
+ --search-icon-color: #8b8274;
+ --input-focus-border-color: #a99d8b;
+
+ /* Dividers, tables, tags, and controls */
+ --btn-border-color: #d8ceba;
+ --btn-backtotop-color: #625b4f;
+ --btn-backtotop-border-color: #d8ceba;
+ --btn-patinator-text-color: #514b41;
+ --btn-paginator-hover-color: #e4dac7;
+ --blockquote-border-color: #cfc2aa;
+ --blockquote-text-color: #665f53;
+ --toc-popup-border-color: #d8ceba;
+ --tag-border: #d4c8b3;
+ --tag-shadow: #ded5c2;
+ --tag-hover: #e4dac7;
+ --search-tag-bg: #ece4d5;
+ --categories-border: #d8ceba;
+ --categories-hover-bg: #e4dac7;
+ --timeline-color: #d8ceba;
+ --timeline-node-bg: #a99d8b;
+ --timeline-year-dot-color: #f5f0e3;
+ --tb-odd-bg: #f0eadc;
+ --tb-border-color: #ded5c2;
+ --dash-color: #b7ab98;
+ --kbd-wrap-color: #b7ab98;
+ --kbd-bg-color: #ebe3d3;
+
+ /* Code and image placeholders */
+ --language-border-color: #d8ceba;
+ --highlight-bg-color: #ebe5d8;
+ --inline-code-bg: rgb(92, 76, 53, 0.09);
+ --code-color: #493f34;
+ --code-header-text-color: #746b5e;
+ --code-header-muted-color: #d8ceba;
+ --code-header-icon-color: #948979;
+ --img-bg: radial-gradient(circle, #faf7ef 0%, #e8e0d1 100%);
+ --shimmer-bg: linear-gradient(
+ 90deg,
+ rgb(245, 240, 227, 0) 0%,
+ #ded5c2 50%,
+ rgb(245, 240, 227, 0) 100%
+ );
+
+ .highlight,
+ .highlight .w {
+ background-color: var(--highlight-bg-color);
+ }
+}
+
+@media (prefers-color-scheme: light) {
+ html:not([data-mode]),
+ html[data-mode='light'] {
+ @include warm-light-colors;
+ }
+}
+
+@media (prefers-color-scheme: dark) {
+ html[data-mode='light'] {
+ @include warm-light-colors;
+ }
+}
diff --git a/assets/css/jekyll-theme-chirpy.scss b/assets/css/jekyll-theme-chirpy.scss
new file mode 100644
index 0000000..c08e0c2
--- /dev/null
+++ b/assets/css/jekyll-theme-chirpy.scss
@@ -0,0 +1,10 @@
+---
+---
+
+@use 'main
+{%- if jekyll.environment == 'production' -%}
+ .bundle
+{%- endif -%}
+';
+@use 'sidebar-controls';
+@use 'warm-light-theme';
diff --git a/assets/img/int-vs-fp-empirical-qsnr.png b/assets/img/int-vs-fp-empirical-qsnr.png
new file mode 100644
index 0000000..e9451c9
Binary files /dev/null and b/assets/img/int-vs-fp-empirical-qsnr.png differ
diff --git a/assets/img/int-vs-fp-theoretical-qsnr.png b/assets/img/int-vs-fp-theoretical-qsnr.png
new file mode 100644
index 0000000..0dbab53
Binary files /dev/null and b/assets/img/int-vs-fp-theoretical-qsnr.png differ
diff --git a/assets/js/sidebar-controls.js b/assets/js/sidebar-controls.js
new file mode 100644
index 0000000..3e76960
--- /dev/null
+++ b/assets/js/sidebar-controls.js
@@ -0,0 +1,77 @@
+(() => {
+ const desktop = window.matchMedia('(min-width: 850px)');
+ const storageKey = 'sidebar-collapsed';
+
+ function readPreference() {
+ try {
+ return localStorage.getItem(storageKey) === 'true';
+ } catch (_) {
+ return false;
+ }
+ }
+
+ function writePreference(collapsed) {
+ try {
+ localStorage.setItem(storageKey, String(collapsed));
+ } catch (_) {
+ // Keep the interaction working even when storage is unavailable.
+ }
+ }
+
+ function applyState(collapsed) {
+ const active = desktop.matches && collapsed;
+ const trigger = document.getElementById('sidebar-trigger');
+
+ document.documentElement.toggleAttribute('data-sidebar-collapsed', active);
+
+ if (!trigger) {
+ return;
+ }
+
+ trigger.setAttribute('aria-controls', 'sidebar');
+ trigger.setAttribute('aria-expanded', String(!active));
+
+ if (desktop.matches) {
+ const label = active ? '展开左侧个人信息' : '收起左侧个人信息';
+ trigger.setAttribute('aria-label', label);
+ trigger.setAttribute('title', label);
+ } else {
+ trigger.setAttribute('aria-label', '打开导航菜单');
+ trigger.removeAttribute('title');
+ }
+ }
+
+ function handleTrigger(event) {
+ if (!desktop.matches) {
+ return;
+ }
+
+ event.preventDefault();
+ event.stopImmediatePropagation();
+
+ const collapsed = !document.documentElement.hasAttribute('data-sidebar-collapsed');
+ writePreference(collapsed);
+ applyState(collapsed);
+ }
+
+ function init() {
+ const trigger = document.getElementById('sidebar-trigger');
+
+ if (!trigger) {
+ return;
+ }
+
+ trigger.addEventListener('click', handleTrigger, { capture: true });
+ applyState(readPreference());
+
+ desktop.addEventListener('change', () => {
+ applyState(readPreference());
+ });
+ }
+
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', init, { once: true });
+ } else {
+ init();
+ }
+})();