academic-pdf-to-gfm について
学術 PDF を GitHub で表示できる GFM に変換するワークフロースキルです。研究論文を Markdown 化する際、ページごとに抽出方法を切り替えてテキスト、数式、表、図を扱い、出力を検証します。
主な機能
- 01ページ単位の PDF 振り分け
- 02300 DPI でのページ描画
- 03テキストと LaTeX の抽出手順
- 04Markdown 表への変換
- 05図の抽出と説明の手順
- 06公開前の数式検証
活用シーン
- 01研究論文の GitHub Markdown 化
- 02PDF 変換での数式と表の保持
- 03OCR が文字を返さない図の処理
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ terrylica/ cc-skills --skill academic-pdf-to-gfmインストール後、Claude Code で/academic-pdf-to-gfmを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
evals/evals.jsonreferences/github-math-support-table.mdpdf-type-detection.mdvalidate-math.mjs詳細
学術論文 PDF → GitHub GFM 変換
学術論文や研究論文の PDF を、インライン画像、数学的に正確な LaTeX、検証済みの出力を備えた、GitHub で表示可能な GFM Markdown に変換する、実績のあるワークフローです。
検証済みの対象:López de Prado(2026)「How to Use the Sharpe Ratio」 — 51 ページ、82 個の数式、8 枚の図。
進化するスキル:このスキルは使用するたびに改善されます。手順に誤りがある場合、パラメーターがずれた場合、または回避策が必要だった場合は、後回しにせず、ただちにこのファイルを修正してください。更新するのは、実際に再現可能な問題がある場合に限ります。
クイックスタート — ページごとの振り分けワークフロー
PDF 全体に単一の抽出方法を適用しようとしないでください。 現代の学術論文では、テキスト、表、図が混在しています。ページごとに振り分けてください。
手順 1:すべてのページを 300 DPI でレンダリングする
# Generate PNG for every page at 300 DPI
uv run --python 3.14 --with pymupdf python3 << 'EOF'
import fitz, os
doc = fitz.open('paper.pdf')
os.makedirs("pages", exist_ok=True)
for i in range(len(doc)):
pix = doc[i].get_pixmap(matrix=fitz.Matrix(300/72, 300/72), alpha=False)
pix.save(f"pages/page{i:04d}.png")
print(f"Page {i}: {pix.width}×{pix.height}")
EOF
手順 2:各ページの種類を検出する
# Locate the Unlimited-OCR script. If installed via marketplace, it will be in the cc-skills plugin directory.
# If running from the cc-skills repo directly:
S=${S:-~/eon/cc-skills/plugins/unlimited-ocr/scripts/unlimited_ocr.py}
# For each page, run Unlimited-OCR and inspect the <|det|> markers
for img in pages/page*.png; do
echo "=== $(basename $img) ==="
uv run --no-project $S parse --input "$img" --collapse-math-spacing --quiet 2>&1 | \
grep "<|det|>" | cut -d'>' -f2 | cut -d' ' -f1 | sort | uniq -c
done
手順 3:各ページを振り分ける
検出された <|det|> マーカーに基づいて振り分けます。
| 検出内容 | 振り分け先 | コマンド |
|---|---|---|
text のみ(equation、image、chart なし) | pymupdf4llm または pdftotext | 下記のツール比較を参照 |
equation または table がある | Unlimited-OCR(--table-format pipe を指定) | uv run --no-project $S parse --input page.png |
image または chart がある | 分割して説明する | unlimited-ocr-segment-figure スキルとビジョンモデルを使用 |
混在(table + image) | 表には Unlimited-OCR、画像には分割を使用 | 出力を分割し、画像を個別に振り分ける |
手順 4:組み立てて検証する
# Concatenate all page outputs
cat pages/page*.md > paper-raw.md
# Extract embedded images (optional)
uv run --python 3.14 --with pymupdf python3 references/extract-images.py paper.pdf
# Validate math before pushing
node references/validate-math.mjs paper-raw.md --fix
ツールの比較(ページの種類別)
1 本の学術論文 PDF では、ほとんどのページがデジタル生成された文章で、数式や図が多いページは一部だけというケースがよくあります。 文書全体を 1 つの種類として処理すると、機能を活用できず、コンテンツが気づかれないまま失われます。
ページごとの振り分け戦略
PDF の各ページについて、次の手順を実行します。
- 300 DPI でレンダリングして PNG にします(Unlimited-OCR の精度に必要です。150 DPI では気づかれないまま誤った内容が生成されます)
- Unlimited-OCR をローカルで実行して、ページの種類を検出します(Apple Silicon では 1 ページあたり約 2.4 秒)
- モデルが検出した内容に基づいて振り分けます:
- テキストのみのページ(数式やグラフがない):
pymupdf4llmまたはpdftotextで抽出します(低コストで、構造を維持できます) - 数式を含むページ:Unlimited-OCR の出力を使用します(実際の LaTeX を返します。例:
\left\{ \begin{array} ... \end{array} \right\}) - グラフを含むページ:Unlimited-OCR で分割し、各パネルをビジョンモデルに渡して説明させます(2026-07-31 に検証済み:グラフに対して Unlimited-OCR は空のテキストを返します)
- フォールバック:ページのテキストレイヤーからの抽出内容が少なすぎる場合は、Unlimited-OCR で再実行します
- テキストのみのページ(数式やグラフがない):
ページごとの振り分けが重要な理由
気づかれない失敗です。 Unlimited-OCR はグラフを正確なバウンディングボックスで特定しますが、その内側の文字は 1 文字も返しません。グラフの多い入力に対して、文書全体を「タイプ C、Unlimited-OCR を使用」として処理した場合、グラフのコンテンツがすべて失われるにもかかわらず、形式の整った結果が出力されるため、出力を確認するまで問題に気づきません。
検証済み(2026-07-31):Unlimited-OCR は(<|det|>chart マーカーを介して)グラフを検出し、正確なバウンディングボックスを返しますが、その内側のテキストは 1 文字も返しません。グラフだけを含むページ(テキスト、数式、表を含まないページ)は実際に空の結果になります。ページごとの振り分けにより、そうしたページをテキストレイヤーからの抽出または手動確認に回せます。
ページタイプの判定(300 DPI で測定)
すべてのページで Unlimited-OCR を実行し、<|det|> マーカーを確認します。
| 出力に含まれるもの | 推定されるタイプ | 振り分け先 |
|---|---|---|
equation または chart を含まない text 領域 | テキストのみのページ | pymupdf4llm または pdftotext(フォールバック:Unlimited-OCR) |
equation 領域 | 数式を含むページ | Unlimited-OCR(実際の LaTeX を返します) |
chart 領域 | 図を含むページ | セグメント化して説明(unlimited-ocr-segment-figure を使用し、その後、チャート読み取りモデルを使用) |
| 空の出力(文字数ゼロ、領域なし) | テキストレイヤーで処理されていない可能性のあるページ | Unlimited-OCR で再試行するか、手動で確認 |
例:TimeMixer(ICLR 2024、28 ページ)
/Users/<you>/eon/<project>/data/papers/<hash>.pdf で 2026-07-31 に検証済み:
ページ 0 — 要旨を含むタイトルページ(テキスト抽出に振り分け)
# Render at 300 DPI
uv run --python 3.14 --with pymupdf python3 -c "
import fitz
doc = fitz.open('timemixer-iclr-2024.pdf')
pix = doc[0].get_pixmap(matrix=fitz.Matrix(300/72, 300/72), alpha=False)
pix.save('page0.png')
"
# Detect structure
S=~/eon/cc-skills/plugins/unlimited-ocr/scripts/unlimited_ocr.py
uv run --no-project $S parse --input page0.png --collapse-math-spacing --quiet 2>&1 | head -15
出力(実際のもの):
<|det|>header [173, 33, 482, 49]<|/det|>Published as a conference paper at ICLR 2024
<|det|>title [172, 99, 818, 149]<|/det|>TIMEMIXER: DECOMPOSABLE MULTISCALE MIXING FOR TIME SERIES FORECASTING
<|det|>text [181, 170, 777, 200]<|/det|>Shiyu Wang \( ^{1,*} \) , Haixu Wu \( ^{2,*} \) , Xiaoming Shi \( ^{1} \) , Tengge Hu \( ^{2} \) , Huakun Luo \( ^{2} \) , Lintao Ma \( ^{1✉} \) , James Y. Zhang \( ^{1} \) , Jun Zhou \( ^{1✉} \)
<|det|>text [182, 200, 781, 243]<|/det|>\( ^{1} \) Ant Group, Hangzhou, China \( ^{2} \) Tsinghua University, Beijing, China {weiming.wsy,lintao.mlt,peter.sxm,james.z,jun.zhoujun}@antgroup.com, {wuhx23,htg21,luhk19}@mails.tsinghua.edu.cn
<|det|>title [452, 279, 547, 293]<|/det|>ABSTRACT
<|det|>text [230, 311, 770, 575]<|/det|>Time series forecasting is widely used in extensive applications, such as traffic planning…
振り分けの判断: header、title、text 領域のみ検出されました。equation も chart もありません → pymupdf4llm または pdftotext に振り分けます(高速で、構造を保持します)。
ページ 6 — ベンチマーク表(Unlimited-OCR に振り分け)
uv run --no-project $S parse --input page6.png --collapse-math-spacing --quiet 2>&1 | head -20
出力(実際のもの):
<|det|>text [187, 114, 812, 129]<|/det|>Table 1: Summary of benchmarks. Forecastability is one minus the entropy of Fourier domain.
<|det|>table [175, 131, 825, 287]<|/det|>| Tasks | Dataset | Variate | Predict Length | Frequency | Forecastability | Information |
| Long-term forecasting | ETT (4 subsets) | 7 | 96~720 | 15 mins | 0.46 | Temperature |
| Weather | 21 | 96~720 | 10 mins | 0.75 | Weather |
| Solar-Energy | 137 | 96~720 | 10min | 0.33 | Electricity |
…
振り分けの判断: table が検出されました → Unlimited-OCR の出力をそのまま使います(すでにパイプ形式の Markdown になっており、--table-format pipe が HTML を Markdown に変換します)。
ページ 7 — 図と表が混在するページ(表のみ Unlimited-OCR に振り分け)
uv run --no-project $S parse --input page7.png --collapse-math-spacing --quiet 2>&1 | head -30
出力(実際のもの):
<|det|>table [186, 174, 819, 384]<|/det|>| Case | Decompose | Past mixing | Future mixing | M4 | PEMS04 | ETTm1 |
…
注: PyMuPDF で確認したところ、ページ 7 には PDF に埋め込まれた画像オブジェクトが 6 個ありますが、Unlimited-OCR の 300 DPI スクリーンショットレンダリングでは、image または image_caption 領域は検出されません。画像は別途 references/extract-images.py で抽出し、説明のためにビジョンモデルに振り分けます。
振り分けの判断: table が検出されました → Unlimited-OCR の出力をそのまま使います。埋め込み画像は別途抽出し、説明のためにビジョンモデルに渡します(unlimited-ocr-segment-figure スキルを参照)。
タイプの分類(過去の情報、参考用に保持)
タイプ A — Word で生成された PDF(タイプ A:現代の学術論文の大半)
特徴:フォントが埋め込まれている、テキストをコピーできる、コピー&ペースト時に Unicode の数式文字(∑、π、α、β、γ、→)が表示される
数式のエンコード方式:数式は PDF ストリーム内の Unicode テキストです。画像でも、グリフマップでもありません。
結果:marker-pdf などの OCR ツールでは LaTeX を抽出できません。「\gamma_4」ではなく「γ₄」のようなテキストとして認識します。空の出力を返したり、気付かれないままクラッシュしたりすることがあります。
タイプ B — LaTeX で生成された PDF
特徴:Computer Modern フォント、正確な数式の間隔、arxiv.org でソースを入手できる
数式のエンコード方式:グリフマップ方式で、構造を部分的に抽出できます。
タイプ C — スキャン画像の PDF
特徴:すべてのページがラスター画像で、コピー可能なテキストがありません。
表の形式に関する注意
Unlimited-OCR の表は HTML の <table> マークアップとして出力されます(Baidu による測定では、実際の表の約 88% に相当)。CLI はデフォルトでパイプ形式の Markdown に変換します(--table-format pipe)。この形式は Markdown ドキュメントに適しています。複数のリーダー間で出力を比較する場合は、パイプ形式の Markdown を標準形式とします。
ツールの比較
| ツール | ページの種類 | インストール | メリット | デメリット |
|---|---|---|---|---|
| pymupdf4llm | テキストのみ、ネイティブテキストレイヤー | uv run --with pymupdf4llm | 構造の保持に最適、高速 | 数式は LaTeX ではなく Unicode で出力される |
| pdftotext | テキストのみ、プレーンな抽出 | brew install poppler | 非常に高速、依存関係が最小限 | 表の構造が完全に失われる |
| Unlimited-OCR | 表、数式、混在ページ | uv run --no-project (インストール不要) | 実際の LaTeX 数式、パイプ形式の Markdown 表、レイアウトボックス、300 DPI の高精度 | グラフのテキストは空で返される。該当する場合は segment-figure を使用する |
| markitdown | テキストのみの代替手段 | uv run --with 'markitdown[pdf]' | 妥当な構造 | わずかに間隔が広すぎる。数式の制限は pymupdf4llm と同じ |
| marker-pdf | スキャン PDF(Type C のみ) | pip install marker-pdf | スキャン画像に対応 | Type A/B では絶対に使用しないでください — 無言で失敗する(Unicode テキストのバグ) |
推奨:ページごとに振り分ける場合:
- テキストのみのページ →
pymupdf4llm(書式を保持)またはpdftotext(速度重視) - 表/数式のあるページ → Unlimited-OCR(実際の LaTeX とパイプ形式の Markdown 表を出力)
- グラフのあるページ → Unlimited-OCR(グラフを検出するものの、テキストは空で返される。説明には
segment-figureスキルとビジョンモデルに振り分ける) - 混在ページ → Unlimited-OCR(1 回の処理で表とレイアウト検出に対応。画像は別途セグメント化)
画像の抽出
references/extract-images.py を保存します:
import fitz, os, sys
doc = fitz.open(sys.argv[1])
os.makedirs("references/media", exist_ok=True)
saved = []
for page_num in range(len(doc)):
for img_idx, img in enumerate(doc[page_num].get_images(full=True)):
xref = img[0]
base_image = doc.extract_image(xref)
img_bytes = base_image["image"]
if len(img_bytes) < 2048: # skip icons/logos/watermarks/rules
continue
ext = base_image["ext"]
fname = f"fig-p{page_num+1:02d}-{img_idx+1:02d}.{ext}"
with open(f"references/media/{fname}", "wb") as f:
f.write(img_bytes)
saved.append((page_num+1, fname, base_image.get("width"), base_image.get("height")))
print(f"Saved: {fname} ({len(img_bytes)//1024}KB, {base_image.get('width')}×{base_image.get('height')})")
doc.close()
print(f"\n{len(saved)} images saved to references/media/")
命名規則:fig-p{page:02d}-{idx:02d}.{ext} — 対応箇所を簡単に見つけられるよう、名前にページ番号を含めます。
サイズフィルター:< 2 KB はスキップします(アイコン、透かし、水平線を除外します)。2 KB 以上はすべて確認します。装飾用の画像もありますが、大半は図です。
Markdown への挿入:

最も近いセクション見出し、または図に言及している段落の直後に配置します。
GitHub GFM の数式レンダリング規則
$$ と ```math ``` の使い分け — 根本原因
GitHub の Markdown プリプロセッサは数式レンダラーより先に実行されます。 \\ をエスケープされたバックスラッシュとして扱い、\ に縮めます。これにより、ディスプレイ数式内の LaTeX の改行が壊れます。
規則は単純です:
| 数式の種類 | 使用する形式 | 理由 |
|---|---|---|
| 1 行のディスプレイ数式 | $$...$$ | \\ がないため、プリプロセッサの影響を受けません |
複数行(\\、\begin{aligned}、行列を含む) | ```math ``` | プリプロセッサはコードフェンスを処理しません |
| インライン | $...$ | 標準形式 |
# BROKEN on GitHub — \\ stripped by pre-processor:
$$
\begin{aligned}
a &= b + c \\
d &= e + f
\end{aligned}
$$
# CORRECT on GitHub:
```math
\begin{aligned}
a &= b + c \\
d &= e + f
\end{aligned}
```
### Display Block Formatting Rules
- `$$` must be on its **own line** — not `$$formula$$` on one line
- **Blank line required** before AND after every `$$` block
- **Blank line required between consecutive** `$$` blocks
- These rules do NOT apply to `` ```math ``` `` blocks
### Supported/Unsupported LaTeX
See [references/github-math-support-table.md](./references/github-math-support-table.md) for the full table.
**Key things to avoid**:
| Command | Problem | Fix |
|---------|---------|-----|
| `\begin{align}` | ❌ Not supported by GitHub | Use `\begin{aligned}` |
| `\boxed{}` | ⚠️ Can cause raw LaTeX passthrough | Remove or use bold text |
| `\operatorname{}` | ⚠️ Active GitHub bug, inconsistent | Use `\text{}` or `\mathrm{}` |
| `\newcommand` | ❌ Was briefly available, then pulled | Expand all macros inline |
| `x^_y` | Superscript immediately before subscript | Write `x^{*}_{i}` with braces |
### Common Gotchas
- `\\[8pt]` vertical spacing inside `$$` → eaten by pre-processor → move to `` ```math ``` ``
- `\frac{1}{T}:\left(` → spurious colon after fraction → remove colon
- Pearson vs excess kurtosis: most finance formulas need Pearson (γ₄ = 3 for Gaussian), not excess. **Always document the kurtosis convention in the formula comment.**
- `\begin{pmatrix}` with `\\` → must use `` ```math ``` ``
- `\begin{cases}` with multiple rows → must use `` ```math ``` ``
---
## GitLab: No Workarounds Needed
**Empirically verified 2026-03-15** on GitLab CE 18.9.2. Confirmed by Comrak source code analysis.
GitLab uses the **Comrak** Rust parser with `math_dollars: true`. When Comrak encounters `$$`, it calls `handle_dollars` which slices the raw input buffer directly and stores it as a `NodeMath` AST node — CommonMark's backslash handler is never invoked on math content. The raw LaTeX is passed to KaTeX via `<span data-math-style="display/inline">` unchanged.
**Every GitHub workaround is unnecessary on GitLab:**
| GitHub problem | GitHub fix required | GitLab |
|----------------|---------------------|--------|
| `\\` in `$$` stripped → broken multiline | Use ` ```math ``` ` | `$$` works with `\\` |
| `\left\{` → `\left{` (delimiter error) | Use `\left\lbrace` | `\left\{` works |
| `\{...\}` set notation → invisible braces | Use `\lbrace...\rbrace` | `\{...\}` works |
| `\,` in `$$` → literal comma | Remove `\,` | `\,` works |
| `\,` in inline `$` → literal comma | Remove `\,` | `\,` works |
On GitLab you can write standard LaTeX without any platform-specific workarounds. If you're targeting GitLab (or hosting your own GitLab CE), skip all the `\lbrace`/`\rbrace` substitutions and ` ```math ``` ` conversions — plain `$$` with standard LaTeX is correct.
### GitLab.com Has a Hard 50-Span Per-Page Limit
**GitLab.com (SaaS) enforces a limit of 50 total math spans per page** (display + inline combined). After the 50th span, all subsequent equations silently fall back to raw LaTeX text. This limit exists to prevent DoS attacks and cannot be overridden on GitLab.com.
| Document math density | gitlab.com | Self-hosted CE |
|---|---|---|
| ≤ 50 total spans | ✅ Renders fully | ✅ |
| 51–100 spans | ⚠️ Partial render | ✅ |
| 100+ spans (academic papers) | ❌ Most equations raw text | ✅ Disable with `math_rendering_limits_enabled: false` |
**Validated on**: Sharpe ratio paper (341 spans) — breaks at span 51 on gitlab.com, renders fully on local CE.
**The W6 check in `validate-math.mjs`** warns when a file exceeds the limit.
**Summary: which platform to use**:
- **GitHub.com**: No math span limit. Use `\lbrace`/`\rbrace` workarounds (handled by `--fix`).
- **Self-hosted GitLab CE**: No limit (disable math_rendering_limits_enabled). No workarounds needed.
- **GitLab.com**: Only suitable for documents with ≤ 50 math spans.
### Self-hosting GitLab CE for Math-Heavy Documents
GitLab CE is free and runs on a single machine. On a 61 GB workstation with slim config:
- Memory footprint: ~3 GB (`puma['worker_processes'] = 2`, `sidekiq['concurrency'] = 5`, monitoring disabled)
- Push mirroring to GitHub: free on CE (syncs within 5 min)
- `glab` CLI: first-party, comparable to `gh`
```yaml
# docker-compose.yml — slim GitLab CE
services:
gitlab:
image: gitlab/gitlab-ce:latest
restart: unless-stopped
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://YOUR_IP:8929'
puma['worker_processes'] = 2
sidekiq['concurrency'] = 5
prometheus_monitoring['enable'] = false
alertmanager['enable'] = false
node_exporter['enable'] = false
redis_exporter['enable'] = false
postgres_exporter['enable'] = false
gitlab_exporter['enable'] = false
ports: ["8929:8929", "8922:22"]
volumes:
- /srv/gitlab/config:/etc/gitlab
- /srv/gitlab/logs:/var/log/gitlab
- /srv/gitlab/data:/var/opt/gitlab
```
---
## Validation Pipeline
### Step 1: Install KaTeX Validator
```bash
bun add -g katex # Bun-first per project policy
# or: npm install -g katex
ステップ 2:プッシュする前に毎回実行
# Validate only (exit 1 on errors)
node references/validate-math.mjs your-file.md
# Validate + auto-fix correctable issues
node references/validate-math.mjs your-file.md --fix
スクリプトはreferences/validate-math.mjsにあります。2 つのレイヤーで実行されます。
レイヤー 1 — KaTeX 構文:$、$$、```math ``` ブロック内の解析エラー レイヤー 2 — GFM 構造(KaTeX では問題ないものの、GitHub では崩れる問題):
| コード | 重大度 | 問題 | 自動修正 |
|---|---|---|---|
| E0 | エラー | $$ ブロック内の \! \, \; \{ \} — 前処理でバックスラッシュが削除され、解析エラーが連鎖します | ✅ 空白を削除;\{→\lbrace |
| E0b | 警告 | インライン $...$ 内の \{ \} \, — 目に見えない波括弧や、文章内にそのまま表示されるカンマ | ✅ → \lbrace/\rbrace; \, を削除 |
| E1 | エラー | \\ を含む $$ ブロック — GitHub の前処理でバックスラッシュが削除されます | ✅ → ```math ``` |
| E2 | エラー | 空行を挟まずに連続する $$ ブロック — 対応する区切り記号がない状態が連鎖します | ✅ 空行を追加 |
| W1 | 警告 | $$ または $ ブロック内の裸の ^* — Markdown の斜体の組み合わせ処理で * が消えます | ✅ → ^{\ast} |
| W2 | 警告 | \begin{align} — GitHub ではサポートされていません | ✗ 手動 |
| W3 | 警告 | \boxed{} — LaTeX がそのまま通過する原因になる可能性があります | ✗ 手動 |
| W4 | 警告 | \operatorname{} — GitHub でのサポートに一貫性がありません | ✗ 手動 |
E0 が最も危険です。$$ ブロックが 1 つでも失敗すると、$$ 区切り記号がそのままテキストとして表示され、対応しない $ が残って、その後のインライン $...$ の対応付けがすべてずれてしまいます。数式 1 つが壊れると、文書全体に影響します。
\{/\} の落とし穴:$$ ブロックでは、\left\{ は \left{ になり(無効な KaTeX 区切り記号 → 「Missing or unrecognized delimiter」)、\{...\} による集合の記法は見えないグルーピングになります。対処法:文字ベースで CommonMark の影響を受けない \lbrace/\rbrace を使用してください。これは、\{\hat{SR}_k\} や \min_T\left\{...\right\} のような集合の記法を使うすべての数式に影響します。
エラーがある場合はコード 1 で終了します(CI に適しています)。警告は CI をブロックしませんが、確認する必要があります。
ローカルプレビュー用ツール
# GitHub-accurate hot-reload preview
bun add -g @hyrious/gfm
gfm your-file.md --serve
# Offline binary (gh extension)
gh extension install thiagokokada/gh-gfm-preview
gh gfm-preview your-file.md
VS Code 拡張機能:
shd101wyy.markdown-preview-enhanced— GitHub のレンダリングに最も近いbierner.markdown-preview-github-styles— GitHub の CSS スタイル
複数エージェントによる敵対的な数式検証
数式が 10 個以上ある論文では、次の複数エージェントのパターンを使用してください。
フェーズ 1 — 並列抽出
- エージェント A:pymupdf4llm で文章を抽出し、PDF のスクリーンショットから数式を書き起こします
- エージェント B:すべての画像を抽出して分類します
フェーズ 2 — 並列検証
- エージェント C:参照実装(コード/リポジトリが存在する場合)と照合して数式を検証します
- エージェント D:数値の抜き取り確認 — 論文に掲載された値を計算して比較します
フェーズ 3 — 不一致への対応
- 不一致ごとに
/tmp/paper-discrepancy/eq-{N}.mdを作成します - 解決担当エージェントを起動し、信頼できる第三者の情報源をオンラインで検索させます
- 権威性に関するルール:暫定的に、論文はコードの実装よりも信頼性が高いものとします。独立した第三の情報源で判断が分かれた場合に決着をつけます
フェーズ 4 — 慎重な適用
- 信頼度の高い修正のみを Markdown に適用します
- 信頼度が中程度の場合は、ファイルに手を加える前に独立した監査エージェントを起動します
- 修正しない場合も含め、すべての不一致を記録します — 将来の読者が把握できるようにする必要があります
アンチパターン
| アンチパターン | 失敗する理由 | 修正方法 |
|---|---|---|
$$ ブロック内の \!\left( または \, | GH プリプロセッサーが KaTeX の前に \!→! と削除します。!\left( は KaTeX でエラーになり、以降もすべて失敗します。 | \! \, \;(スペース調整のみ)を削除するか、```math ``` を使います |
$$/$ ブロック内の \left\{ または \{...\} | \{→{(CommonMark のエスケープ)となるため、\left\{→\left{ は「Missing delimiter」エラーになり、\{x\} は波括弧が表示されずにレンダリングされます | \left\lbrace、\right\rbrace、\lbrace、\rbrace に置き換えます |
$$\begin{aligned}...\\...\end{aligned}$$ | GH プリプロセッサーが \\ を削除します | ```math ``` を使います |
Word の PDF で marker-pdf を信頼する | 出力がないか、数式がすべてゼロになります(Unicode のバグ) | スクリーンショットとして読み取り、手作業で書き起こします |
ディスプレイ数式で \begin{align} | GitHub ではサポートされていません | \begin{aligned} に置き換えます |
\operatorname{Cov} | GH の既知のバグにより、そのまま表示されることがあります | \text{Cov} または \mathrm{Cov} を使います |
KaTeX の検証のみを行い、```math ``` への変換をしない | KaTeX の検証は通っても、GH プリプロセッサーが \\ を壊します | 複数行のブロックもすべて変換します |
強調表示に \boxed{} を使う | GitHub で生の LaTeX がそのまま通過することがあります | 太字のテキストまたは引用ブロックのコールアウトを使います |
| ピアソンの定義を想定した数式で過剰尖度を使う | 分散の数式で、気づかないまま約 50% 過小評価されます | 常に定義を明記し、scipy.stats.kurtosis(fisher=False) を使います |
空行を挟まずに $$ ブロックを連続させる | GitHub がそれらを 1 つの壊れたブロックにまとめます | 各ブロックの間に空行を追加します |
| プッシュ後に検証を実行する | バグが公開リポジトリで見える状態になります | プッシュの前に毎回ローカルで検証します(--fix が E0/E1/E2 を自動修正します) |
参考資料
| ファイル | 目的 |
|---|---|
| validate-math.mjs | GFM ファイル用の KaTeX 一括検証ツール |
| pdf-type-detection.md | PDF の種類を検出する詳細ガイド |
| github-math-support-table.md | LaTeX の完全な対応/非対応一覧 |
関連スキル
| スキル | 関連性 |
|---|---|
| unlimited-ocr-parse-document | PDF からテキストや数式をローカルで抽出します(Type A/C の PDF、約 2.4 秒/ページ) |
| unlimited-ocr-segment-figure | 後続モデル向けに複数パネルの図(グラフ、図表)を切り抜きます |
| pandoc-pdf-generation | 逆方向:Markdown → PDF |
| documentation-standards | GFM の書式規約 |
| quant-research:opendeviation-eval-metrics | 実例:references/how-to-use-the-sharpe-ratio-2026.md |
実行後の振り返り
このスキルの完了後、タスクを終了する前に振り返ってください。
- 現在地を確認します。 — 編集する前に、この SKILL.md の正規パスを確認します。
- 何が失敗しましたか? — 原因となった指示を修正します。
- 予想以上にうまくいったことは何ですか? — 推奨プラクティスとして取り入れます。
- 何が現状とずれていましたか? — 現実に合わなくなったスクリプト、参照、依存関係を修正します。
- 記録します。 — きっかけ、修正内容、根拠を含む進化ログのエントリを追加します。
先送りしないでください。次回の実行では、あなたが残した状態を引き継ぎます。