Skip to main content

fandhe_ai/
lib.rs

1//! composition root(TASK-9.3・イシュー #410・spec 確定は
2//! fandhe-ai-spec#52/spec PR #53。`docs/spec/05-tasks.md:315`)。
3//!
4//! `facade` は 2 つの責務を担う(spec 確定内容)。
5//!
6//! 1. **composition root(本クレート・本イシューで実装)**: [`Device`]
7//!    識別子を受け取り、対応する具体 `BackendOps` 実装
8//!    (`fandhe_ai_backend_cpu::CpuBackendOps`/`fandhe_ai_backend_cuda::CudaBackendOps`/
9//!    `fandhe_ai_backend_metal::MetalBackendOps`)を構築して `fandhe_ai_autodiff::Tape` へ
10//!    結線する。この結線ロジックを持つのは本クレートのみであり、
11//!    `tensor-core`/`autodiff`/`backend-*` は互いに他バックエンドを
12//!    直接参照しない構造的境界(REQ-9・`docs/fusion-graph-design.md`
13//!    §3.4「`autodiff` は具体クレートへの依存を一切持たない」)を、
14//!    上位でここに一本化する。
15//! 2. **compat 公開面**([`compat::array`]/[`compat::Sequential`]):
16//!    TASK-9.4(イシュー #411)で `fandhe_ai_autodiff::compat` から本クレートへ
17//!    移設し実装済み。サポート境界の明文化(`facade` が唯一のサポート
18//!    対象公開 API 面であり `tensor-core`/`autodiff`/`backend-*` は
19//!    内部クレート)は `docs/compat-api-scope.md` を参照。
20//!
21//! 3. **optim 公開面**([`optim`]。イシュー #961・親 #960。Adam〈coupled
22//!    L2 weight decay〉は #1742・RMSprop/Adagrad は #1743・親 #1610・
23//!    LAMB は #1744): SGD・AdamW・Adam・RMSprop・Adagrad・LAMB・
24//!    gradient clipping・LR スケジューラを `fandhe_ai::optim` の単一入口へ再エクスポートする。
25//!    値型・純関数のみのため REQ-12 と矛盾しない(詳細は [`optim`]
26//!    モジュール doc)。
27//!
28//! 4. **data 公開面**([`data`]。イシュー #1615・親 #1602): map-style
29//!    データセット(`Dataset`/`TensorDataset`)とミニバッチ供給
30//!    (`DataLoader`/`DataLoaderConfig`)を `fandhe_ai::data` の単一
31//!    入口へ再エクスポートする。ホスト側だけで完結し `Op`/
32//!    `BackendOps`/VJP を経由しないため REQ-12 と矛盾しない(詳細は
33//!    [`data`] モジュール doc)。
34//!
35//! 5. **nn 公開面**([`nn::rnn`]。イシュー #1955): RNN/LSTM/GRU の
36//!    Sequence レベル API(`Rnn`/`Lstm`/`Gru`。実体は
37//!    `fandhe_ai_autodiff::nn`。#1647)を `fandhe_ai::nn::rnn` の単一
38//!    入口へ純再エクスポートする。`forward_seq` が生 `Tape` を引数に
39//!    取るため facade 利用者からは直接呼べず、`impl Tape` に追加した
40//!    `rnn_forward_seq`/`lstm_forward_seq`/`gru_forward_seq`(`&self.0`
41//!    を渡すだけの薄い委譲。`step_device_param_store` 等と同型)が
42//!    入口となる。イシュー #2535 で多層・双方向・層間 dropout 版
43//!    (`RnnConfig`・`StackedRnn`/`StackedLstm`/`StackedGru`・戻り値型 2 型)
44//!    も同モジュールへ再エクスポートし、`stacked_rnn_forward_seq`/
45//!    `stacked_lstm_forward_seq`/`stacked_gru_forward_seq` を追加した。
46//!    値型の再エクスポート+薄い委譲のみで任意
47//!    `BackendOps` 注入経路を新設しないため REQ-12 と矛盾しない
48//!    (詳細は [`nn::rnn`] モジュール doc)。同じく `nn` 配下に、PyTorch
49//!    `torch.nn.init.*` 相当の初期化関数 9 個と補助 4 名を [`nn::init`] へ
50//!    純再エクスポートする(イシュー #2504。グローバル RNG に従う)。
51//!    さらに KV キャッシュ付き attention(`KvCache`・`StatefulAttention`・
52//!    `MultiheadAttentionConfig`)を [`nn::kv_cache`] へ純再エクスポートし、
53//!    入口として `Tape::stateful_attention_forward`(薄い委譲)を追加した
54//!    (イシュー #2579。`docs/kv-cache-design.md` §11.4)。#3096 で外部キャッシュ版
55//!    `Tape::stateful_attention_forward_with_cache` も追加した
56//!    (`docs/facade-speculative-decoding-batching-design.md` §19)。
57//!    #3112 でデバイス常駐ページ化キャッシュ(K-3。`PagedKvCache`・`PagedKvCacheConfig`)と
58//!    入口 `Tape::new_paged_kv_cache`/`Tape::paged_attention_forward` も追加した
59//!    (`docs/device-resident-kv-paged-attention-design.md` §6・§13)。
60//!    損失構造体 14 種と引数型 10 種(`Reduction`・各オプション型 9 種。うち 5 種は #2854)は
61//!    [`nn::loss`] へ純再エクスポートする(イシュー #2602・#2854。`docs/facade-nn-loss-structs-exposure-decision.md`)。
62//!
63//! 6. **model 公開面**([`model`]。イシュー #2087・親 #2082):
64//!    ホームディレクトリ配下のキャッシュディレクトリを基盤とする
65//!    ローカル限定モデルレジストリ [`model::ModelRegistry`] を提供
66//!    する。ホスト側のパス管理と [`interop::safetensors`] への委譲
67//!    のみで完結し `BackendOps` 注入経路を新設しないため REQ-12 と
68//!    矛盾しない(詳細は [`model`] モジュール doc・`docs/facade-
69//!    model-registry-decision.md` 参照)。
70//!
71//! 7. **text 公開面**([`text`]。イシュー #2937・親 #2935):
72//!    語彙 lookup 型のテキスト変換 [`text::TextVectorization`]
73//!    (Keras `TextVectorization` 相当。文字列バッチを `[B, L]` の
74//!    `Tensor<i32>` へ変換する)。ホスト側の処理のみで完結し
75//!    `BackendOps` 注入経路を新設しないため REQ-12 と矛盾しない
76//!    (標準化・分割は ASCII 限定。詳細は [`text`] モジュール doc・
77//!    `docs/facade-text-vectorization-design.md` §16 参照)。
78//!
79//! 8. **distributed 公開面**([`distributed`]。イシュー #3147・親 #3143):
80//!    DDP 初期形(std のみの TCP によるホスト側 ring all-reduce)の設定
81//!    [`distributed::DistributedConfig`]・集合の確立・分散ステップ
82//!    (`step_sgd`/`step_adam`/`step_adamw`)。内部型は公開せず、認証・暗号化は無い
83//!    (詳細は [`distributed`] モジュール doc・
84//!    `docs/facade-distributed-host-collective-decision.md` §16 参照)。
85//!
86//! # 公開面の設計(REQ-12: 任意 `BackendOps` 注入の公開 API を設けない)
87//!
88//! 利用者向けに公開するのは [`Device`] 識別子を受け取る 2 関数
89//! ([`tape`]・[`tape_for`])と、それに必要な最小限の型再エクスポート
90//! ([`Device`]・[`BackendError`])のみである。`fandhe_ai_autodiff::Tape`・
91//! `fandhe_ai_tensor_core::BackendOps` は本クレートから再エクスポートしない
92//! (`fandhe_ai::Tape::new_with_ops(ops)` という経路がサポート面に露出すると
93//! 「任意 `BackendOps` 実装を注入できる公開 API を設けない」(REQ-12)と
94//! 矛盾するため)。この制約は `tests/api_surface.rs` がソース走査で
95//! 機械的に固定する。
96//!
97//! **`Tape`(composition root が構築する値)の扱い(codex-review PR #424
98//! P1 是正)**: [`tape`]・[`tape_for`] の戻り値は `fandhe_ai_autodiff::Tape` を
99//! そのまま返すのではなく、本クレート所有の newtype [`Tape`] でラップする。
100//! `fandhe_ai_autodiff::Tape` を素通しすると `Tape::new_with_ops` という
101//! `BackendOps` 注入経路が facade 型として到達可能になり REQ-12 と矛盾する
102//! ため、[`Tape`] は [`Tape::var`]/[`Tape::backward`] の 2 メソッドのみを
103//! 再委譲する(構築は [`tape`]/[`tape_for`] 経由のみで、`fandhe_ai_autodiff::Tape`
104//! の任意構築経路は到達不能なまま)。[`compat::Sequential::forward`]/
105//! [`compat::Sequential::bind`] もこの [`Tape`] 型を引数に取る(旧実装は
106//! `fandhe_ai_autodiff::Tape` を直に引数へ取っており、内部クレートの型が facade の
107//! 公開シグネチャへ直接露出していた。codex-review 指摘)。
108//!
109//! [`TapeRef`](#2394。[`nn::Module::forward`] の第 1 引数)は `var`/`var_from`/`var_no_grad` のみを持つ借用ハンドルで、
110//! [`Tape`] の公開メソッドは変えない。crate 外の入口は `From<&Tape>` のみ。
111//!
112//! [`TapeF64`]/[`VarF64`]/[`GradientsF64`](#2599)は f64 専用の独立自動微分グラフで、
113//! 3 型とも本クレート所有の newtype(`docs/autodiff-var-dtype-multiplexing-design.md`
114//! §4.1・§10.1 の推奨案 D-2)。構築は [`TapeF64::new`](facade [`Tape`] の借用)のみ。
115//!
116//! **`Var`/`Gradients`/`AutodiffError`/`LinearVars`(`autodiff` 由来)・
117//! `Tensor`(`tensor_core` 由来)の扱い**: これらは `BackendOps` 注入の
118//! 迂回経路を持たない値型・エラー型であるため、`facade` の正式な公開契約
119//! として本クレートから再エクスポートする(下記 `pub use`)。
120//! `compat::{array, Sequential}` の公開シグネチャはこの再エクスポート
121//! パス(`crate::{AutodiffError, Tensor}` 等)を使う。
122//!
123//! # `Device::Cuda(_)`/`Device::Metal` の構築規則
124//!
125//! spec は本規則を「TASK-9.3 実装時にユーザー承認を得て確定」とする
126//! 未決事項として残しているため、以下の最小・自明な規則を採用した
127//! (イシュー #410 実装計画 §2-2。PR 本文でユーザー確認を仰ぐ)。
128//!
129//! - `Device::Cpu` → `CpuBackendOps::new()`(常に利用可能なため検証不要)。
130//! - `Device::Cuda(ordinal)` → `CudaDeviceProvider::select` で存在検証
131//!   (driver 不在・範囲外 ordinal は [`BackendError`] を返す fail-fast)
132//!   したうえで `CudaBackendOps::new(ordinal)` を構築する。イシュー #929:
133//!   `CudaBackendOps` の各演算メソッドは `backend-cuda` 側のプロセス内
134//!   キャッシュ(`crate::context_cache`。`ordinal` キー)を経由するため、
135//!   同一プロセス内で 2 回目以降に `tape_for(Device::Cuda(_))` を呼んでも
136//!   `CudaContext` 生成・NVRTC コンパイルは再実行されない。`resolve_ops`
137//!   自体(この関数)は毎回新しい `CudaBackendOps`/`Tape` を構築する
138//!   軽量な値であり、重い初期化コストはバックエンド側キャッシュが吸収する。
139//! - `Device::Metal`(`cfg(target_os = "macos")`)→ `MetalDeviceProvider::select`
140//!   で検証したうえで `MetalBackendOps::new()` を構築する。
141//!
142//! 既定デバイスの自動選択(GPU フォールバック等)・デバイス列挙の集約入口
143//! (`Device::available()` 相当の facade 結線)は本イシューのスコープ外
144//! (`docs/public-api-design.md` §4.1 の未決事項を尊重。
145//! out-of-scope-tracking.md 対象)。
146
147use fandhe_ai_tensor_core::device::select_from;
148use fandhe_ai_tensor_core::{BackendOps, DeviceProvider};
149
150/// numpy/Keras 慣習の互換 API 層(compat 公開面。TASK-9.4・#411)。
151/// [`compat::array`]・[`compat::Sequential`] を提供する(詳細はモジュール
152/// doc・`docs/compat-api-scope.md` 参照)。
153pub mod compat;
154
155/// optimizer 公開面(イシュー #961・親 #960。Adam は #1742・RMSprop/
156/// Adagrad は #1743・親 #1610・LAMB は #1744)。SGD・AdamW・Adam・RMSprop・
157/// Adagrad・LAMB・gradient clipping・LR スケジューラを再エクスポートする(詳細・
158/// 適用順序契約はモジュール doc 参照)。
159pub mod optim;
160
161/// Dataset/DataLoader 公開面(イシュー #1615・親 #1602)。map-style
162/// データセット([`data::Dataset`]・[`data::TensorDataset`])とミニ
163/// バッチ供給([`data::DataLoader`]・[`data::DataLoaderConfig`])を
164/// 再エクスポートする(詳細はモジュール doc・`docs/dataset-dataloader-
165/// design.md` 参照)。
166pub mod data;
167
168/// `nn` 公開面(イシュー #1955)。[`nn::rnn`]
169/// (`Rnn`/`Lstm`/`Gru` と多層版 `Stacked*`・`RnnConfig` の Sequence レベル
170/// API の純再エクスポート)と、
171/// facade 独自の [`nn::Module`](#2395)を提供する。`forward_seq` の呼び出しには [`Tape::rnn_forward_seq`]
172/// 等(本モジュール自体ではなく `impl Tape` の薄い委譲メソッド)を
173/// 使う(詳細は [`nn::rnn`] モジュール doc 参照)。
174pub mod nn;
175
176/// 相互運用(interop)公開面の入口(イシュー #2017・#2018・#2019)。
177/// [`interop::onnx`](ONNX import/export。`OnnxModel`/`OnnxValue`/
178/// `OnnxError`・`OnnxModel::{from_bytes, from_path, from_path_with_limits, run,
179/// to_bytes, to_path}`・`OnnxExportOptions`・`OnnxExternalDataLimits`
180/// 〈external data 読み込み予算。#2360〉。export は 2 経路で、`to_bytes`/`to_path`
181/// は import 済みモデルの roundtrip export〈#2018〉、`OnnxModel::from_sequential`
182/// は `compat::Sequential` の対応 6 層〈`Linear`/`ReLU`/`Softmax`/`LayerNorm`/
183/// `GELU`〈erf 版〉/`Conv2d`。#2037・#2076〉から ONNX グラフを組み立てる。対応外の層は
184/// `UnsupportedLayer` で拒否する。`docs/facade-onnx-export-exposure-decision.md` §17)
185/// に加え、[`interop::safetensors`](safetensors
186/// save/load 純再エクスポート。イシュー #2019)と [`interop::npy`](npy/npz
187/// 読み書き純再エクスポート。イシュー #2590)を提供する
188/// (`docs/facade-onnx-export-exposure-decision.md`・`docs/facade-
189/// safetensors-exposure-decision.md`)。
190pub mod interop;
191
192/// 6. **model 公開面**([`model`]。イシュー #2087・親 #2082): ホーム
193///    ディレクトリ配下のキャッシュディレクトリを基盤とするローカル
194///    限定モデルレジストリ [`model::ModelRegistry`] を提供する。
195///    ホスト側のパス管理と [`interop::safetensors`] への委譲のみで
196///    完結し `BackendOps` 注入経路を新設しないため REQ-12 と矛盾しない
197///    (詳細は [`model`] モジュール doc・
198///    `docs/facade-model-registry-decision.md` 参照)。
199pub mod model;
200
201// バッチ推論(`compat::Sequential::predict_batches`)の推論フェーズ計測公開面
202// (イシュー #2582・親 #2581。公開形は
203// `docs/facade-predict-batches-phase-metrics-decision.md` §8.4 の確定形)。
204// モジュール doc は `inference/mod.rs` の `//!` に置く(外側 `///` と併記すると
205// intra-doc link が親スコープで解決され壊れるため)。
206// 同モジュールは自己回帰生成 `generate`(`AutoregressiveModel`/`GenerateConfig`/
207// `SamplingStrategy`/`generate`。イシュー #2575)も純再エクスポートで公開する。
208pub mod inference;
209
210/// 非公開。`model` と `compat::model_io`(#2369)が共有する no-follow 葉オープンと
211/// サイズ上限(`fs_guard` モジュール doc 参照)。
212mod fs_guard;
213
214/// 非公開。`model`(`ModelRegistry::save`)と `compat::model_io` が共有する書き込み側
215/// ヘルパー(一時ファイル確保・自己所有一時ファイルの後始末。unix 限定。`fs_write` モジュール doc 参照)。
216mod fs_write;
217
218/// 非公開。`optim::ExponentialMovingAverage`(イシュー #2560)の実体。公開パスは
219/// `optim.rs` の `pub use` のみ(`optim_ema` モジュール自体は公開しない)。
220mod optim_ema;
221
222/// 非公開。`optim::AveragedModel`(SWA。イシュー #2679)の実体。公開パスは
223/// `optim.rs` の `pub use` のみ(`optim_swa` モジュール自体は公開しない)。
224mod optim_swa;
225
226// 語彙 lookup 型のテキスト変換(Keras `TextVectorization` 相当。イシュー #2937・親 #2935)。
227// 公開形は `docs/facade-text-vectorization-design.md` §16 の確定形(承認:
228// イシュー #2499 コメント 6067263650 の項 1)。公開パスは `text` の 6 名のみで、
229// サブモジュールは非公開・クレートルートへの再エクスポートはしない。
230// モジュール doc は `text/mod.rs` の `//!` に置く(外側 `///` と併記すると
231// intra-doc link が親スコープで解決され壊れるため)。
232pub mod text;
233
234// 参照モデル `Mlp`/`LeNet`/`ResNet`/`ResNetBlock`/`TransformerClassifier`/
235// `TransformerClassifierConfig`(PyTorch の定番モデル。イシュー #2974・親 #2541 の Phase 11-1 と
236// #2975 の Phase 11-2)。
237// 承認: イシュー #2499 コメント 6097478475(`docs/reference-models-decision.md` §11)。
238// 公開パスは `models` の 6 名のみで、サブモジュールは非公開・クレートルートへの
239// 再エクスポートはしない。モジュール doc は `models/mod.rs` の `//!` に置く(外側 `///` と
240// 併記すると intra-doc link が親スコープで解決され壊れるため)。
241pub mod models;
242
243// 分散学習(DDP 初期形。std のみの TCP によるホスト側 ring all-reduce。イシュー #3147・親 #3143)。
244// 承認: `docs/facade-distributed-host-collective-decision.md` §11 の D-A・D-B のみ。
245// 公開パスは `distributed` の 5 型 + 3 関数で、サブモジュールは非公開・クレートルートへの
246// 再エクスポートはしない。モジュール doc は `distributed/mod.rs` の `//!` に置く
247// (外側 `///` と併記すると intra-doc link が親スコープで解決され壊れるため)。
248pub mod distributed;
249
250// 公開面として再エクスポートする型(モジュール冒頭「公開面の設計」参照)。
251// `fandhe_ai_autodiff::Tape`(生の型)・`fandhe_ai_tensor_core::BackendOps` は意図的に含めない
252// (`Tape::new_with_ops` という BackendOps 注入経路が到達可能になるため。
253// REQ-12)。`Var`/`Gradients`/`AutodiffError`/`LinearVars`・`Tensor` は
254// 迂回経路を持たない値型・エラー型のため facade の正式な公開契約として
255// 再エクスポートする(codex-review PR #424 P1 是正)。
256// `tests/api_surface.rs::facade_does_not_reexport_tape_or_backend_ops` は
257// `pub use` を行単位(`trimmed.starts_with("pub use")`)で走査するため、
258// 複数行に折り返す `pub use fandhe_ai_autodiff::{ ... };` ブロックは
259// 開き括弧の行しか検査対象に入らず、ブロック内部に `Tape` が紛れ込んでも
260// 検出できない(レビュー指摘対応)。1 文 1 行を維持する。
261//
262// `SgdConfig` はここ(クレート root)と `crate::optim::SgdConfig`
263// (イシュー #961)の 2 経路から再エクスポートされるが、いずれも
264// `fandhe_ai_autodiff::optim::SgdConfig` を指す同一型である(再エクスポート
265// 経路が 2 つあるだけで型は 1 つ。`Tape::step_device_param_store` の
266// 引数型として本経路が既に使われているため、`optim` モジュール新設に
267// 伴いこちら側を除去・付け替えることはしない)。
268//
269// `DeviceParamStore`/`Tape::step_device_param_store`(デバイス常駐更新
270// 経路)は REQ-9 の 2026-08-29 追記(正本 spec
271// `docs/spec/04-requirements.md:213`。実装リポ #984/#986)で `tape()`系・
272// `compat`/`optim` と並ぶ確定入口となった(`docs/compat-api-scope.md` §0)。
273pub use fandhe_ai_autodiff::optim::{DeviceParamStore, ResidentLeaf, SgdConfig};
274// `Tape::step_device_param_store_adam`/`_adamw`(イシュー #1959)の
275// 引数型として使う。`AdamConfig`/`AdamWConfig` 自体は `crate::optim`
276// (`optim.rs`)から利用者向けにも再エクスポート済みのため、ここでは
277// 型を参照するためだけの `use`(`pub use` ではない)とする。
278use fandhe_ai_autodiff::nn::optim::{
279    AdagradConfig, AdamConfig, AdamWConfig, GradScaler, LambConfig, RmsPropConfig,
280};
281pub use fandhe_ai_autodiff::{AutodiffError, Gradients, Var, nn::LinearVars};
282// ユーザー定義 forward/backward(カスタム VJP)の trait を facade の
283// crate ルートへ再エクスポートする(イシュー #2549。ルート #2499 の一括
284// 承認・`docs/autodiff-custom-function-decision.md` §16.1 (a)・
285// `docs/compat-api-scope.md` §5 経路 2)。利用者は `Tape::custom` へ
286// `Arc<dyn fandhe_ai::CustomFunction>` を渡す。1 文 1 行・別名なし・
287// グループ形なしを維持する(`tests/api_surface.rs` が行単位で固定する)。
288pub use fandhe_ai_autodiff::CustomFunction;
289// `VarHostView`(借用ビュー読み出し API。イシュー #1335)は 1 文 1 行を
290// 維持する(`tests/api_surface.rs` が `pub use` を行単位で走査するため。
291// 上記コメント「1 文 1 行を維持する」参照)。
292pub use fandhe_ai_autodiff::VarHostView;
293// 線形代数(イシュー #1621・`docs/autodiff-linalg-design.md`)の多出力
294// 戻り値型(`Var::qr`/`Var::svd`)は 1 文 1 行で再エクスポートする
295// (上記コメント「1 文 1 行を維持する」と同じ理由)。
296pub use fandhe_ai_autodiff::QrVars;
297pub use fandhe_ai_autodiff::SvdVars;
298// `Var::eigh`/`Var::slogdet`(イシュー #2515)の多出力戻り値型。`QrVars`/`SvdVars`
299// と同じ書き方(1 文 1 行)で再エクスポートし、型注釈・型名での分割代入を可能にする。
300pub use fandhe_ai_autodiff::EighVars;
301pub use fandhe_ai_autodiff::SlogdetVars;
302// `topk_unique_ops`(イシュー #2153 実装・#2519 公開)の入出力型。
303// `Var::topk_with_options`/`unique_with_options`/`unique_consecutive` の
304// 引数(`TopkOptions`/`UniqueOptions`)と戻り値(`UniqueOutput`)で、これらが
305// 無いと委譲メソッドを呼べない。モジュール `topk_unique_ops` 自体は
306// 再エクスポートしない(型だけを autodiff ルート経由で 1 文 1 行で公開する。
307// `api_surface.rs::facade_reexports_topk_unique_types_only_in_approved_shape`)。
308pub use fandhe_ai_autodiff::{TopkOptions, UniqueOptions, UniqueOutput};
309// Phase 4 の演算(`Var` の委譲メソッド。イシュー #2678・ルート #2499 の一括承認
310// `issuecomment-6033824965`・`docs/compat-api-scope.md` §5.1)の引数型。モジュール
311// (`fft_ops`・`shape_view_ops`・`pad_ops` 等)自体は再エクスポートせず、型だけを
312// 内部クレートのルート経由で 1 文 1 行・別名なしで公開する
313// (`tests/api_surface.rs::facade_reexports_phase4_ops_types_only_in_approved_shape`)。
314pub use fandhe_ai_autodiff::IstftOptions;
315pub use fandhe_ai_autodiff::MeshgridIndexing;
316pub use fandhe_ai_autodiff::StftOptions;
317pub use fandhe_ai_tensor_core::FftNorm;
318pub use fandhe_ai_tensor_core::PadMode;
319pub use fandhe_ai_tensor_core::QuantileInterpolation;
320pub use fandhe_ai_tensor_core::ScatterReduceMode;
321pub use fandhe_ai_tensor_core::StftPadMode;
322pub use fandhe_ai_tensor_core::{BackendError, Device, PoolStats, Tensor};
323// `RngError`(イシュー #1725): `randint` の戻り値型(`low >= high` の
324// 範囲不正を表す)。`Tape`/`BackendOps` を含まない単純なエラー型のため
325// 1 行の `pub use` で足りる(`api_surface.rs::facade_does_not_reexport_tape_or_backend_ops`
326// は行単位で `Tape`/`BackendOps`/`new_with_ops` を検査するのみで抵触
327// しない)。
328pub use fandhe_ai_tensor_core::RngError;
329// `Generator`(イシュー #2593・2026-10-07 承認): グローバル RNG
330// (`manual_seed`)と独立した乱数源。`bernoulli`/`multinomial`/`normal`
331// と同じ分布サンプラーを持つ(`Generator::new(seed)` から生成し、グローバル
332// RNG の列を変えない)。`RngError` と同じく `fandhe_ai_tensor_core::` 直下
333// 経由の 1 行 `pub use`(`::rng::` 経由にしない)。既知の制限: `randn`/
334// `rand`/`randint` の `Generator` 版は無い(`docs/rng-distributions-generator-decision.md`
335// §5.1)。
336pub use fandhe_ai_tensor_core::Generator;
337// `ShapeError`(イシュー #1725): `randn`/`rand`(本 PR で新設したトップ
338// レベル `pub fn`)の戻り値型(形状不正を表す)。`Tensor::zeros` 等の
339// 既存メソッドも同型を返すが、それらは既存の再エクスポート型
340// (`Tensor`)のメソッドであるのに対し `randn`/`rand` は本 PR 新設の
341// トップレベル関数であり、facade が「唯一のサポートされる公開 API 面」
342// である方針(CLAUDE.md)に照らし `RngError` と同様に 1 行の
343// `pub use` で再エクスポートする(codex-review 指摘対応。上記
344// `RngError` コメントと同じ理由で `api_surface.rs` の走査にも抵触
345// しない)。
346pub use fandhe_ai_tensor_core::ShapeError;
347// `CreationError`(イシュー #1726): `arange`/`linspace`(本ファイルで
348// 新設したトップレベル `pub fn`)の戻り値型(`step` 不正・非有限値を
349// 表す)。`RngError`/`ShapeError` と同じ理由で 1 行の `pub use` で
350// 再エクスポートする(`api_surface.rs` の走査にも抵触しない)。
351pub use fandhe_ai_tensor_core::CreationError;
352// `ChecksumReadout`/`GemmChecksum`(イシュー #1339・`Var::matmul_checksum`
353// の戻り値・引数型)も 1 文 1 行で再エクスポートする(上記コメント
354// 「1 文 1 行を維持する」と同じ理由)。
355pub use fandhe_ai_tensor_core::{ChecksumReadout, GemmChecksum};
356// 線形代数(イシュー #1621)の値型(`BackendOps::linalg_qr`/
357// `linalg_svd`/`linalg_matrix_norm` の入出力)も 1 文 1 行で
358// 再エクスポートする(`QrFactors`/`SvdFactors`/`MatrixNormOrd` は
359// `Var::qr`/`svd`/`matrix_norm` の呼び出し側からは直接見えないが、
360// バックエンド実装を跨いで自作するテスト・診断コードのために公開する。
361// 上記コメント「1 文 1 行を維持する」と同じ理由)。
362pub use fandhe_ai_tensor_core::MatrixNormOrd;
363pub use fandhe_ai_tensor_core::QrFactors;
364pub use fandhe_ai_tensor_core::SvdFactors;
365// `InterpolateMode`(イシュー #1757・`Var::interpolate` の `mode`
366// 引数型)も 1 文 1 行で再エクスポートする(上記コメント「1 文 1 行を
367// 維持する」と同じ理由)。`Bilinear { align_corners }` variant
368// (イシュー #1762)追加時も新規公開アイテムは発生しない
369// (`InterpolateMode` 自体の再エクスポートのみで完結する)。
370pub use fandhe_ai_tensor_core::InterpolateMode;
371// `GlobalPoolMode`(イシュー #2527。`compat::Sequential::add_global_pool`
372// の `mode` 引数型。`#[non_exhaustive]`)も 1 文 1 行で再エクスポートする。
373// `GlobalPool` 層型・`AdaptiveMaxPool2d`/`AdaptiveMaxPool1d` 層型の
374// 再エクスポートは未承認のため行わない(`AdaptiveMaxGlobalPoolHoldDoctestGuard`
375// と `tests/api_surface.rs` の正ガードが固定)。
376pub use fandhe_ai_autodiff::nn::GlobalPoolMode;
377// `EmbeddingBagMode`(イシュー #2528。`compat::Sequential::add_embedding_bag`・
378// `Var::embedding_bag` の `mode` 引数型。`#[non_exhaustive]`)も 1 文 1 行で
379// 再エクスポートする。`Dropout2d`/`AlphaDropout`/`EmbeddingBag`/
380// `EmbeddingBagVars` 層型の再エクスポートは未承認のため行わない
381// (`DropoutEmbeddingBagHoldDoctestGuard` と `tests/api_surface.rs` の正ガードが固定)。
382pub use fandhe_ai_autodiff::nn::EmbeddingBagMode;
383// `CreateGraphResult`(子テープ方式の高階微分結果型。イシュー #2545。
384// `Tape::backward_create_graph` の戻り値型)も 1 文 1 行で再エクスポートする。
385// 承認根拠はルート #2499 の一括承認(2026-10-04)と
386// `docs/autodiff-higher-order-grad-decision.md` §17.2 の確定形。フィールドは
387// 非公開で利用者は構築できない。`TapeRef` 版・子テープ構築ヘルパーは
388// §17.3 により公開しない(`tests/api_surface.rs` の正ガードが固定)。
389pub use fandhe_ai_autodiff::CreateGraphResult;
390// `JvpCreateGraphResult`(微分可能な jvp の結果型。イシュー #3068。`Tape::jvp_create_graph` の
391// 戻り値型)も `CreateGraphResult` と同じ先例で 1 文 1 行で再エクスポートする。承認根拠は
392// 2026-10-11 の所有者判断 D-A(一括承認)と `docs/autodiff-functional-transforms-design.md`
393// §31.1。フィールドは非公開で利用者は構築できない。経路は必ずクレートルート経由とする
394// (`functional_ops::` 経由は `tests/api_surface.rs` の関数型 AD 正ガードが拒否)。
395pub use fandhe_ai_autodiff::JvpCreateGraphResult;
396// `HookHandle`(backward hook の解除用不透明ハンドル。イシュー #2587。
397// `Tape::register_backward_hook` の戻り値・`Tape::remove_hook` の引数型)も 1 文 1 行で
398// 再エクスポートする。承認根拠はルート #2499 のコメントによる #2584 の §14 推奨案の承認と
399// `docs/autodiff-forward-backward-hooks-design.md` §14.4 P3。フィールドは非公開で
400// `Clone`/`Copy` を持たず、利用者は構築できない。
401pub use fandhe_ai_autodiff::HookHandle;
402// `GradcheckOptions`/`GradcheckReport`(`Tape::gradcheck` の閾値引数型・結果型。イシュー
403// #2847)も 1 文 1 行(別名なし)で再エクスポートする。承認根拠はルート #2499 の
404// issuecomment-6052732061 と `docs/autodiff-jacobian-hessian-gradcheck-decision.md` §11.3。
405// `gradcheck` モジュールと裸の自由関数 `gradcheck` は再エクスポートしない
406// (`tests/api_surface.rs` の正ガードが固定)。
407pub use fandhe_ai_autodiff::gradcheck::{GradcheckOptions, GradcheckReport};
408// `SpectralNormState`(`Var::spectral_norm` の状態引数型。イシュー #2851)も 1 文 1 行(別名なし)で
409// 再エクスポートする。承認根拠はルート #2499 の issuecomment-6052732061 と
410// `docs/autodiff-lrn-weight-reparam-decision.md` §12.2。`weight_reparam_ops` モジュール・`norm_except_dim`・
411// `SPECTRAL_NORM_INIT_POWER_ITERATIONS` は再エクスポートしない(`tests/api_surface.rs` の正ガード
412// `facade_reexports_spectral_norm_state_only_in_approved_shape` と否定スキャンが固定)。
413pub use fandhe_ai_autodiff::weight_reparam_ops::SpectralNormState;
414// `CastDType`/`CastElement`(イシュー #1750。`Var::cast`/`Tape::
415// var_from` の型境界・dtype タグ)も 1 文 1 行で再エクスポートする
416// (上記コメント「1 文 1 行を維持する」と同じ理由)。`CastOps`(動的
417// ディスパッチ面)は再エクスポートしない——利用者は `Var::cast`/
418// `Tape::var_from` 経由で到達し、`CastOps` 自体を直接構築・実装する
419// 経路は facade の公開契約に含めない(`docs/tensor-core-cast-design.md`
420// 参照)。
421pub use fandhe_ai_tensor_core::{CastDType, CastElement};
422// `Scalar`/`ScalarDType`/`TypedOps`(イシュー #1939・
423// `docs/compat-api-scope.md` §5 経路 2 承認・`docs/backend-dtype-
424// dispatch-design.md`): `Tensor<T>` を直接対象とする dtype 別演算集合
425// (`gemm`/`add`/`mul`/`relu`/`exp`/`tanh`/`sum`/`max` の 8 演算
426// 限定)への capability accessor 面を facade へ昇格する。到達経路は
427// `Tape::typed_ops_f64`/`_f16`/`_bf16`(本ファイル下部)が返す
428// `Option<&dyn TypedOps<T>>` のみで、`Var`/autograd は経由しない
429// (勾配は付かない)。`half::f16`/`half::bf16` を名指しする利用者は
430// `half`(本 workspace と同一バージョン)へ直接依存する前提とし、
431// facade は `half` 自体を再エクスポートしない(承認事項)。上記コメント
432// 「1 文 1 行を維持する」と同じ理由で 1 行にまとめる。
433pub use fandhe_ai_tensor_core::{Scalar, ScalarDType, TypedOps};
434
435// `TypedOps<T>` の戻り値型シグネチャで `half::f16`/`half::bf16` を
436// 名指しするための非公開 `use`(facade 自体は `half` を再エクスポート
437// しない。上記 `Scalar`/`ScalarDType`/`TypedOps` コメント参照)。
438use fandhe_ai_tensor_core::{bf16, f16};
439
440/// composition root([`tape`]/[`tape_for`])が構築する `Tape` の
441/// newtype ラッパー(codex-review PR #424 P1 是正)。
442///
443/// `fandhe_ai_autodiff::Tape` をそのまま公開すると `Tape::new_with_ops(ops)`
444/// (任意 `BackendOps` 注入経路)が facade の型として到達可能になり
445/// REQ-12「任意 `BackendOps` 実装を注入できる公開 API を設けない」と
446/// 矛盾する。本型は内部の `fandhe_ai_autodiff::Tape`(フィールド `0`。`pub(crate)`
447/// のためクレート外から直接構築・分解できない)が持つメソッドのうち
448/// [`Tape::var`]/[`Tape::backward`] のみを再委譲し、それ以外(特に
449/// `new_with_ops`)を到達不能に保つ。構築できるのは [`tape`]/[`tape_for`]
450/// のみ(`pub(crate)` タプルフィールドのため crate 外からのフィールド
451/// アクセス・構築は不能。`tests/api_surface.rs` が機械的に固定する)。
452pub struct Tape(pub(crate) fandhe_ai_autodiff::Tape);
453
454impl std::fmt::Debug for Tape {
455    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
456        // 内部の `fandhe_ai_autodiff::Tape` も同じ理由(`ops` が `Debug` 非実装)で
457        // `finish_non_exhaustive` を使う(`fandhe_ai_autodiff::tape::Tape` の
458        // `Debug` 実装と同じ方針。`crates/autodiff/src/tape.rs` 参照)。
459        f.debug_struct("Tape").finish_non_exhaustive()
460    }
461}
462
463/// デバイスに常駐する入力テンソルの不透明ハンドル(イシュー #3250 P1。公開形の決定は
464/// `docs/compat-resident-train-step-decision.md` §4)。
465///
466/// [`Tape::upload_resident`] が計測窓の外で 1 回だけ upload して作り、
467/// [`compat::Sequential::predict_resident_input`](推論)と [`Tape::matmul_resident`](行列積)が
468/// 入力の H2D なしで受け取る。中身(バッファ)は公開しない。推論では作成時の
469/// [`DeviceParamStore`] に束縛され、別 store・別デバイス・古い世代のハンドルは型付きエラーに
470/// なる。`!Send`(`Send` を足さない。イシュー #3254 で次の `compile_fail` により公開形として固定)。
471///
472/// ```compile_fail
473/// fn assert_send<T: Send>() {}
474/// assert_send::<fandhe_ai::ResidentTensor>();
475/// ```
476pub struct ResidentTensor(pub(crate) fandhe_ai_autodiff::optim::resident_input::ResidentInput);
477
478impl ResidentTensor {
479    /// 入力の shape。
480    pub fn shape(&self) -> &[usize] {
481        self.0.shape()
482    }
483
484    /// 入力が常駐するデバイス。
485    pub fn device(&self) -> Device {
486        self.0.device()
487    }
488}
489
490impl std::fmt::Debug for ResidentTensor {
491    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
492        std::fmt::Debug::fmt(&self.0, f)
493    }
494}
495
496/// 学習 1 step の loss(デバイス常駐スカラー)の不透明ハンドル(イシュー #3254 P6。公開形の決定は
497/// `docs/compat-resident-train-step-decision.md` §4)。
498///
499/// [`compat::Sequential::train_step_resident`] が返し、[`Self::read`] で `f32` に読み出す。
500/// **`read` が 1 step の唯一の D2H・同期点**(読まなければ同期は起きない)。所有権は
501/// [`DeviceParamStore`] に一本化している(ハンドル自体は store の loss 領域を指す鍵で、共有所有は
502/// 採らない)。次の step を積むと世代が進み、古いハンドルは [`BackendError::InvalidArgument`]
503/// になる。別 store のハンドルも `InvalidArgument`。store を drop した後は渡す先が無く読めない。
504/// `!Send`(`Send` を足さない。将来 `Send` を外す破壊的変更を避けるため marker で固定している)。
505///
506/// ```
507/// use fandhe_ai::{SgdConfig, Tensor, compat::Sequential};
508/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
509/// let tape = fandhe_ai::tape();
510/// let model = Sequential::new().add_linear(2, 4, 1)?.add_relu().add_linear(4, 1, 2)?;
511/// let mut store = model.init_device_param_store(&tape)?;
512/// let x = tape.upload_resident(&store, &Tensor::new(vec![0.5_f32; 6], &[3, 2])?)?;
513/// let y = tape.upload_resident(&store, &Tensor::new(vec![1.0_f32; 3], &[3, 1])?)?;
514/// let loss = model.train_step_resident(&mut store, &x, &y, &SgdConfig::new(0.05))?;
515/// tape.wait_device_param_store(&store)?; // 読み出しなしの完了待ち(P7)
516/// assert!(loss.read(&mut store)?.is_finite()); // 唯一の D2H・同期点(P6)
517/// # Ok(())
518/// # }
519/// ```
520///
521/// `Send` を要求するとコンパイルが通らない(公開形の固定)。
522///
523/// ```compile_fail
524/// fn assert_send<T: Send>() {}
525/// assert_send::<fandhe_ai::ResidentLoss>();
526/// ```
527pub struct ResidentLoss(
528    pub(crate) fandhe_ai_autodiff::optim::resident_input::TrainStepLoss,
529    std::marker::PhantomData<*const ()>,
530);
531
532impl ResidentLoss {
533    /// loss を `f32` で読む(D2H と同期はここ 1 回だけ。イシュー #3254 P6)。
534    ///
535    /// 別 `store`・古い世代のハンドルは [`BackendError::InvalidArgument`]。poison 済み `store` は
536    /// [`BackendError::StorePoisoned`]。読み出し後に失敗トークンがセット済みなら `store` を
537    /// poison して `StorePoisoned`(積んだ GPU 仕事の失敗が表面化した場合)。Tape 経路へ
538    /// フォールバックした step の loss はホストで確定済みで、同期なしで返る。
539    pub fn read(&self, store: &mut DeviceParamStore) -> Result<f32, AutodiffError> {
540        // 内部 tape は作り直しても順序が保たれる: CUDA は ordinal で context/default stream を
541        // プロセス内共有(`backend-cuda::context_cache::cached_device`)、Metal はプロセス全体の
542        // バッチ(`cached_context`)に積むため、`train_step_resident` 側の tape を drop しても
543        // 積んだ仕事は失われず、download はストリーム順で SGD 書き込みの後に並ぶ。
544        let tape = tape_for(store.device())?;
545        store
546            .read_train_step_loss(&tape.0, &self.0)
547            .map_err(AutodiffError::Backend)
548    }
549}
550
551impl std::fmt::Debug for ResidentLoss {
552    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
553        std::fmt::Debug::fmt(&self.0, f)
554    }
555}
556
557impl Tape {
558    /// `x` を `store` のデバイスへ **1 回だけ** upload し、常駐入力ハンドルを返す
559    /// (イシュー #3250 P2。計測窓の外で呼ぶ想定)。`store` は `self` と同じデバイスで
560    /// なければならず、違えば [`BackendError::DeviceMismatch`]。poison 済みの `store` は
561    /// [`BackendError::StorePoisoned`]。
562    pub fn upload_resident(
563        &self,
564        store: &DeviceParamStore,
565        x: &Tensor<f32>,
566    ) -> Result<ResidentTensor, AutodiffError> {
567        store
568            .upload_resident_input(&self.0, x)
569            .map(ResidentTensor)
570            .map_err(AutodiffError::Backend)
571    }
572
573    /// 常駐した `a: [m, k]`・`b: [k, n]` の行列積を計算し、結果を D2H 1 回でホストへ返す
574    /// (イシュー #3250 P4)。ホスト入力の `Var::matmul` と bit 一致する(バックエンドが
575    /// `gemm` と同じ核を持つ場合。CUDA の TF32 系精度モードなど未対応なら
576    /// [`BackendError::Unsupported`]。ホスト経路へは落とさない)。同じハンドルを `a` と `b`
577    /// の両方に渡してもよい。
578    ///
579    /// ```
580    /// use fandhe_ai::{Tensor, compat::Sequential};
581    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
582    /// let tape = fandhe_ai::tape();
583    /// let model = Sequential::new().add_linear(2, 3, 1)?;
584    /// let store = model.init_device_param_store(&tape)?;
585    /// let a = tape.upload_resident(&store, &Tensor::new(vec![1.0_f32, 2.0, 3.0, 4.0], &[2, 2])?)?;
586    /// let product = tape.matmul_resident(&a, &a)?; // D2H 1 回
587    /// assert_eq!(product.shape(), &[2, 2]);
588    /// // 推論は常駐入力のまま渡せる(入力の H2D なし)。
589    /// let out = model.predict_resident_input(&store, &a)?;
590    /// assert_eq!(out.shape(), &[2, 3]);
591    /// # Ok(())
592    /// # }
593    /// ```
594    pub fn matmul_resident(
595        &self,
596        a: &ResidentTensor,
597        b: &ResidentTensor,
598    ) -> Result<Tensor<f32>, AutodiffError> {
599        fandhe_ai_autodiff::optim::resident_input::matmul_resident(&self.0, &a.0, &b.0)
600            .map_err(AutodiffError::Backend)
601    }
602
603    /// `store` のデバイスに積まれた仕事の完了を、ホスト転送(D2H)なしで待つ(イシュー #3254 P7)。
604    /// loss を読まない step の間でデバイスの進行を区切りたいときに使う(読み出しは
605    /// [`ResidentLoss::read`])。poison 済み `store` は [`BackendError::StorePoisoned`]、別デバイスは
606    /// [`BackendError::DeviceMismatch`]。待機後に失敗トークンがセット済みなら `store` を poison して
607    /// `StorePoisoned`。バックエンドが D2H なしの待機を持たない場合は [`BackendError::Unsupported`]
608    /// (store は変わらない。ホストへは落とさない)。
609    pub fn wait_device_param_store(&self, store: &DeviceParamStore) -> Result<(), AutodiffError> {
610        store.wait_device(&self.0).map_err(AutodiffError::Backend)
611    }
612
613    /// 入力テンソルをテープ上の葉ノード `Var` として登録する
614    /// (`fandhe_ai_autodiff::Tape::var` への委譲)。
615    pub fn var(&self, tensor: &Tensor<f32>) -> Var<'_> {
616        self.0.var(tensor)
617    }
618
619    /// 非 f32 dtype の入力テンソルを f32 へ変換したうえでテープ上の
620    /// 葉ノード `Var` として登録する([`Self::var`] の dtype 変換版。
621    /// イシュー #1750・`fandhe_ai_autodiff::Tape::var_from` への委譲)。
622    pub fn var_from<T: CastElement>(&self, tensor: &Tensor<T>) -> Result<Var<'_>, AutodiffError> {
623        self.0.var_from(tensor)
624    }
625
626    /// 入力テンソルを `requires_grad == false` の葉ノードとして
627    /// テープ上へ登録する(イシュー #1748・PyTorch
628    /// `requires_grad=False` 相当。`fandhe_ai_autodiff::Tape::
629    /// var_no_grad` への委譲。`Var::detach`〈既存 `Var` 再エクスポート
630    /// 経由で到達〉と対になる no_grad 側の入口)。
631    pub fn var_no_grad(&self, tensor: &Tensor<f32>) -> Var<'_> {
632        self.0.var_no_grad(tensor)
633    }
634
635    /// `loss` から逆伝播し勾配を計算する(`fandhe_ai_autodiff::Tape::backward`
636    /// への委譲)。
637    pub fn backward(&self, loss: &Var<'_>) -> Result<Gradients, AutodiffError> {
638        self.0.backward(loss)
639    }
640
641    /// `loss` から逆伝播し、その結果を既存の `into`(同一世代の
642    /// `Gradients`)へ加算する(イシュー #1749・`docs/compat-api-scope.md`
643    /// §5 経路 2〈#1612 承認〉。`fandhe_ai_autodiff::Tape::backward_
644    /// accumulate` への委譲)。PyTorch の複数回 `loss.backward()` に
645    /// よる `.grad` 蓄積相当の opt-in API。`retain_graph`(テープは
646    /// `reset`/drop まで常時グラフを保持し、同一グラフへの複数回
647    /// `backward` は無条件で成功する契約)自体は追加の API なしで
648    /// 常時成立している(`fandhe_ai_autodiff::Tape` doc「`retain_graph`
649    /// 契約」参照)。
650    pub fn backward_accumulate(
651        &self,
652        loss: &Var<'_>,
653        into: &mut Gradients,
654    ) -> Result<(), AutodiffError> {
655        self.0.backward_accumulate(loss, into)
656    }
657
658    /// ノード列を葉プレフィックスまで切り詰め、次のステップで同一
659    /// `Tape` を再利用可能にする(イシュー #1048。
660    /// `fandhe_ai_autodiff::Tape::reset` への委譲。同メソッドの doc
661    /// 「学習ループでの運用」参照)。学習ループ・reuse GEMM が step
662    /// ごとに新しい `Tape` を生成・破棄する運用の代替となる。
663    pub fn reset(&mut self) {
664        self.0.reset();
665    }
666
667    /// [`Tape::reset`] 後も保持される葉の個数(`fandhe_ai_autodiff::
668    /// Tape::leaf_count` への委譲)。
669    pub fn leaf_count(&self) -> usize {
670        self.0.leaf_count()
671    }
672
673    /// 保持される葉 `index` 番目(登録順)の `Var` を再取得する
674    /// (`fandhe_ai_autodiff::Tape::leaf` への委譲。範囲外・非 `Var`
675    /// 表現の葉は `None`)。
676    pub fn leaf(&self, index: usize) -> Option<Var<'_>> {
677        self.0.leaf(index)
678    }
679
680    /// [`DeviceParamStore::step`] への委譲入口(イシュー #935)。
681    ///
682    /// `DeviceParamStore` の状態機械メソッドは `fandhe_ai_autodiff::Tape`
683    /// (内部クレートの生の型)を直接引数に取るため、`facade::Tape`
684    /// (本型。内部フィールド `0` は `pub(crate)`)の利用者からは直接
685    /// 呼べない。本メソッドは `&self.0` を渡すだけの薄い委譲であり、
686    /// `BackendOps`/`MemoryOps` を利用者向け公開面へ露出しない
687    /// (`crate::lib.rs` モジュール doc「公開面の設計」・REQ-12)。
688    pub fn step_device_param_store(
689        &self,
690        store: &mut DeviceParamStore,
691        grads: &Gradients,
692        config: &SgdConfig,
693    ) -> Result<(), BackendError> {
694        store.step(&self.0, grads, config)
695    }
696
697    /// [`DeviceParamStore::step_adam`] への委譲入口(イシュー #1959)。
698    /// `step_device_param_store`(SGD)と同じ理由の薄い委譲。
699    pub fn step_device_param_store_adam(
700        &self,
701        store: &mut DeviceParamStore,
702        grads: &Gradients,
703        config: &AdamConfig,
704    ) -> Result<(), BackendError> {
705        store.step_adam(&self.0, grads, config)
706    }
707
708    /// [`DeviceParamStore::step_adamw`] への委譲入口(イシュー #1959)。
709    /// `step_device_param_store`(SGD)と同じ理由の薄い委譲。
710    pub fn step_device_param_store_adamw(
711        &self,
712        store: &mut DeviceParamStore,
713        grads: &Gradients,
714        config: &AdamWConfig,
715    ) -> Result<(), BackendError> {
716        store.step_adamw(&self.0, grads, config)
717    }
718
719    /// [`DeviceParamStore::step_rmsprop`] への委譲入口(イシュー
720    /// #2175)。`step_device_param_store`(SGD)と同じ理由の薄い委譲。
721    pub fn step_device_param_store_rmsprop(
722        &self,
723        store: &mut DeviceParamStore,
724        grads: &Gradients,
725        config: &RmsPropConfig,
726    ) -> Result<(), BackendError> {
727        store.step_rmsprop(&self.0, grads, config)
728    }
729
730    /// [`DeviceParamStore::step_adagrad`] への委譲入口(イシュー
731    /// #2175)。`step_device_param_store`(SGD)と同じ理由の薄い委譲。
732    pub fn step_device_param_store_adagrad(
733        &self,
734        store: &mut DeviceParamStore,
735        grads: &Gradients,
736        config: &AdagradConfig,
737    ) -> Result<(), BackendError> {
738        store.step_adagrad(&self.0, grads, config)
739    }
740
741    /// [`DeviceParamStore::step_lamb`] への委譲入口(イシュー #2175)。
742    /// `step_device_param_store`(SGD)と同じ理由の薄い委譲。
743    pub fn step_device_param_store_lamb(
744        &self,
745        store: &mut DeviceParamStore,
746        grads: &Gradients,
747        config: &LambConfig,
748    ) -> Result<(), BackendError> {
749        store.step_lamb(&self.0, grads, config)
750    }
751
752    /// [`DeviceParamStore::step_amp`] への委譲入口(イシュー #2181。AMP
753    /// を常駐 step へ結線する。`docs/device-resident-update-design.md`
754    /// 追補)。`step_device_param_store`(SGD)と同じ理由の薄い委譲だが、
755    /// 戻り値は `Result<(), BackendError>` ではなく `Result<bool,
756    /// AutodiffError>`(内部で [`GradScaler::update`] も呼ぶため
757    /// `AutodiffError`。`bool` は「この step が非有限勾配により skip
758    /// されたか」)。
759    ///
760    /// 1 step の使い方: `scaler.scale_loss(&loss)` → `tape.
761    /// backward_device_param_store(&scaled, &store)`(`Op::
762    /// LinearResident` を含むグラフの場合。含まない場合は素の
763    /// [`Tape::backward`])→ 本メソッド。戻り値 `true` は skip
764    /// (どのパラメータも更新されず、forward 登録のみ消費された)ことを
765    /// 示し、呼び出し元は次の step へそのまま進めばよい
766    /// (`crate::optim::GradScaler` doc「1 step の使い方」参照)。
767    pub fn step_device_param_store_amp(
768        &self,
769        store: &mut DeviceParamStore,
770        grads: &Gradients,
771        config: &SgdConfig,
772        scaler: &mut GradScaler,
773    ) -> Result<bool, AutodiffError> {
774        store.step_amp(&self.0, grads, config, scaler)
775    }
776
777    /// [`DeviceParamStore::step_adam_amp`] への委譲入口(イシュー
778    /// #2181)。[`Self::step_device_param_store_amp`] と同じ理由の
779    /// 薄い委譲。
780    pub fn step_device_param_store_adam_amp(
781        &self,
782        store: &mut DeviceParamStore,
783        grads: &Gradients,
784        config: &AdamConfig,
785        scaler: &mut GradScaler,
786    ) -> Result<bool, AutodiffError> {
787        store.step_adam_amp(&self.0, grads, config, scaler)
788    }
789
790    /// [`DeviceParamStore::step_adamw_amp`] への委譲入口(イシュー
791    /// #2181)。[`Self::step_device_param_store_amp`] と同じ理由の
792    /// 薄い委譲。
793    pub fn step_device_param_store_adamw_amp(
794        &self,
795        store: &mut DeviceParamStore,
796        grads: &Gradients,
797        config: &AdamWConfig,
798        scaler: &mut GradScaler,
799    ) -> Result<bool, AutodiffError> {
800        store.step_adamw_amp(&self.0, grads, config, scaler)
801    }
802
803    /// [`DeviceParamStore::backward`] への委譲入口(イシュー #1022)。
804    ///
805    /// `Sequential::forward_resident`(`compat::sequential`)で forward
806    /// したグラフ(`Op::LinearResident` を含む)は、weight のデバイス
807    /// バッファを解決できる本メソッドで backward する必要がある——
808    /// 素の [`Tape::backward`] はこの解決手段を持たず型付きエラーで
809    /// 拒否する(`fandhe_ai_autodiff::optim::device_store::
810    /// DeviceParamStore::backward` doc・`docs/device-resident-update-
811    /// design.md` §3.3e 参照)。`step_device_param_store` と同じ理由の
812    /// 薄い委譲であり、`BackendOps`/`MemoryOps` を利用者向け公開面へ
813    /// 露出しない(`crate::lib.rs` モジュール doc「公開面の設計」・
814    /// REQ-12)。
815    ///
816    /// 入力が `var_no_grad` 等で勾配不要な層は d_input の GEMM を省く(#3246)。
817    /// その入力の `Gradients::get` は `Err(GradientTrackingDisabled)`。
818    pub fn backward_device_param_store(
819        &self,
820        loss: &Var<'_>,
821        store: &DeviceParamStore,
822    ) -> Result<Gradients, AutodiffError> {
823        store.backward(&self.0, loss)
824    }
825
826    /// [`DeviceParamStore::sync_to_host`] への委譲入口(イシュー #935)。
827    /// 上記 `step_device_param_store` と同じ理由の薄い委譲。
828    pub fn sync_device_param_store_to_host(
829        &self,
830        store: &DeviceParamStore,
831    ) -> Result<Vec<Tensor<f32>>, BackendError> {
832        store.sync_to_host(&self.0)
833    }
834
835    /// [`DeviceParamStore::resident_grads_to_host`] への委譲入口
836    /// (イシュー #1479)。resident 経路(`GradStaging`)で新鮮に充填
837    /// 済みの勾配のみをホストへ読み出す。weight slot は CPU・CUDA
838    /// 〈#1559〉・Metal〈#1555〉のいずれも resident 経由で `Some`。bias
839    /// slot は Metal〈#1566 以降〉・CUDA〈#3204 以降〉が resident 経由で
840    /// `Some` を返し、CPU は引き続き `None`(bias 縮約はホスト経由の
841    /// `Gradients` へ回る。イシュー #1898・`crates/backend-metal/src/
842    /// ops.rs::MetalBackendOps::gemm_fp32_strict_into_with_bias_reduce_
843    /// tracked` doc 参照)。resident 未対応バックエンド(`gemm_fp32_
844    /// strict_into` 未実装のモック等)では [`BackendError::Unsupported`]
845    /// を返す(panic なし)。全パラメータの勾配をバックエンド横断で
846    /// 読みたい場合は [`Self::param_grads_to_host`] を使う。上記
847    /// `sync_device_param_store_to_host` と同じ理由の薄い委譲。
848    pub fn resident_grads_to_host(
849        &self,
850        store: &DeviceParamStore,
851        grads: &Gradients,
852    ) -> Result<Vec<Option<Tensor<f32>>>, BackendError> {
853        store.resident_grads_to_host(&self.0, grads)
854    }
855
856    /// [`DeviceParamStore::param_grads_to_host`] への委譲入口
857    /// (イシュー #1479)。resident 経由で充填済みの slot は staging
858    /// から、それ以外は `grads` からのフォールバックで、全パラメータの
859    /// 勾配を 3 バックエンド共通の読み出し窓として返す(CUDA/Metal も
860    /// `Ok` を返す。§設計は `fandhe_ai_autodiff::optim::device_store::
861    /// DeviceParamStore::param_grads_to_host` doc 参照)。上記と同じ
862    /// 理由の薄い委譲。
863    pub fn param_grads_to_host(
864        &self,
865        store: &DeviceParamStore,
866        grads: &Gradients,
867    ) -> Result<Vec<Tensor<f32>>, BackendError> {
868        store.param_grads_to_host(&self.0, grads)
869    }
870
871    /// この `Tape` が結線されているデバイス(イシュー #1614)。
872    /// `fandhe_ai_autodiff::Tape::device` への委譲。
873    pub fn device(&self) -> Device {
874        self.0.device()
875    }
876
877    /// 別の `facade::Tape`(`self` 自身でもよい)上の `source` を、
878    /// この `Tape` 上へ新しい葉ノードとして転送する(イシュー #1614。
879    /// `fandhe_ai_autodiff::Var::to_tape` への委譲)。
880    ///
881    /// facade 利用者は `fandhe_ai_autodiff::Tape`(生の内部型)を
882    /// 取り出せない(本型のフィールド `0` は `pub(crate)`)ため、
883    /// facade 経由でクロスデバイス転送を行う唯一の入口がこのメソッド
884    /// になる。`self` と `source` が同じ `Tape` を指す場合は恒等
885    /// (`Var::to_tape` の契約どおり)。値の数値契約・`requires_grad`
886    /// 引き継ぎ・`reset` 契約は `fandhe_ai_autodiff::Var::to_tape` の
887    /// doc comment を参照。
888    pub fn transfer(&self, source: &Var<'_>) -> Result<Var<'_>, AutodiffError> {
889        source.to_tape(&self.0)
890    }
891
892    /// 子テープ方式の高階微分(`create_graph`)入口(イシュー #2545・
893    /// `fandhe_ai_autodiff::Tape::backward_create_graph` への薄い委譲。
894    /// 公開形は `docs/autodiff-higher-order-grad-decision.md` §17.2)。
895    ///
896    /// `loss` を `self`(親テープ)上で逆伝播し、1 階勾配の計算過程を
897    /// `child`(子テープ)へ `Var` 演算として記録する。返る
898    /// [`CreateGraphResult`] の `grad`/`child_var` で得た子テープ上の
899    /// `Var` を `child.backward(..)` でさらに微分すれば二階勾配(Hessian・
900    /// HVP)が得られる。`first_order()` は通常の [`Tape::backward`] と
901    /// bit 同一。
902    ///
903    /// `child` は [`tape`]/[`tape_for`] で作った**空**の `Tape` で、`self`
904    /// と別のものでなければならない。`BackendOps` を露出しない薄い委譲
905    /// (REQ-12)。エラー契約は既存 [`AutodiffError`] の variant のみ:
906    /// `Backward`(同一テープ・非空の子・checkpoint・未対応 Op)/
907    /// `TapeMismatch`/`DeviceMismatch`/`GradientTrackingDisabled`。
908    /// 拒否時は `child` へ何も書き込まない。
909    ///
910    /// 対象 Op の正本は `fandhe_ai_autodiff` の `Op::supports_create_graph` の網羅 match と決定記録
911    /// `docs/autodiff-higher-order-grad-decision.md` §21.2・§22〜§31(#3077〜#3086 で正規化・畳み込み 2D・Gelu・損失・
912    /// 索引累積・Pad・プーリング・線形代数/FFT の一部へ拡大)。`Tape::custom` のユーザー定義関数は恒久的に対象外。
913    ///
914    /// ```
915    /// use fandhe_ai::{tape, Tensor};
916    ///
917    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
918    /// let t = tape();
919    /// let child = tape();
920    /// let x = t.var(&Tensor::new(vec![2.0_f32], &[1])?);
921    /// let loss = x.mul(&x)?.mul(&x)?.sum(None)?; // x^3
922    /// let cg = t.backward_create_graph(&loss, &child)?;
923    /// // 1 階: 3x^2 = 12
924    /// let first = cg.first_order().get(&x)?.unwrap().as_slice().unwrap().to_vec();
925    /// assert!((first[0] - 12.0).abs() < 1e-4);
926    /// // 2 階: 6x = 12(子テープ上でもう一度逆伝播する)
927    /// let g = cg.grad(&x)?.unwrap();
928    /// let grads2 = child.backward(&g.sum(None)?)?;
929    /// let xc = cg.child_var(&x)?.unwrap();
930    /// let second = grads2.get(&xc)?.unwrap().as_slice().unwrap().to_vec();
931    /// assert!((second[0] - 12.0).abs() < 1e-4);
932    /// # Ok(())
933    /// # }
934    /// ```
935    pub fn backward_create_graph<'c>(
936        &self,
937        loss: &Var<'_>,
938        child: &'c Tape,
939    ) -> Result<CreateGraphResult<'c>, AutodiffError> {
940        self.0.backward_create_graph(loss, &child.0)
941    }
942
943    /// 重みなしの度数カウント(`torch.bincount(input, minlength=…)` 相当。イシュー
944    /// #2678・`fandhe_ai_autodiff::binning_ops::bincount` への薄い委譲)。
945    ///
946    /// `Var` を取らない演算のため `BackendOps` へ到達する `Tape` が入口になる
947    /// (REQ-12 により生の autodiff `Tape` は露出しない)。`input` は 1 次元・非負のみ。
948    /// 出力長は `max(max(input) + 1, minlength)`。違反は型付きエラーで返る。
949    ///
950    /// ```
951    /// use fandhe_ai::{tape, Tensor};
952    ///
953    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
954    /// let t = tape();
955    /// let counts = t.bincount(&Tensor::new(vec![0_i32, 1, 1, 3], &[4])?, 0)?;
956    /// assert_eq!(counts.host_slice().into_owned(), [1, 2, 0, 1]);
957    /// # Ok(())
958    /// # }
959    /// ```
960    pub fn bincount(
961        &self,
962        input: &Tensor<i32>,
963        minlength: usize,
964    ) -> Result<Tensor<i32>, AutodiffError> {
965        fandhe_ai_autodiff::binning_ops::bincount(&self.0, input, minlength)
966    }
967
968    /// 重み付きの度数カウント(`torch.bincount(input, weights, minlength)` 相当。
969    /// イシュー #2678・`fandhe_ai_autodiff::binning_ops::bincount_weighted` への
970    /// 薄い委譲)。
971    ///
972    /// 出力は detached(`weights` への勾配は流れない)。`weights` が別の `Tape` の
973    /// `Var` なら [`AutodiffError::TapeMismatch`]。
974    ///
975    /// ```
976    /// use fandhe_ai::{tape, Tensor};
977    ///
978    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
979    /// let t = tape();
980    /// let w = t.var(&Tensor::new(vec![0.5_f32, 1.0, 2.0], &[3])?);
981    /// let out = t.bincount_weighted(&Tensor::new(vec![0_i32, 1, 1], &[3])?, &w, 0)?;
982    /// assert_eq!(out.host_slice().into_owned(), [0.5, 3.0]);
983    /// # Ok(())
984    /// # }
985    /// ```
986    pub fn bincount_weighted(
987        &self,
988        input: &Tensor<i32>,
989        weights: &Var<'_>,
990        minlength: usize,
991    ) -> Result<Tensor<f32>, AutodiffError> {
992        fandhe_ai_autodiff::binning_ops::bincount_weighted(&self.0, input, weights, minlength)
993    }
994
995    /// ヤコビアン `∂output/∂input`(`torch.autograd.functional.jacobian` の
996    /// reverse-mode 相当。イシュー #2678・`fandhe_ai_autodiff::jacobian_ops::jacobian`
997    /// への薄い委譲)。
998    ///
999    /// 戻り値は shape `output.shape ++ input.shape` の非微分ホスト値で、行 `i` は
1000    /// `output` の平坦添字 `i` の `input` に関する勾配。`input` が勾配追跡なしなら
1001    /// [`AutodiffError::GradientTrackingDisabled`]、別テープなら
1002    /// [`AutodiffError::TapeMismatch`]。`output` の要素ごとに逆伝播するため計算量は
1003    /// `output` の要素数に比例する。
1004    ///
1005    /// ```
1006    /// use fandhe_ai::{tape, Tensor};
1007    ///
1008    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1009    /// let t = tape();
1010    /// let x = t.var(&Tensor::new(vec![1.0_f32, 2.0], &[2])?);
1011    /// let y = x.mul(&x)?; // y_i = x_i^2
1012    /// let j = t.jacobian(&y, &x)?;
1013    /// assert_eq!(j.shape(), &[2, 2]);
1014    /// assert_eq!(j.host_slice().into_owned(), [2.0, 0.0, 0.0, 4.0]);
1015    /// # Ok(())
1016    /// # }
1017    /// ```
1018    pub fn jacobian(
1019        &self,
1020        output: &Var<'_>,
1021        input: &Var<'_>,
1022    ) -> Result<Tensor<f32>, AutodiffError> {
1023        fandhe_ai_autodiff::jacobian_ops::jacobian(&self.0, output, input)
1024    }
1025
1026    /// ヘッセ行列 `∂²loss/∂input²`(`torch.autograd.functional.hessian` の
1027    /// reverse-mode 相当。イシュー #2678・`fandhe_ai_autodiff::jacobian_ops::hessian`
1028    /// への薄い委譲)。
1029    ///
1030    /// `child` は [`Tape::backward_create_graph`] と同じく [`tape`]/[`tape_for`] で作った
1031    /// **空**の別 `Tape`。`loss` は要素数 1 でなければならない。対象は
1032    /// `create_graph` 対応 Op の範囲で、非対応・非空の子などは
1033    /// [`AutodiffError::Backward`] 等の既存エラー variant で拒否される。
1034    ///
1035    /// 対象 Op の正本は `fandhe_ai_autodiff` の `Op::supports_create_graph` の網羅 match と決定記録
1036    /// `docs/autodiff-higher-order-grad-decision.md` §21.2・§22〜§31(#3077〜#3086 で正規化・畳み込み 2D・Gelu・損失・
1037    /// 索引累積・Pad・プーリング・線形代数/FFT の一部へ拡大)。`Tape::custom` のユーザー定義関数は恒久的に対象外。
1038    ///
1039    /// ```
1040    /// use fandhe_ai::{tape, Tensor};
1041    ///
1042    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1043    /// let t = tape();
1044    /// let child = tape();
1045    /// let x = t.var(&Tensor::new(vec![2.0_f32], &[1])?);
1046    /// let loss = x.mul(&x)?.mul(&x)?.sum(None)?; // x^3
1047    /// let h = t.hessian(&loss, &x, &child)?;
1048    /// assert!((h.host_slice()[0] - 12.0).abs() < 1e-4); // 6x
1049    /// # Ok(())
1050    /// # }
1051    /// ```
1052    pub fn hessian(
1053        &self,
1054        loss: &Var<'_>,
1055        input: &Var<'_>,
1056        child: &Tape,
1057    ) -> Result<Tensor<f32>, AutodiffError> {
1058        fandhe_ai_autodiff::jacobian_ops::hessian(&self.0, loss, input, &child.0)
1059    }
1060
1061    /// ベクトル・ヤコビ積 `cotangentᵀ · ∂output/∂input`(`torch.func.vjp` 相当。イシュー #2931・
1062    /// 設計記録 `docs/autodiff-functional-transforms-design.md` §23。内部実装
1063    /// `fandhe_ai_autodiff::functional_ops` の `vjp` への薄い委譲)。
1064    ///
1065    /// 戻り値は `input` と同じ shape の非微分のホスト値。`cotangent` は `output` と shape が完全一致
1066    /// (ブロードキャストなし)でなければならない。
1067    ///
1068    /// # エラー(入口検査の順序)
1069    ///
1070    /// [`AutodiffError::TapeMismatch`] → [`AutodiffError::GradientTrackingDisabled`](`input` が追跡なし)
1071    /// → `cotangent` の shape 不一致(`Shape(ShapeMismatch)`)→ 要素数の検査。
1072    ///
1073    /// # 追跡なしの挙動(現状のまま・契約は変えない)
1074    ///
1075    /// 追跡なしの `output` に対しては全ゼロを返す(`Err` にならない)。追跡なしの `input` は
1076    /// `Err(GradientTrackingDisabled)`。`hvp` とは `output`/`loss` の追跡なしの扱いが非対称。
1077    ///
1078    /// # 副作用
1079    ///
1080    /// 入口検査とゼロ返却分岐を通過した本体経路に限り、親テープへちょうど 2 ノード(余接の葉と `mul`)を
1081    /// 足す。入口検査の失敗時、および要素数 0 または追跡なし `output` でゼロを返す場合は足さない。
1082    ///
1083    /// # 数値・適用範囲
1084    ///
1085    /// 数値は REQ-2 の統一複合判定で、`hvp` の 1 階 VJP との bit 同一は契約にしない。f32 の `Tape` のみ
1086    /// (`VarF64`・低精度 forward は対象外)。
1087    ///
1088    /// ```
1089    /// use fandhe_ai::{tape, Tensor};
1090    ///
1091    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1092    /// let t = tape();
1093    /// let x = t.var(&Tensor::new(vec![1.0_f32, 2.0, 3.0], &[3])?);
1094    /// let y = x.mul(&x)?; // y = x ⊙ x
1095    /// let u = Tensor::new(vec![1.0_f32, 0.5, 2.0], &[3])?;
1096    /// let g = t.vjp(&y, &x, &u)?; // 2x ⊙ u
1097    /// assert_eq!(g.shape(), &[3]);
1098    /// assert_eq!(g.host_slice().into_owned(), [2.0, 2.0, 12.0]);
1099    /// # Ok(())
1100    /// # }
1101    /// ```
1102    pub fn vjp(
1103        &self,
1104        output: &Var<'_>,
1105        input: &Var<'_>,
1106        cotangent: &Tensor<f32>,
1107    ) -> Result<Tensor<f32>, AutodiffError> {
1108        fandhe_ai_autodiff::functional_ops::vjp(&self.0, output, input, cotangent)
1109    }
1110
1111    /// ヘッセ・ベクトル積 `∂²loss/∂input² · vector`(reverse-over-reverse。`torch.func.hvp` 相当。
1112    /// イシュー #2931・設計記録 §23。内部実装 `fandhe_ai_autodiff::functional_ops` の `hvp` への
1113    /// 薄い委譲)。
1114    ///
1115    /// `child` は [`tape`]/[`tape_for`] で作った**空**の別 `Tape`([`Tape::hessian`] と同じ契約)。
1116    /// 戻り値は `input` と同じ shape の非微分のホスト値。
1117    ///
1118    /// # エラー(入口検査の順序。`vjp` とは異なる)
1119    ///
1120    /// [`AutodiffError::TapeMismatch`](`loss`・`input` の順)→ [`AutodiffError::GradientTrackingDisabled`]
1121    /// → `loss` の要素数 1(`[]`・`[1]`・`[1, 1]` は可。違反は [`AutodiffError::InvalidArgument`])
1122    /// → `vector` の shape 完全一致(`Shape(ShapeMismatch)`)→ `input` の要素数検査。`loss` の要素数と
1123    /// `vector` の shape が両方不正な場合は `ShapeMismatch` ではなく `InvalidArgument` が返る。
1124    ///
1125    /// # 追跡なしの挙動(現状のまま・契約は変えない)
1126    ///
1127    /// 追跡なしの `loss` に対しては `backward_create_graph` の `Err` を伝播する(`vjp` の全ゼロ返却と
1128    /// 非対称)。追跡なしの `input` は `Err(GradientTrackingDisabled)`。
1129    ///
1130    /// # 副作用
1131    ///
1132    /// 親テープへノードを足さない。子テープにはノードが残るので、呼び出し後の `child` は作り直す。
1133    ///
1134    /// # 数値・適用範囲
1135    ///
1136    /// 数値は REQ-2 の統一複合判定で、1 階 VJP との bit 同一は契約にしない。経路上の Op は
1137    /// `create_graph` 対応(`supports_create_graph()` が真)のものに限る。f32 の `Tape` のみ
1138    /// (`VarF64`・低精度 forward は対象外)。
1139    /// 対象 Op の正本は `fandhe_ai_autodiff` の `Op::supports_create_graph` の網羅 match と決定記録
1140    /// `docs/autodiff-higher-order-grad-decision.md` §21.2・§22〜§31(#3077〜#3086 で正規化・畳み込み 2D・Gelu・損失・
1141    /// 索引累積・Pad・プーリング・線形代数/FFT の一部へ拡大)。`Tape::custom` のユーザー定義関数は恒久的に対象外。
1142    ///
1143    /// ```
1144    /// use fandhe_ai::{tape, Tensor};
1145    ///
1146    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1147    /// let t = tape();
1148    /// let child = tape();
1149    /// let x = t.var(&Tensor::new(vec![2.0_f32], &[1])?);
1150    /// let loss = x.mul(&x)?.mul(&x)?.sum(None)?; // x^3
1151    /// let v = Tensor::new(vec![1.0_f32], &[1])?;
1152    /// let hv = t.hvp(&loss, &x, &v, &child)?; // 6x ⊙ v
1153    /// assert!((hv.host_slice()[0] - 12.0).abs() < 1e-4);
1154    /// # Ok(())
1155    /// # }
1156    /// ```
1157    pub fn hvp(
1158        &self,
1159        loss: &Var<'_>,
1160        input: &Var<'_>,
1161        vector: &Tensor<f32>,
1162        child: &Tape,
1163    ) -> Result<Tensor<f32>, AutodiffError> {
1164        fandhe_ai_autodiff::functional_ops::hvp(&self.0, loss, input, vector, &child.0)
1165    }
1166
1167    /// ヤコビアン・ベクトル積 `J·v`(double-VJP 法。`torch.func.jvp` 相当の値。イシュー #2956・
1168    /// 設計記録 §27・§28。内部実装 `fandhe_ai_autodiff::functional_ops` の `jvp` への薄い委譲)。
1169    ///
1170    /// `J = ∂output/∂input`。結果は `output` と同じ shape の非微分のホスト値。`tangent` は `input` と
1171    /// shape が**完全一致**すること(ブロードキャストしない。`vjp` が output 側と照合するのとは向きが逆)。
1172    /// `child` は [`tape`]/[`tape_for`] で作った**空**の別 `Tape`([`Tape::hessian`]・[`Tape::hvp`]
1173    /// と同じ契約)。
1174    ///
1175    /// # エラー(入口検査の順序)
1176    ///
1177    /// [`AutodiffError::TapeMismatch`] → [`AutodiffError::GradientTrackingDisabled`](`input` が追跡なし)
1178    /// → `tangent` と `input` の shape 不一致(`Shape(ShapeMismatch)`)→ 要素数の検査 → 要素数 0 か
1179    /// 追跡なしの `output` なら全ゼロ(テープに触れない)。その後の `backward_create_graph` 側の拒否
1180    /// (`supports_create_graph()` が偽の Op・rank 3 以上の `MatMul`・空でない子テープや同一の子テープ・
1181    /// デバイス不一致・checkpoint 登録済み)は [`AutodiffError::Backward`] などの既存 variant をそのまま伝播する。
1182    ///
1183    /// # 追跡なしの挙動
1184    ///
1185    /// 追跡なしの `output` には全ゼロを返す([`Tape::jacobian`]・[`Tape::vjp`] と同じ。[`Tape::hvp`] が
1186    /// `Err` を返すのとは非対称)。追跡なしの `input` は `Err(GradientTrackingDisabled)`。
1187    ///
1188    /// # 副作用
1189    ///
1190    /// 入口検査を通った後は、失敗した場合でも親テープへちょうど 2 ノード(全要素 1 の追跡ありの葉と
1191    /// `mul`)が残る(`vjp` とは違う)。既存ノードの値は変わらない。成功時は子テープにノードが残るので、
1192    /// `child` は再利用せず作り直す。
1193    ///
1194    /// # 数値・適用範囲
1195    ///
1196    /// 経路上の Op は `Op::supports_create_graph()` が真のものに限り、非対象は型付きの `Err` になる。
1197    /// f32 の `Tape` のみ(`VarF64`・f16 は対象外)、入力は単一(複数入力は [`Tape::jvp_multi`])、結果は非微分のホスト値。数値は REQ-2 の
1198    /// 統一複合判定(相対誤差 1e-3 未満 または 絶対誤差 1e-5 未満)で一致し、`jacobian` や 1 階 VJP との
1199    /// bit 同一は契約にしない。計算量は親 backward 1 回+子 backward 1 回。
1200    /// 対象 Op の正本は `fandhe_ai_autodiff` の `Op::supports_create_graph` の網羅 match と決定記録
1201    /// `docs/autodiff-higher-order-grad-decision.md` §21.2・§22〜§31(#3077〜#3086 で正規化・畳み込み 2D・Gelu・損失・
1202    /// 索引累積・Pad・プーリング・線形代数/FFT の一部へ拡大)。`Tape::custom` のユーザー定義関数は恒久的に対象外。
1203    ///
1204    /// ```
1205    /// use fandhe_ai::{tape, Tensor};
1206    ///
1207    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1208    /// let t = tape();
1209    /// let child = tape();
1210    /// let x = t.var(&Tensor::new(vec![1.0_f32, 2.0, 3.0], &[3])?);
1211    /// let y = x.mul(&x)?; // y = x ⊙ x
1212    /// let v = Tensor::new(vec![1.0_f32, 0.5, 2.0], &[3])?;
1213    /// let jv = t.jvp(&y, &x, &v, &child)?; // 2x ⊙ v = [2, 2, 12]
1214    /// let jv = jv.host_slice().into_owned();
1215    /// // Tape::jacobian と tangent のホスト側の行列ベクトル積に一致する。
1216    /// let jac = t.jacobian(&y, &x)?.host_slice().into_owned();
1217    /// let vv = v.host_slice().into_owned();
1218    /// for i in 0..3 {
1219    ///     let expect: f32 = (0..3).map(|j| jac[i * 3 + j] * vv[j]).sum();
1220    ///     assert!((jv[i] - expect).abs() < 1e-4);
1221    /// }
1222    /// for (a, b) in jv.iter().zip([2.0_f32, 2.0, 12.0]) {
1223    ///     assert!((a - b).abs() < 1e-4);
1224    /// }
1225    /// # Ok(())
1226    /// # }
1227    /// ```
1228    pub fn jvp(
1229        &self,
1230        output: &Var<'_>,
1231        input: &Var<'_>,
1232        tangent: &Tensor<f32>,
1233        child: &Tape,
1234    ) -> Result<Tensor<f32>, AutodiffError> {
1235        fandhe_ai_autodiff::functional_ops::jvp(&self.0, output, input, tangent, &child.0)
1236    }
1237
1238    /// 前向き(入力要素数 `n` に比例)で求めるヤコビアン全体(double-VJP 法。`torch.func.jacfwd` 相当の値。
1239    /// イシュー #2956・設計記録 §27・§28。内部実装 `fandhe_ai_autodiff::functional_ops` の `jacfwd` への
1240    /// 薄い委譲)。
1241    ///
1242    /// 結果の shape は `output.shape ++ input.shape`([`Tape::jacobian`] と同じ並び)。`child` の契約・
1243    /// 入口検査の順序・追跡なしの挙動・副作用・数値の契約は [`Tape::jvp`] と同じ(`tangent` の検査を除く。
1244    /// `m × n` は検査付き乗算で求める)。計算量は子 backward を入力要素数 `n` 回([`Tape::jacobian`] は
1245    /// 出力要素数 `m` 回)。`child` は呼び出しごとに作り直す。
1246    ///
1247    /// ```
1248    /// use fandhe_ai::{tape, Tensor};
1249    ///
1250    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1251    /// let t = tape();
1252    /// let child = tape();
1253    /// let x = t.var(&Tensor::new(vec![1.0_f32, 2.0, 3.0], &[3])?);
1254    /// let y = x.mul(&x)?;
1255    /// let jf = t.jacfwd(&y, &x, &child)?; // diag(2x)
1256    /// assert_eq!(jf.shape(), &[3, 3]);
1257    /// let jf = jf.host_slice().into_owned();
1258    /// let jac = t.jacobian(&y, &x)?.host_slice().into_owned();
1259    /// for (a, b) in jf.iter().zip(jac.iter()) {
1260    ///     assert!((a - b).abs() < 1e-4);
1261    /// }
1262    /// # Ok(())
1263    /// # }
1264    /// ```
1265    pub fn jacfwd(
1266        &self,
1267        output: &Var<'_>,
1268        input: &Var<'_>,
1269        child: &Tape,
1270    ) -> Result<Tensor<f32>, AutodiffError> {
1271        fandhe_ai_autodiff::functional_ops::jacfwd(&self.0, output, input, &child.0)
1272    }
1273
1274    /// 複数入力のヤコビアン・ベクトル積 `J·v = Σ_i J_i·v_i`(`J_i = ∂output/∂inputs[i]`。
1275    /// `torch.func.jvp` に複数の primals/tangents を渡す形に相当。イシュー #3063・設計記録 §30。
1276    /// 内部実装 `fandhe_ai_autodiff::functional_ops` の `jvp_multi` への薄い委譲。[`Tape::jvp`] の追加のみの
1277    /// 拡張で、既存 `jvp` のシグネチャ・挙動は変えない)。
1278    ///
1279    /// 結果の shape は `output.shape()`。`inputs` と `tangents` は同じ長さで、`tangents[i]` は `inputs[i]` と
1280    /// 同じ shape(ブロードキャスト不可)。`child` は空の子テープで呼び出しごとに作り直す。
1281    ///
1282    /// # 入口検査(ノードを足す前。順序固定。失敗時は親・子テープとも無変更)
1283    ///
1284    /// 長さ不一致・空の `inputs` → `InvalidArgument`、別テープ → `TapeMismatch`、追跡なしの入力 →
1285    /// `GradientTrackingDisabled`、同一 `Var` の重複指定 → `InvalidArgument`、`tangents[i]` の shape 不一致 →
1286    /// `Shape(ShapeMismatch)`、要素数オーバーフロー → `Shape(ElementCountOverflow)`。追跡なしの `output`・
1287    /// 要素数 0 はテープに触れず全ゼロ。入力 1 つのときのエラーは [`Tape::jvp`] と一致する。
1288    ///
1289    /// # 副作用
1290    ///
1291    /// 入口検査後の失敗(非対象 Op・空でない子テープ等)でも親テープへちょうど 2 ノードが残る(入力数に依らない)。
1292    /// 成功時の子テープには補助ノードが残るため `child` は再利用しない。
1293    ///
1294    /// # 数値・適用範囲
1295    ///
1296    /// 経路上の Op は `Op::supports_create_graph()` が真のものに限る。f32 の `Tape` のみ、結果は非微分の
1297    /// ホスト値。数値は REQ-2 統一複合判定で `jacobian` 由来の `Σ J_i·v_i` と一致する(bit 同一は契約にしない)。
1298    /// 計算量は入力数に依らず親 backward 1 回+子 backward 1 回。
1299    /// 対象 Op の正本は `fandhe_ai_autodiff` の `Op::supports_create_graph` の網羅 match と決定記録
1300    /// `docs/autodiff-higher-order-grad-decision.md` §21.2・§22〜§31(#3077〜#3086 で正規化・畳み込み 2D・Gelu・損失・
1301    /// 索引累積・Pad・プーリング・線形代数/FFT の一部へ拡大)。`Tape::custom` のユーザー定義関数は恒久的に対象外。
1302    ///
1303    /// ```
1304    /// use fandhe_ai::{tape, Tensor};
1305    ///
1306    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1307    /// let t = tape();
1308    /// let child = tape();
1309    /// let x1 = t.var(&Tensor::new(vec![1.0_f32, 2.0, 3.0], &[3])?);
1310    /// let x2 = t.var(&Tensor::new(vec![4.0_f32, 5.0, 6.0], &[3])?);
1311    /// let y = x1.mul(&x2)?; // y = x1 ⊙ x2
1312    /// let v1 = Tensor::new(vec![1.0_f32, 0.5, 2.0], &[3])?;
1313    /// let v2 = Tensor::new(vec![0.0_f32, 1.0, -1.0], &[3])?;
1314    /// let jv = t.jvp_multi(&y, &[&x1, &x2], &[&v1, &v2], &child)?; // x2⊙v1 + x1⊙v2
1315    /// let jv = jv.host_slice().into_owned();
1316    /// for (a, b) in jv.iter().zip([4.0_f32, 4.5, 9.0]) {
1317    ///     assert!((a - b).abs() < 1e-4);
1318    /// }
1319    /// // Tape::jacobian 由来の参照 Σ J_i·v_i とも一致する。
1320    /// let j1 = t.jacobian(&y, &x1)?.host_slice().into_owned();
1321    /// let j2 = t.jacobian(&y, &x2)?.host_slice().into_owned();
1322    /// let (a1, a2) = (v1.host_slice().into_owned(), v2.host_slice().into_owned());
1323    /// for i in 0..3 {
1324    ///     let expect: f32 = (0..3).map(|j| j1[i * 3 + j] * a1[j] + j2[i * 3 + j] * a2[j]).sum();
1325    ///     assert!((jv[i] - expect).abs() < 1e-4);
1326    /// }
1327    /// # Ok(())
1328    /// # }
1329    /// ```
1330    pub fn jvp_multi(
1331        &self,
1332        output: &Var<'_>,
1333        inputs: &[&Var<'_>],
1334        tangents: &[&Tensor<f32>],
1335        child: &Tape,
1336    ) -> Result<Tensor<f32>, AutodiffError> {
1337        fandhe_ai_autodiff::functional_ops::jvp_multi(&self.0, output, inputs, tangents, &child.0)
1338    }
1339
1340    /// 微分可能なヤコビアン・ベクトル積 `J·v`(`torch.func.jvp` を `create_graph=True` で使う形に相当。
1341    /// イシュー #3068・設計記録 `docs/autodiff-functional-transforms-design.md` §31。内部実装
1342    /// `fandhe_ai_autodiff::functional_ops::jvp_create_graph` への薄い委譲で、追加のみ。
1343    /// 既存の [`Tape::jvp`](非微分のホスト値)は変えない)。
1344    ///
1345    /// `child`(中間)と `grandchild`(結果を置く)は呼び出し側が用意する空の `Tape` で、どちらも
1346    /// `self` と別のもの、かつ互いに別でなければならない。結果の [`JvpCreateGraphResult::output`] は
1347    /// `grandchild` 上の `Var<'g>`(shape = `output.shape()`)。成功後も失敗後も 2 枚のテープは再利用せず
1348    /// 作り直す。
1349    ///
1350    /// # 微分の繋がり方
1351    ///
1352    /// 元の入力についての微分は [`JvpCreateGraphResult::child_var`] で 2 段(親→子→孫)の写しを引き、
1353    /// `grandchild.backward(..)` で得る。親テープの `Var` そのものとは微分で繋がらない
1354    /// (`backward_create_graph` の写しが境界)。`child_var` が `Ok(None)` を返すのは、結果がその変数に
1355    /// 依存しないとき。`TapeMismatch`/`GradientTrackingDisabled` は `CreateGraphResult::child_var` と
1356    /// 同じ契約。
1357    ///
1358    /// # 入口検査(順序固定。ノードを足す前)
1359    ///
1360    /// 1〜4 は [`Tape::jvp`] と同じ(別テープ → `TapeMismatch`、追跡なしの入力 →
1361    /// `GradientTrackingDisabled`、`tangent` の shape 不一致 → `Shape(ShapeMismatch)`、要素数
1362    /// オーバーフロー → `Shape(ElementCountOverflow)`)。5 はテープの事前検査で、同一テープ →
1363    /// `Backward`、デバイス不一致 → `DeviceMismatch`、空でないテープ → `Backward`。5 までで失敗すれば
1364    /// 3 枚のテープとも無変更。
1365    ///
1366    /// # ゼロ経路
1367    ///
1368    /// 追跡なしの `output`、要素数 0、`J ≡ 0` のとき、`output()` は `grandchild` 上の全ゼロの追跡なし葉
1369    /// 1 個で、写しはすべて `None`。
1370    ///
1371    /// # ノードの残り方
1372    ///
1373    /// 1 段目・2 段目での拒否と成功時には親へ 2 ノードが残り、子・孫テープにも補助ノードが残る
1374    /// (詳細は設計記録 §31.4 の表)。
1375    ///
1376    /// # 数値・適用範囲
1377    ///
1378    /// 経路上の Op は `Op::supports_create_graph()` が真のものに限る。f32 の `Tape`・単一入力のみ。
1379    /// `output()` の値は REQ-2 統一複合判定の範囲で [`Tape::jvp`] と一致し、bit 同一は契約にしない。
1380    /// 計算量は親 backward 1 回+子 backward 1 回+孫テープへの記録 1 回。
1381    /// 対象 Op の正本は `fandhe_ai_autodiff` の `Op::supports_create_graph` の網羅 match と決定記録
1382    /// `docs/autodiff-higher-order-grad-decision.md` §21.2・§22〜§31(#3077〜#3086 で正規化・畳み込み 2D・Gelu・損失・
1383    /// 索引累積・Pad・プーリング・線形代数/FFT の一部へ拡大)。`Tape::custom` のユーザー定義関数は恒久的に対象外。
1384    ///
1385    /// ```
1386    /// use fandhe_ai::{tape, Tensor};
1387    ///
1388    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1389    /// let t = tape();
1390    /// let child = tape();
1391    /// let grandchild = tape();
1392    /// let x = t.var(&Tensor::new(vec![1.0_f32, 2.0, 3.0], &[3])?);
1393    /// let y = x.mul(&x)?; // y = x ⊙ x
1394    /// let v = Tensor::new(vec![1.0_f32, 0.5, 2.0], &[3])?;
1395    /// let res = t.jvp_create_graph(&y, &x, &v, &child, &grandchild)?;
1396    /// // output() = 2x ⊙ v = [2, 2, 12]
1397    /// let jv = res.output().value().host_slice().into_owned();
1398    /// for (a, b) in jv.iter().zip([2.0_f32, 2.0, 12.0]) {
1399    ///     assert!((a - b).abs() < 1e-4);
1400    /// }
1401    /// // さらに微分すると d(Σ 2x⊙v)/dx = 2v = [2, 1, 4]。
1402    /// let grads = grandchild.backward(&res.output().sum(None)?)?;
1403    /// let xc = res.child_var(&x)?.expect("結果は x に依存する");
1404    /// let g = grads.get(&xc)?.expect("勾配あり").host_slice().into_owned();
1405    /// for (a, b) in g.iter().zip([2.0_f32, 1.0, 4.0]) {
1406    ///     assert!((a - b).abs() < 1e-4);
1407    /// }
1408    /// # Ok(())
1409    /// # }
1410    /// ```
1411    pub fn jvp_create_graph<'g>(
1412        &self,
1413        output: &Var<'_>,
1414        input: &Var<'_>,
1415        tangent: &Tensor<f32>,
1416        child: &Tape,
1417        grandchild: &'g Tape,
1418    ) -> Result<JvpCreateGraphResult<'g>, AutodiffError> {
1419        fandhe_ai_autodiff::functional_ops::jvp_create_graph(
1420            &self.0,
1421            output,
1422            input,
1423            tangent,
1424            &child.0,
1425            &grandchild.0,
1426        )
1427    }
1428
1429    /// バッチ軸 `in_dim` に沿って `f` を各スライスへ適用し、結果を dim 0 に積む(`torch.func.vmap`
1430    /// 相当のループ版。イシュー #2931・設計記録 §23。内部実装 `fandhe_ai_autodiff::functional_ops` の
1431    /// `vmap` への薄い委譲)。
1432    ///
1433    /// 単一入力・`FnMut`。`out_dim` は無く、出力のバッチ軸は dim 0 固定。戻り値は同じテープ上の
1434    /// 微分可能な [`Var`]。
1435    ///
1436    /// # エラー
1437    ///
1438    /// Phase A(テープ無変更): [`AutodiffError::TapeMismatch`]・軸範囲外(`Shape(AxisOutOfRange)`)・
1439    /// 空バッチ([`AutodiffError::InvalidArgument`])。Phase B: クロージャの `Err` の伝播、別テープの出力、
1440    /// スライス間の出力形状不一致。
1441    ///
1442    /// # 副作用
1443    ///
1444    /// Phase B で失敗すると、それまでに足されたノードがテープに残る。
1445    ///
1446    /// # 数値・適用範囲
1447    ///
1448    /// バッチなし実行との bit 一致は契約にしない(REQ-2 の統一複合判定)。本関数のクロージャ内で
1449    /// 勾配を取る合成は契約外。サンプルごとの勾配は子テープで勾配を取る [`Tape::vmap_grad`]
1450    /// (イシュー #3072・設計記録 §32)を使う。複数入力は無い。f32 の `Tape` のみ
1451    /// (`VarF64`・低精度 forward は対象外)。
1452    ///
1453    /// ```
1454    /// use fandhe_ai::{tape, Tensor};
1455    ///
1456    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1457    /// let t = tape();
1458    /// let x = t.var(&Tensor::new(vec![1.0_f32, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3])?);
1459    /// let y = t.vmap(&x, 0, |s| s.mul(s))?; // 行ごとの二乗
1460    /// let out = y.to_tensor();
1461    /// assert_eq!(out.shape(), &[2, 3]);
1462    /// assert_eq!(out.host_slice().into_owned(), [1.0, 4.0, 9.0, 16.0, 25.0, 36.0]);
1463    /// # Ok(())
1464    /// # }
1465    /// ```
1466    pub fn vmap<'t, F>(
1467        &'t self,
1468        input: &Var<'t>,
1469        in_dim: usize,
1470        f: F,
1471    ) -> Result<Var<'t>, AutodiffError>
1472    where
1473        F: FnMut(&Var<'t>) -> Result<Var<'t>, AutodiffError>,
1474    {
1475        fandhe_ai_autodiff::functional_ops::vmap(&self.0, input, in_dim, f)
1476    }
1477
1478    /// サンプルごとの勾配(`torch.func` の `vmap(grad(f))` 相当のループ版。イシュー #3072・設計記録
1479    /// `docs/autodiff-functional-transforms-design.md` §32)。内部
1480    /// `fandhe_ai_autodiff::functional_ops::vmap_grad` への薄い委譲で、公開面は追加のみ(所有者判断 D-A)。
1481    ///
1482    /// `input` を `in_dim` 軸で `B` 個のスライスに分け、サンプルごとに `f` が返す 1 要素の損失 `loss_i` の
1483    /// `∂loss_i/∂slice_i` を dim 0 に積んだ非微分の `Tensor<f32>`(shape は `[B] ++ slice_shape`、
1484    /// `in_dim` 軸を除いた形)を返す。入力 shape と一致するのは `in_dim = 0` のときだけ。
1485    /// 同一テープ・微分可能な `Var` を返す [`Tape::vmap`] とは別物で、親テープを持たないため `&self` は取らない。
1486    ///
1487    /// # 子テープ
1488    ///
1489    /// 呼び出し側が用意した**空**の `Tape` を `&mut` で渡す(空でなければ拒否)。サンプルごとに内部で
1490    /// `reset` し入口の状態へ戻すため、成功時も失敗時も戻り時は空で、続けて再利用できる。ピークメモリは
1491    /// サンプル 1 個分のグラフ。クロージャが panic したときの状態は契約外。
1492    ///
1493    /// # クロージャ
1494    ///
1495    /// [`TapeRef`] とスライスの `Var` を受け、勾配は取らず 1 要素の損失 `Var` を返す。定数は
1496    /// `t.var_no_grad` などでサンプルごとに登録し直す。HRTB のため `Var` はサンプルをまたいで保持できない。
1497    ///
1498    /// # エラー
1499    ///
1500    /// Phase A(子テープは無変更): 軸範囲外 `Shape(AxisOutOfRange)` → 空バッチ `InvalidArgument` →
1501    /// 要素数オーバーフロー `Shape(ElementCountOverflow)` → 空でない子テープ `Backward`。
1502    /// Phase B: クロージャの `Err` をそのまま伝播 → 別テープ・別世代の損失は `TapeMismatch` → 損失が
1503    /// 1 要素でなければ `InvalidArgument`(`[]`・`[1]`・`[1, 1]` は可)→ `backward`・バックエンドの `Err` を伝播。
1504    /// 追跡なしの損失、またはスライスに勾配が届かない場合は、その行が全ゼロになる。
1505    ///
1506    /// # 数値・適用範囲
1507    ///
1508    /// 明示ループ参照と REQ-2 統一複合判定(相対誤差 1e-3 未満 または 絶対誤差 1e-5 未満)で一致し、
1509    /// bit 一致は契約にしない。経路上の Op は 1 階 `backward` が対応する範囲。微分可能な版は含めず
1510    /// (§32.5)、共有パラメータについての勾配は返さない(§32.8-1)。f32 の `Tape` のみ。
1511    ///
1512    /// ```
1513    /// use fandhe_ai::{tape, Tape, Tensor};
1514    ///
1515    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1516    /// let x = Tensor::new(vec![1.0_f32, 2.0, 3.0, 4.0, 5.0, 6.0], &[2, 3])?;
1517    /// let mut child = tape();
1518    /// // 行ごとに loss_i = Σ x_i ⊙ x_i、勾配は 2 x_i
1519    /// let g = Tape::vmap_grad(&x, 0, &mut child, |_t, s| s.mul(s)?.sum(None))?;
1520    /// assert_eq!(g.shape(), &[2, 3]);
1521    /// for (a, b) in g.host_slice().iter().zip([2.0_f32, 4.0, 6.0, 8.0, 10.0, 12.0]) {
1522    ///     assert!((a - b).abs() < 1e-4);
1523    /// }
1524    /// // 子テープは空のまま戻るので続けて再利用できる
1525    /// let g1 = Tape::vmap_grad(&x, 1, &mut child, |_t, s| s.mul(s)?.sum(None))?;
1526    /// assert_eq!(g1.shape(), &[3, 2]);
1527    /// # Ok(())
1528    /// # }
1529    /// ```
1530    pub fn vmap_grad<F>(
1531        input: &Tensor<f32>,
1532        in_dim: usize,
1533        child: &mut Tape,
1534        mut f: F,
1535    ) -> Result<Tensor<f32>, AutodiffError>
1536    where
1537        F: for<'c> FnMut(TapeRef<'c>, &Var<'c>) -> Result<Var<'c>, AutodiffError>,
1538    {
1539        fandhe_ai_autodiff::functional_ops::vmap_grad(input, in_dim, &mut child.0, |t, s| {
1540            f(TapeRef::from_autodiff(t), s)
1541        })
1542    }
1543
1544    /// 非有限値(NaN/±inf)を最初に生んだノードを検出する逆伝播(イシュー #2678・
1545    /// `fandhe_ai_autodiff::anomaly::backward_detect_anomaly` への薄い委譲)。
1546    ///
1547    /// 正常時は [`Tape::backward`] と bit 一致の [`Gradients`] を返す。検出時の
1548    /// [`AutodiffError::Backward`] のメッセージはノード種別名だけを含み、テンソル値や
1549    /// 利用者定義名を含まない。検出は読み取りのみでテープを書き換えない。
1550    ///
1551    /// ```
1552    /// use fandhe_ai::{tape, Tensor};
1553    ///
1554    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1555    /// let t = tape();
1556    /// let x = t.var(&Tensor::new(vec![3.0_f32], &[1])?);
1557    /// let loss = x.mul(&x)?.sum(None)?;
1558    /// let grads = t.backward_detect_anomaly(&loss)?;
1559    /// assert_eq!(grads.get(&x)?.unwrap().host_slice().into_owned(), [6.0]);
1560    /// # Ok(())
1561    /// # }
1562    /// ```
1563    pub fn backward_detect_anomaly(&self, loss: &Var<'_>) -> Result<Gradients, AutodiffError> {
1564        fandhe_ai_autodiff::anomaly::backward_detect_anomaly(&self.0, loss)
1565    }
1566
1567    /// 解析勾配(`backward` の合成)と中心差分の数値勾配を全入力要素で突合する
1568    /// (イシュー #2847。決定記録 `docs/autodiff-jacobian-hessian-gradcheck-decision.md`
1569    /// §11・§12。内部実装は `fandhe_ai_autodiff::gradcheck::gradcheck`)。
1570    ///
1571    /// 評価ごとに空の新しいテープが要るため、`&self` を取らず `device` から
1572    /// [`tape_for`] で都度生成する関連関数である(利用者の既存テープには触れない)。
1573    /// `f` は渡されたテープ([`TapeRef`])上で入力 [`Var`] 列から**単一の出力**を記録する。
1574    /// 定数は `TapeRef::var_no_grad` で作る。
1575    ///
1576    /// - 評価回数は `1 + 2·Σn_k`(`n_k` は各入力の要素数)で、解析側は `m×n` の領域を確保する。
1577    ///   大きな形状は呼び出し側の責任で避ける。Metal では評価ごとにデバイス存在確認が走る。
1578    /// - 不一致は `Ok` の [`GradcheckReport::passed`] が `false`(`Err` ではない)。
1579    /// - 入口検査(空の `inputs` 等)はテープ生成より先に行う。テープ生成の失敗は
1580    ///   `Err(AutodiffError::Backend(_))`。
1581    /// - `relu` の 0 付近等のキンク近傍・低精度 forward は適用外(偽陽性になりうる)。
1582    ///
1583    /// ```
1584    /// use fandhe_ai::{Device, GradcheckOptions, Tape, Tensor};
1585    ///
1586    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1587    /// let options = GradcheckOptions::new(1e-3, 1e-3, 1e-2, 1e-4)?;
1588    /// let x = Tensor::new(vec![0.5_f32, -1.0, 1.5, 2.0], &[4])?;
1589    /// let report = Tape::gradcheck(Device::Cpu, |_t, xs| xs[0].mul(&xs[0]), &[x], &options)?;
1590    /// assert!(report.passed());
1591    /// // 検査要素数は 出力要素数 × 入力要素数(4 × 4)。
1592    /// assert_eq!(report.checked_elements(), 16);
1593    /// # Ok(())
1594    /// # }
1595    /// ```
1596    pub fn gradcheck<F>(
1597        device: Device,
1598        f: F,
1599        inputs: &[Tensor<f32>],
1600        options: &GradcheckOptions,
1601    ) -> Result<GradcheckReport, AutodiffError>
1602    where
1603        F: for<'a> Fn(TapeRef<'a>, &[Var<'a>]) -> Result<Var<'a>, AutodiffError>,
1604    {
1605        fandhe_ai_autodiff::gradcheck::gradcheck(
1606            || {
1607                tape_for(device)
1608                    .map(|t| t.0)
1609                    .map_err(AutodiffError::Backend)
1610            },
1611            |t, xs| f(TapeRef::from_autodiff(t), xs),
1612            inputs,
1613            options,
1614        )
1615    }
1616
1617    /// [`fandhe_ai_autodiff::Tape::custom`] への委譲入口(イシュー #2549。
1618    /// ルート #2499 の一括承認・`docs/autodiff-custom-function-decision.md`
1619    /// §16.1 (b)(c)(d))。
1620    ///
1621    /// 利用者実装の [`CustomFunction`](host の `Tensor<f32>` だけを受け渡す
1622    /// forward/backward 対)を 1 ノードとして Tape へ記録し、出力 [`Var`]
1623    /// を返す。`facade::Tape` は内部の autodiff `Tape` を隠すため、本メソッド
1624    /// が facade 経由の唯一の入口になる(`Var::custom` は設けない)。
1625    ///
1626    /// # 契約
1627    ///
1628    /// - `forward`/`backward` は常に host 実行で `BackendOps` を経由しない
1629    ///   ため、REQ-2 のバックエンド間数値一致の判定対象外
1630    /// - `backward` は `Tape::backward_accumulate` 等で複数回呼ばれうる。
1631    ///   実装は入力だけに依存する純関数・冪等にすること
1632    /// - 二階微分(`create_graph`)には非対応(fail-closed で `Err`)
1633    ///
1634    /// # エラー
1635    ///
1636    /// - 空の `inputs` → [`AutodiffError::InvalidArgument`]
1637    /// - 別の Tape の入力 → [`AutodiffError::TapeMismatch`]
1638    /// - 宣言 shape と実出力の不一致 → `Shape`/`Backward` 系
1639    /// - `requires_grad = true` の入力に `None` を返した backward →
1640    ///   `Backward`(逆伝播時)
1641    ///
1642    /// # 使用例
1643    ///
1644    /// ```
1645    /// use std::sync::Arc;
1646    /// use fandhe_ai::{AutodiffError, CustomFunction, Tensor};
1647    ///
1648    /// // y = 2x(要素ごと)。backward は upstream を 2 倍する。
1649    /// struct Double;
1650    ///
1651    /// impl CustomFunction for Double {
1652    ///     fn name(&self) -> &str {
1653    ///         "double"
1654    ///     }
1655    ///     fn output_shape(&self, shapes: &[&[usize]]) -> Result<Vec<usize>, AutodiffError> {
1656    ///         Ok(shapes[0].to_vec())
1657    ///     }
1658    ///     fn forward(&self, inputs: &[&Tensor<f32>]) -> Result<Tensor<f32>, AutodiffError> {
1659    ///         let d: Vec<f32> = inputs[0].host_slice().iter().map(|v| v * 2.0).collect();
1660    ///         Tensor::new(d, inputs[0].shape()).map_err(AutodiffError::Shape)
1661    ///     }
1662    ///     fn backward(
1663    ///         &self,
1664    ///         inputs: &[&Tensor<f32>],
1665    ///         _out_value: &Tensor<f32>,
1666    ///         upstream: &Tensor<f32>,
1667    ///         _requires_grad: &[bool],
1668    ///     ) -> Result<Vec<Option<Tensor<f32>>>, AutodiffError> {
1669    ///         let d: Vec<f32> = upstream.host_slice().iter().map(|g| g * 2.0).collect();
1670    ///         let g = Tensor::new(d, inputs[0].shape()).map_err(AutodiffError::Shape)?;
1671    ///         Ok(vec![Some(g)])
1672    ///     }
1673    /// }
1674    ///
1675    /// # fn main() -> Result<(), AutodiffError> {
1676    /// let tape = fandhe_ai::tape();
1677    /// let x = tape.var(&Tensor::new(vec![1.0, -2.0, 3.0], &[3]).unwrap());
1678    /// let y = tape.custom(Arc::new(Double), &[x])?;
1679    /// let loss = y.sum(None)?;
1680    /// let grads = tape.backward(&loss)?;
1681    /// let dx = grads.get(&x)?.expect("x は loss に寄与する");
1682    /// assert_eq!(dx.host_slice().as_ref(), &[2.0, 2.0, 2.0]);
1683    /// # Ok(())
1684    /// # }
1685    /// ```
1686    pub fn custom<'t>(
1687        &'t self,
1688        func: std::sync::Arc<dyn CustomFunction>,
1689        inputs: &[Var<'t>],
1690    ) -> Result<Var<'t>, AutodiffError> {
1691        self.0.custom(func, inputs)
1692    }
1693
1694    /// [`fandhe_ai_autodiff::Tape::register_backward_hook`] への委譲入口(イシュー #2587・
1695    /// 親 #2584。ルート #2499 のコメントによる #2584 の §14 推奨案の承認・
1696    /// `docs/autodiff-forward-backward-hooks-design.md` §14.4 P2・§18)。
1697    ///
1698    /// `var` の勾配が確定した時点で呼ばれる観察専用の backward hook(PyTorch
1699    /// `Tensor.register_hook` の観察専用版)を登録し、解除用の不透明ハンドル
1700    /// [`HookHandle`] を返す。`facade::Tape` は内部の autodiff `Tape` を隠すため、本メソッドが
1701    /// facade 経由の唯一の入口になる(`Var`・`compat::Sequential`・`TapeRef` には設けない)。
1702    ///
1703    /// # 契約
1704    ///
1705    /// - hook は `backward` 系(`backward`・`backward_accumulate`・`backward_create_graph`
1706    ///   の 1 階)の逆走査で、当該ノードの確定勾配を受けて VJP の直前に呼ばれる。同一ノードの
1707    ///   複数 hook は登録順(FIFO)、ノード間は `NodeId` 降順
1708    /// - hook は勾配を書き換えられず、登録の有無で勾配は bit 一致する。`'static` 境界により
1709    ///   `Tape`/`Var` を捕捉できない(再入防止)
1710    /// - hook が `Err` を返すとその時点で打ち切られ、同じ `Err` が `backward` の戻り値になる
1711    /// - [`Tape::reset`] で全 hook が消える(旧ハンドルの `remove_hook` は `TapeMismatch`)
1712    ///
1713    /// # エラー
1714    ///
1715    /// - 別の `Tape` の `var`: [`AutodiffError::TapeMismatch`]
1716    /// - `requires_grad == false`(`var_no_grad` 系・`detach` 後):
1717    ///   [`AutodiffError::GradientTrackingDisabled`]
1718    /// - デバイス常駐葉: [`AutodiffError::InvalidArgument`]
1719    ///
1720    /// # 使用例
1721    ///
1722    /// ```
1723    /// use std::sync::{Arc, Mutex};
1724    /// use fandhe_ai::Tensor;
1725    ///
1726    /// # fn main() -> Result<(), fandhe_ai::AutodiffError> {
1727    /// let tape = fandhe_ai::tape();
1728    /// let x = tape.var(&Tensor::new(vec![1.0, 2.0], &[2]).unwrap());
1729    /// let loss = x.mul(&x)?.sum(None)?;
1730    /// let seen = Arc::new(Mutex::new(Vec::new()));
1731    /// let sink = Arc::clone(&seen);
1732    /// let handle = tape.register_backward_hook(&x, move |g: &Tensor<f32>| {
1733    ///     sink.lock().unwrap().push(g.host_slice().to_vec());
1734    ///     Ok(())
1735    /// })?;
1736    /// let grads = tape.backward(&loss)?;
1737    /// assert_eq!(seen.lock().unwrap().len(), 1);
1738    /// let dx = grads.get(&x)?.expect("x は loss に寄与する");
1739    /// assert_eq!(dx.host_slice().as_ref(), &seen.lock().unwrap()[0][..]);
1740    /// tape.remove_hook(handle)?;
1741    /// # Ok(())
1742    /// # }
1743    /// ```
1744    pub fn register_backward_hook<F>(
1745        &self,
1746        var: &Var<'_>,
1747        hook: F,
1748    ) -> Result<HookHandle, AutodiffError>
1749    where
1750        F: Fn(&Tensor<f32>) -> Result<(), AutodiffError> + Send + Sync + 'static,
1751    {
1752        self.0.register_backward_hook(var, hook)
1753    }
1754
1755    /// [`fandhe_ai_autodiff::Tape::remove_hook`] への委譲入口(イシュー #2587・設計記録 §14.4 P2)。
1756    ///
1757    /// [`Self::register_backward_hook`] が返したハンドルの hook を解除する。ハンドルは値で
1758    /// 消費されるため二重解除は型上起きない。
1759    ///
1760    /// # エラー
1761    ///
1762    /// 別の `Tape` のハンドル、または [`Tape::reset`] より前に発行されたハンドルは
1763    /// [`AutodiffError::TapeMismatch`](登録簿は変更しない)。
1764    pub fn remove_hook(&self, handle: HookHandle) -> Result<(), AutodiffError> {
1765        self.0.remove_hook(handle)
1766    }
1767
1768    /// [`fandhe_ai_autodiff::nn::Rnn::forward_seq`] への委譲入口
1769    /// (イシュー #1955)。
1770    ///
1771    /// `Rnn::forward_seq` は生の `fandhe_ai_autodiff::Tape` を第 1
1772    /// 引数に取るため、`facade::Tape`(本型。内部フィールド `0` は
1773    /// `pub(crate)`)の利用者からは直接呼べない。本メソッドは
1774    /// `&self.0` を渡すだけの薄い委譲であり、`BackendOps` を利用者向け
1775    /// 公開面へ露出しない(`step_device_param_store` と同じ理由。
1776    /// `crate::lib.rs` モジュール doc「公開面の設計」・REQ-12)。
1777    /// `h0` 省略時はゼロ初期化される(`Rnn::forward_seq` の契約を
1778    /// 参照)。
1779    pub fn rnn_forward_seq<'t>(
1780        &'t self,
1781        rnn: &nn::rnn::Rnn,
1782        x: &Tensor<f32>,
1783        h0: Option<&Var<'t>>,
1784    ) -> Result<nn::rnn::RnnSeqOutput<'t, nn::rnn::RnnCellVars<'t>>, AutodiffError> {
1785        rnn.forward_seq(&self.0, x, h0)
1786    }
1787
1788    /// [`fandhe_ai_autodiff::nn::Lstm::forward_seq`] への委譲入口
1789    /// (イシュー #1955)。上記 [`Self::rnn_forward_seq`] と同じ理由の
1790    /// 薄い委譲。`h0`/`c0` 省略時はいずれもゼロ初期化される
1791    /// (`Lstm::forward_seq` の契約を参照)。
1792    pub fn lstm_forward_seq<'t>(
1793        &'t self,
1794        lstm: &nn::rnn::Lstm,
1795        x: &Tensor<f32>,
1796        h0: Option<&Var<'t>>,
1797        c0: Option<&Var<'t>>,
1798    ) -> Result<nn::rnn::LstmSeqOutput<'t>, AutodiffError> {
1799        lstm.forward_seq(&self.0, x, h0, c0)
1800    }
1801
1802    /// [`fandhe_ai_autodiff::nn::Gru::forward_seq`] への委譲入口
1803    /// (イシュー #1955)。上記 [`Self::rnn_forward_seq`] と同じ理由の
1804    /// 薄い委譲。`h0` 省略時はゼロ初期化される(`Gru::forward_seq`
1805    /// の契約を参照)。
1806    pub fn gru_forward_seq<'t>(
1807        &'t self,
1808        gru: &nn::rnn::Gru,
1809        x: &Tensor<f32>,
1810        h0: Option<&Var<'t>>,
1811    ) -> Result<nn::rnn::RnnSeqOutput<'t, nn::rnn::GruCellVars<'t>>, AutodiffError> {
1812        gru.forward_seq(&self.0, x, h0)
1813    }
1814
1815    /// 多層・双方向・層間 dropout 付き RNN の `Tape` 委譲メソッド
1816    /// (イシュー #2535・`docs/autodiff-rnn-stacked-config-decision.md`
1817    /// §9・`docs/compat-api-scope.md` §5 経路 2)。[`Self::rnn_forward_seq`]
1818    /// と同じ理由(生の `fandhe_ai_autodiff::Tape` を取り出せない)の
1819    /// 薄い委譲で、`&self.0` を渡すだけ。
1820    ///
1821    /// `h0` は `Some` の場合、長さ `num_layers * num_directions`
1822    /// (index = `layer * num_directions + direction`)でなければならない。
1823    /// 双方向時の各 step 出力は `[B, 2H]`(forward と reverse の連結)。
1824    ///
1825    /// **既知の制限**: `StackedRnn::new` は training=true で構築され、
1826    /// `Module::set_training` は facade から到達できないため、`dropout > 0`
1827    /// の場合は常に層間 dropout を適用してグローバル RNG
1828    /// ([`manual_seed`] で再現可能。消費順は layer 昇順 → t 昇順)を
1829    /// 消費する。推論用途では `dropout = 0.0` で構築する。
1830    pub fn stacked_rnn_forward_seq<'t>(
1831        &'t self,
1832        rnn: &nn::rnn::StackedRnn,
1833        x: &Tensor<f32>,
1834        h0: Option<&[Var<'t>]>,
1835    ) -> Result<nn::rnn::StackedRnnSeqOutput<'t, nn::rnn::RnnCellVars<'t>>, AutodiffError> {
1836        rnn.forward_seq(&self.0, x, h0)
1837    }
1838
1839    /// [`Self::stacked_rnn_forward_seq`] の LSTM 版(イシュー #2535)。
1840    /// `h0`/`c0` は `Some` の場合ともに長さ `num_layers * num_directions`。
1841    /// eval モード不可・dropout の RNG 消費は同メソッドの doc を参照。
1842    pub fn stacked_lstm_forward_seq<'t>(
1843        &'t self,
1844        lstm: &nn::rnn::StackedLstm,
1845        x: &Tensor<f32>,
1846        h0: Option<&[Var<'t>]>,
1847        c0: Option<&[Var<'t>]>,
1848    ) -> Result<nn::rnn::StackedLstmSeqOutput<'t>, AutodiffError> {
1849        lstm.forward_seq(&self.0, x, h0, c0)
1850    }
1851
1852    /// [`Self::stacked_rnn_forward_seq`] の GRU 版(イシュー #2535)。
1853    pub fn stacked_gru_forward_seq<'t>(
1854        &'t self,
1855        gru: &nn::rnn::StackedGru,
1856        x: &Tensor<f32>,
1857        h0: Option<&[Var<'t>]>,
1858    ) -> Result<nn::rnn::StackedRnnSeqOutput<'t, nn::rnn::GruCellVars<'t>>, AutodiffError> {
1859        gru.forward_seq(&self.0, x, h0)
1860    }
1861
1862    /// KV キャッシュ付き self-attention の forward(イシュー #2579。
1863    /// `docs/kv-cache-design.md` §11.4 P3)。`StatefulAttention::forward` へ
1864    /// `&self.0` を渡すだけの薄い委譲で、`rnn_forward_seq` と同じ理由
1865    /// (生の autodiff `Tape` を取り出せない。REQ-12)で `Tape` に置く。
1866    ///
1867    /// mask 規則: (a) キャッシュ空かつ `L_new > 1` は causal、(b) `L_new == 1`
1868    /// は全キャッシュを参照、(c) キャッシュ非空かつ `L_new > 1` は offset 付き
1869    /// causal(`docs/kv-cache-design.md`)。更新は原子的で、`Err` のときキャッシュは
1870    /// 呼び出し前から変化しない。`x_new` は `[B, L_new, E]`。
1871    ///
1872    /// # Errors
1873    ///
1874    /// rank・`E`・`B` の不一致、別 `Tape` の `Var`(`TapeMismatch`)等で
1875    /// `AutodiffError` を返す。
1876    pub fn stateful_attention_forward<'t>(
1877        &'t self,
1878        sa: &mut nn::kv_cache::StatefulAttention,
1879        x_new: &Var<'t>,
1880    ) -> Result<Var<'t>, AutodiffError> {
1881        sa.forward(&self.0, x_new)
1882    }
1883
1884    /// [`Self::stateful_attention_forward`] の外部キャッシュ版(イシュー
1885    /// #3096・親 #3094。`docs/facade-speculative-decoding-batching-design.md`
1886    /// §19.4・§19.6)。`sa` の内部キャッシュは変えず、渡された `cache` を進める。
1887    ///
1888    /// `AutoregressiveModel::forward_step` の中で `caches[i]` を進める入口で、
1889    /// 要求ごとの `Vec<KvCache>` を持つ `generate_speculative`・`BatchScheduler`
1890    /// と組み合わせられる。facade だけで KV 付きモデルを組むときは
1891    /// `RefCell<StatefulAttention>` 形より本入口を推奨する。`Tape` に置く理由
1892    /// (REQ-12。生の autodiff `Tape` を取り出せない)・mask 規則・原子性
1893    /// (`Err` のとき `cache` は不変)は `stateful_attention_forward` と同じ。
1894    ///
1895    /// # Errors
1896    ///
1897    /// rank・`E`・`B` の不一致、別 `Tape` の `Var`(`TapeMismatch`)等で
1898    /// `AutodiffError` を返す。
1899    pub fn stateful_attention_forward_with_cache<'t>(
1900        &'t self,
1901        sa: &nn::kv_cache::StatefulAttention,
1902        x_new: &Var<'t>,
1903        cache: &mut nn::kv_cache::KvCache,
1904    ) -> Result<Var<'t>, AutodiffError> {
1905        sa.forward_with_external_cache(&self.0, x_new, cache)
1906    }
1907
1908    /// デバイス常駐ページ化 KV キャッシュ(K-3)をこの `Tape` のバックエンドへ構築する
1909    /// (イシュー #3112・親 #3108。`docs/device-resident-kv-paged-attention-design.md` §6・§13)。
1910    ///
1911    /// `PagedKvCache::new` は生の autodiff `Tape` を取り facade から呼べない(REQ-12)ため、
1912    /// `&self.0` を渡すだけの薄い委譲を `Tape` に置く。プールは `config` の
1913    /// `max_blocks · block_size · embed_dim` ぶん K/V 各 1 本を確保する。
1914    ///
1915    /// # Errors
1916    ///
1917    /// バックエンドが `MemoryOps` を持たない場合は `Unsupported`、`max_blocks · block_size` が
1918    /// `u32::MAX` 超・確保失敗で `AutodiffError` を返す。
1919    pub fn new_paged_kv_cache(
1920        &self,
1921        config: nn::kv_cache::PagedKvCacheConfig,
1922    ) -> Result<nn::kv_cache::PagedKvCache, AutodiffError> {
1923        nn::kv_cache::PagedKvCache::new(&self.0, config)
1924    }
1925
1926    /// ページ化 KV キャッシュを使う self-attention の入口(K-3。イシュー #3112)。
1927    ///
1928    /// `x_new`(`[B, L_new, E]`)を q/k/v へ射影して `cache` へ追記し、キャッシュ全体に対する
1929    /// attention と `out_proj` を適用した `[B, L_new, E]` を返す。**推論専用**(入出力は
1930    /// 非追跡の `Tensor`。勾配が要る用途は K-1 の `stateful_attention_forward*`)。`sa` の
1931    /// 内部キャッシュは変えない。`Err` のとき `cache` の論理状態は不変(poison は戻らない)。
1932    /// バックエンドが `Unsupported` でも K-1 へ暗黙フォールバックしない。`Tape` に置く理由は
1933    /// `stateful_attention_forward` と同じ(REQ-12)。
1934    ///
1935    /// # Errors
1936    ///
1937    /// 非既定 config・rank/`E`/`B` の不一致・ブロック枯渇・バックエンド失敗で
1938    /// `AutodiffError` を返す。
1939    pub fn paged_attention_forward(
1940        &self,
1941        sa: &nn::kv_cache::StatefulAttention,
1942        x_new: &Tensor<f32>,
1943        cache: &mut nn::kv_cache::PagedKvCache,
1944    ) -> Result<Tensor<f32>, AutodiffError> {
1945        sa.forward_paged(&self.0, x_new, cache)
1946    }
1947
1948    /// この `Tape` が結線されているバックエンドの `f64` 演算本体
1949    /// ([`TypedOps<f64>`])への capability accessor(イシュー #1939・
1950    /// `docs/compat-api-scope.md` §5 経路 2 承認・`docs/backend-dtype-
1951    /// dispatch-design.md`)。
1952    ///
1953    /// `Tensor<f64>` を直接対象とする 8 演算(`gemm`/`add`/`mul`/
1954    /// `relu`/`exp`/`tanh`/`sum`/`max`)限定の capability であり、
1955    /// `Var`/autograd を経由しない(呼び出しは tape に記録されず
1956    /// 勾配は付かない)。バックエンドが対応しない場合は `None`
1957    /// (fail-closed。例: Metal は f64 型自体が既定非対応)。`Some` が
1958    /// 返っても個々の演算が [`BackendError::Unsupported`] を返す場合が
1959    /// ある(例: CUDA の `TypedOps<f64>` は 8 演算すべて
1960    /// `Unsupported`)——`Some`/`None` は型としての対応可否のみを表す。
1961    ///
1962    /// REQ-12: 返すのは `TypedOps<f64>` の不変借用のみで、`BackendOps`
1963    /// 自体の注入経路は増えない(`fandhe_ai_autodiff::Tape::ops()` は
1964    /// 引き続き `pub(crate)`)。
1965    pub fn typed_ops_f64(&self) -> Option<&dyn TypedOps<f64>> {
1966        self.0.typed_ops_f64()
1967    }
1968
1969    /// `half::f16` 演算本体([`TypedOps<f16>`])への capability
1970    /// accessor。契約は [`Self::typed_ops_f64`] と同じ(イシュー
1971    /// #1939)。`half::f16` を名指しするには利用者が `half` クレート
1972    /// (本 workspace と同一バージョン)へ直接依存する(facade は
1973    /// `half` を再エクスポートしない)。
1974    pub fn typed_ops_f16(&self) -> Option<&dyn TypedOps<f16>> {
1975        self.0.typed_ops_f16()
1976    }
1977
1978    /// `half::bf16` 演算本体([`TypedOps<bf16>`])への capability
1979    /// accessor。契約は [`Self::typed_ops_f64`] と同じ(イシュー
1980    /// #1939)。
1981    pub fn typed_ops_bf16(&self) -> Option<&dyn TypedOps<bf16>> {
1982        self.0.typed_ops_bf16()
1983    }
1984}
1985
1986/// autodiff コンテナ内で facade 独自層へ渡す、`var` 系メソッドのみの借用ハンドル。
1987///
1988/// 役割: `fandhe_ai::nn::Module::forward`(#2395)の第 1 引数、および autodiff
1989/// 側コンテナ(`compat::Sequential` 内部)から facade 独自層を呼ぶアダプタ(#2397)
1990/// が `&fandhe_ai_autodiff::Tape` から構築する橋渡しである。生の
1991/// `fandhe_ai_autodiff::Tape` から facade の [`Tape`](newtype)を作る安全な手段は
1992/// なく、`#[repr(transparent)]` と `unsafe` の参照キャストは不採用(#2338
1993/// 2026-09-29 承認事項 4「案 1: 借用ハンドル型・`unsafe` なし」)。
1994///
1995/// REQ-12: 生の `Tape`/`BackendOps` を露出しないため、公開メソッドは
1996/// [`Self::var`]・[`Self::var_from`]・[`Self::var_no_grad`] の 3 件のみで、
1997/// `backward` 等は委譲しない。フィールドは `pub(crate)`。crate 内の構築は
1998/// `from_autodiff`、crate 外の入口は `From<&Tape>` のみ。
1999/// `tests/api_surface.rs` がこの面を機械的に固定する。
2000#[derive(Clone, Copy)]
2001pub struct TapeRef<'t>(pub(crate) &'t fandhe_ai_autodiff::Tape);
2002
2003impl<'t> TapeRef<'t> {
2004    /// `&fandhe_ai_autodiff::Tape` から借用ハンドルを作る crate 内専用の構築経路
2005    /// (#2397 のアダプタが使う。`From<&Tape>` もここへ集約する)。
2006    pub(crate) fn from_autodiff(tape: &'t fandhe_ai_autodiff::Tape) -> Self {
2007        Self(tape)
2008    }
2009
2010    /// [`Tape::var`] と同じ(葉ノード登録)。戻り値の寿命は借用元テープ `'t` に結び付く。
2011    pub fn var(&self, tensor: &Tensor<f32>) -> Var<'t> {
2012        self.0.var(tensor)
2013    }
2014
2015    /// [`Tape::var_from`] と同じ(dtype 変換つきの葉ノード登録)。
2016    pub fn var_from<T: CastElement>(&self, tensor: &Tensor<T>) -> Result<Var<'t>, AutodiffError> {
2017        self.0.var_from(tensor)
2018    }
2019
2020    /// [`Tape::var_no_grad`] と同じ(`requires_grad == false` の葉ノード登録)。
2021    pub fn var_no_grad(&self, tensor: &Tensor<f32>) -> Var<'t> {
2022        self.0.var_no_grad(tensor)
2023    }
2024}
2025
2026impl std::fmt::Debug for TapeRef<'_> {
2027    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2028        // facade `Tape` の `Debug` と同じ方針(内部 `Tape` の表現に依存しない)。
2029        f.debug_struct("TapeRef").finish_non_exhaustive()
2030    }
2031}
2032
2033impl<'t> From<&'t Tape> for TapeRef<'t> {
2034    fn from(tape: &'t Tape) -> Self {
2035        Self::from_autodiff(&tape.0)
2036    }
2037}
2038// ---------------------------------------------------------------------------
2039// f64 専用の独立自動微分グラフ(イシュー #2599・親 #2499/#2542)
2040// ---------------------------------------------------------------------------
2041//
2042// `fandhe_ai_autodiff::f64_autograd` の `TapeF64`/`VarF64`/`GradientsF64` を、
2043// `docs/autodiff-var-dtype-multiplexing-design.md` §4.1・§10.1 の推奨案 D-2
2044// (3 型とも facade newtype・`lib.rs` 直下宣言・1 式委譲)で公開する。承認根拠:
2045// https://github.com/Fandhe-AI/fandhe-ai/issues/2499#issuecomment-6033824965
2046// (2026-10-07・#2597 の行)。承認範囲は同記録の形に限る。内部型は完全修飾パスで
2047// のみ参照し、`pub use` での再エクスポートや trait impl は設けない
2048// (`tests/api_surface.rs` の `f64_autograd_*` 正ガードが機械的に固定する)。
2049
2050/// f64 専用の独立自動微分グラフのテープ(f32 の [`Tape`] とは別の添字空間)。
2051///
2052/// 役割: f64 の葉ノード登録([`Self::var`]/[`Self::var_no_grad`])と逆伝播
2053/// ([`Self::backward`])を提供する。構築は借用元の facade [`Tape`] からのみ行い
2054/// ([`Self::new`])、生の `fandhe_ai_autodiff::Tape`/`BackendOps` は受け取らない
2055/// (REQ-12)。内部実装 `fandhe_ai_autodiff::f64_autograd::TapeF64` への 1 式委譲。
2056///
2057/// 制約: f32 グラフとは独立であり、f32 の [`Var`] から勾配は流れない。f32 側の値は
2058/// `Var::cast::<f64>()` が返す勾配の切れた `Tensor<f64>` を [`Self::var`] へ渡す
2059/// 経路のみで取り込む。`matmul` は rank 2 限定、縮約は `dim: Option<usize>` のみ。
2060/// 全軸 `sum` の CPU ネイティブとホストの bit 一致は 4096 要素以下。Metal は
2061/// 常にホスト計算、`div`/`pow` は常にホスト計算。CUDA/Metal 実機 parity は未実測
2062/// (`docs/perf/logs/f64-autograd-facade-2599/README.md` に申し送り)。
2063/// `backward` の非スカラー loss は全要素 1 のシードで逆伝播する。
2064///
2065/// ```
2066/// use fandhe_ai::{TapeF64, Tensor};
2067///
2068/// let tape = fandhe_ai::tape();
2069/// let g = TapeF64::new(&tape);
2070/// let x = g.var(&Tensor::<f64>::new(vec![3.0], &[1]).unwrap());
2071/// let y = x.mul(&x).unwrap(); // y = x^2
2072/// let grads = g.backward(&y.sum(None).unwrap()).unwrap();
2073/// assert_eq!(grads.get(&x).unwrap().unwrap().as_slice().unwrap(), &[6.0]);
2074/// ```
2075pub struct TapeF64<'t>(pub(crate) fandhe_ai_autodiff::f64_autograd::TapeF64<'t>);
2076
2077impl<'t> TapeF64<'t> {
2078    /// facade の [`Tape`] に結線した f64 グラフを作る(バックエンドは `tape` のもの)。
2079    pub fn new(tape: &'t Tape) -> Self {
2080        Self(fandhe_ai_autodiff::f64_autograd::TapeF64::new(&tape.0))
2081    }
2082
2083    /// 勾配追跡ありの f64 葉ノードを登録する。
2084    pub fn var(&self, value: &Tensor<f64>) -> VarF64<'_, 't> {
2085        VarF64(self.0.var(value))
2086    }
2087
2088    /// 勾配追跡なしの f64 葉ノードを登録する(`GradientsF64::get` は
2089    /// [`AutodiffError::GradientTrackingDisabled`])。
2090    pub fn var_no_grad(&self, value: &Tensor<f64>) -> VarF64<'_, 't> {
2091        VarF64(self.0.var_no_grad(value))
2092    }
2093
2094    /// `loss` から逆伝播する。別テープの変数は [`AutodiffError::TapeMismatch`]、
2095    /// 勾配追跡対象を持たない loss は [`AutodiffError::Backward`]。
2096    pub fn backward(&self, loss: &VarF64<'_, 't>) -> Result<GradientsF64, AutodiffError> {
2097        self.0.backward(&loss.0).map(GradientsF64)
2098    }
2099}
2100
2101/// [`TapeF64`] 上の f64 変数(`Copy` なハンドル)。
2102///
2103/// 役割: f64 の演算(`add`/`mul`/`div`/`pow`/`matmul`/`sum`/`mean`/`max`)を
2104/// 内部 `VarF64` へ 1 式委譲する。意味論・エラー契約は内部実装と同一。
2105#[derive(Clone, Copy)]
2106pub struct VarF64<'g, 't>(pub(crate) fandhe_ai_autodiff::f64_autograd::VarF64<'g, 't>);
2107
2108impl<'g, 't> VarF64<'g, 't> {
2109    /// 現在値の複製を返す。
2110    pub fn value(&self) -> Tensor<f64> {
2111        self.0.value()
2112    }
2113
2114    /// 形状を返す。
2115    pub fn shape(&self) -> Vec<usize> {
2116        self.0.shape()
2117    }
2118
2119    /// 要素ごとの加算(ブロードキャストあり)。
2120    pub fn add(&self, other: &Self) -> Result<Self, AutodiffError> {
2121        self.0.add(&other.0).map(VarF64)
2122    }
2123
2124    /// 要素ごとの乗算(ブロードキャストあり)。
2125    pub fn mul(&self, other: &Self) -> Result<Self, AutodiffError> {
2126        self.0.mul(&other.0).map(VarF64)
2127    }
2128
2129    /// 要素ごとの除算(常にホスト計算)。
2130    pub fn div(&self, other: &Self) -> Result<Self, AutodiffError> {
2131        self.0.div(&other.0).map(VarF64)
2132    }
2133
2134    /// 要素ごとの冪乗(常にホスト計算)。
2135    pub fn pow(&self, other: &Self) -> Result<Self, AutodiffError> {
2136        self.0.pow(&other.0).map(VarF64)
2137    }
2138
2139    /// 行列積(rank 2 限定)。
2140    pub fn matmul(&self, other: &Self) -> Result<Self, AutodiffError> {
2141        self.0.matmul(&other.0).map(VarF64)
2142    }
2143
2144    /// 総和(`dim: None` で全軸、`Some(d)` で 1 軸。`keepdim` なし)。
2145    pub fn sum(&self, dim: Option<usize>) -> Result<Self, AutodiffError> {
2146        self.0.sum(dim).map(VarF64)
2147    }
2148
2149    /// 平均(`sum` の後に 1 回だけ除算)。
2150    pub fn mean(&self, dim: Option<usize>) -> Result<Self, AutodiffError> {
2151        self.0.mean(dim).map(VarF64)
2152    }
2153
2154    /// 最大値(`dim: None` で全軸、`Some(d)` で 1 軸)。
2155    pub fn max(&self, dim: Option<usize>) -> Result<Self, AutodiffError> {
2156        self.0.max(dim).map(VarF64)
2157    }
2158}
2159
2160/// [`TapeF64::backward`] の結果(葉ごとの f64 勾配)。
2161pub struct GradientsF64(pub(crate) fandhe_ai_autodiff::f64_autograd::GradientsF64);
2162
2163impl GradientsF64 {
2164    /// `var` の勾配を返す。loss から未到達なら `Ok(None)`、別テープなら
2165    /// [`AutodiffError::TapeMismatch`]、`var_no_grad` の葉なら
2166    /// [`AutodiffError::GradientTrackingDisabled`]。
2167    pub fn get(&self, var: &VarF64<'_, '_>) -> Result<Option<&Tensor<f64>>, AutodiffError> {
2168        self.0.get(&var.0)
2169    }
2170}
2171
2172/// 既定バックエンド(CPU・TASK-2.5 ユーザー承認済み。
2173/// `docs/public-api-design.md:429`)で [`Tape`] を構築する。
2174///
2175/// CPU は常に利用可能であるため非 fallible。`CpuBackendOps::new()`
2176/// (`run_fused` を `run_fused_elementwise` へオーバーライド済み=融合
2177/// 有効。`crates/backend-cpu/src/ops.rs`)を結線する唯一の入口。
2178pub fn tape() -> Tape {
2179    Tape(fandhe_ai_autodiff::Tape::new_with_ops(Box::new(
2180        fandhe_ai_backend_cpu::CpuBackendOps::new(),
2181    )))
2182}
2183
2184/// 指定した [`Device`] へ明示的に結線した [`Tape`] を構築する。
2185///
2186/// 存在しないデバイス・範囲外 ordinal・driver 不在は [`BackendError`]
2187/// を返す(fail-fast。本番経路で `panic!`/`unwrap()` しない。
2188/// `.claude/rules/coding-rust.md`)。構築規則はモジュール冒頭コメント
2189/// 参照。
2190pub fn tape_for(device: Device) -> Result<Tape, BackendError> {
2191    let ops = resolve_ops(device)?;
2192    Ok(Tape(fandhe_ai_autodiff::Tape::new_with_ops(ops)))
2193}
2194
2195/// 実行時に利用可能な [`Device`] を列挙する(`docs/public-api-design.md`
2196/// §4.1 `Device::available()` の集約入口。イシュー #1614。TASK-1.9a
2197/// (#44。`tensor-core::device` モジュール doc)が「集約入口をどの層で
2198/// 結線するかは後続イシューへ引き継ぐ」としていた未決事項をここで解消
2199/// する)。
2200///
2201/// `tensor-core::device::enumerate_all`(`&[&dyn DeviceProvider]` を
2202/// 横断して列挙する下位ヘルパー。`tensor-core` は 3 バックエンドを
2203/// 直接参照できないため依存逆転構成を取る)へ、composition root
2204/// (本クレート)が 3 バックエンドの `DeviceProvider` を束ねて渡す
2205/// 唯一の入口。返すのは [`Device`] 識別子のみで、`DeviceProvider`/
2206/// `DeviceInfo`(デバイス名・メモリ容量等)は再エクスポートしない
2207/// (REQ-12 と同じ「利用者向け公開面は `Device` 識別子のみ」の方針。
2208/// `tests/api_surface.rs` が機械的に固定する)。
2209///
2210/// **順序契約**: `Device::Cpu`(常に含まれる)→ `Device::Cuda(0..n)`
2211/// (ordinal 昇順。CUDA driver 不在なら 0 件)→ `Device::Metal`
2212/// (`cfg(target_os = "macos")` 限定。デバイス検出 0 件なら含まれない)
2213/// の順で、同一プロセス内の複数回呼び出しでも決定的。ROCm は未公開
2214/// (`docs/backend-rocm-device-exposure-decision.md`。所有者判断待ち)。
2215///
2216/// ```
2217/// // ROCm 非搭載の CI でも通る。`Device` に ROCm variant が無いことを
2218/// // 網羅的 `match` で示し、`Cpu` が必ず含まれることを確認する。
2219/// let devices = fandhe_ai::available_devices();
2220/// for d in &devices {
2221///     match d {
2222///         fandhe_ai::Device::Cpu => {}
2223///         fandhe_ai::Device::Cuda(_) => {}
2224///         #[cfg(target_os = "macos")]
2225///         fandhe_ai::Device::Metal => {}
2226///     }
2227/// }
2228/// assert!(devices.contains(&fandhe_ai::Device::Cpu));
2229/// ```
2230///
2231/// **副作用**: `CudaDeviceProvider::enumerate` は検出した CUDA
2232/// ordinal ごとに `context_cache` のコンテキストを初期化する
2233/// (`crates/backend-cuda/src/device.rs`。2 回目以降はキャッシュ
2234/// ヒットで軽量)。これは後で [`tape_for`] が払うはずのコストを
2235/// 前倒しするだけであり、追加コストではない。
2236///
2237/// **一貫性契約**: 本関数が返した各 `Device` に対して [`tape_for`]
2238/// を呼べば `Ok` になることを意図する(ただし列挙と `tape_for` の
2239/// 呼び出しの間でデバイス状態が変化する TOCTOU は契約外——ドライバの
2240/// 抜き差し等の外部要因まではカバーしない)。
2241///
2242/// **fail-safe**: 個々のバックエンドの列挙が失敗しても `panic!`/
2243/// `unwrap()` せず、その分を除いた結果を返す(`enumerate_all` の
2244/// fail-safe 方針をそのまま引き継ぐ)。
2245pub fn available_devices() -> Vec<Device> {
2246    let cpu = fandhe_ai_backend_cpu::CpuDeviceProvider::new();
2247    let cuda = fandhe_ai_backend_cuda::CudaDeviceProvider::new();
2248    #[cfg(target_os = "macos")]
2249    let metal = fandhe_ai_backend_metal::MetalDeviceProvider::new();
2250
2251    // macOS 以外では 2 要素で固定(`providers` を `mut` にすると
2252    // 非 macOS ビルドで `push` が到達不能になり `unused_mut` 警告
2253    // (`-D warnings` で fail)になるため、cfg ごとに構築を分ける)。
2254    #[cfg(target_os = "macos")]
2255    let providers: Vec<&dyn DeviceProvider> = vec![&cpu, &cuda, &metal];
2256    #[cfg(not(target_os = "macos"))]
2257    let providers: Vec<&dyn DeviceProvider> = vec![&cpu, &cuda];
2258
2259    fandhe_ai_tensor_core::enumerate_all(&providers)
2260        .into_iter()
2261        .map(|info| info.device)
2262        .collect()
2263}
2264
2265/// PyTorch `torch.manual_seed` 相当。プロセス全体で共有されるグローバル
2266/// 決定的 RNG([`randn`]/[`rand`]/[`randint`] が消費する。#1602 本文の
2267/// 設計方針どおりホスト生成のみで `BackendOps` は経由しない)の状態を
2268/// `seed` からやり直す(イシュー #1724)。
2269///
2270/// `fandhe_ai_autodiff::manual_seed`(実体は `fandhe_ai_tensor_core::rng`)
2271/// への薄い委譲(composition root。`docs/compat-api-scope.md` §0 の確定
2272/// 公開面)。既存の個別シード API(`nn::Linear::new(.., seed)` 等)とは
2273/// 独立した別機構であり、本関数を呼んでもそれらの挙動には一切影響しない
2274/// (設計判断・スレッド安全性の範囲は `docs/rng-global-contract-design.md`)。
2275pub fn manual_seed(seed: u64) {
2276    fandhe_ai_autodiff::manual_seed(seed);
2277}
2278
2279/// PyTorch `torch.use_deterministic_algorithms` 相当の決定論モードを
2280/// プロセス全体で切り替える(イシュー #2507。実装は #2157)。既定は
2281/// `false`(opt-in)。
2282///
2283/// `fandhe_ai_autodiff::determinism::set_deterministic` への薄い委譲
2284/// (composition root。`set_cuda_gemm_precision` と同型の crate ルート
2285/// 自由関数)。現時点では状態を記録するだけの no-op 契約で、ON/OFF で
2286/// forward/backward の結果は bit 一致する。保証範囲は CPU(同一
2287/// バイナリ・同一マシン)に限り、CUDA/Metal の `Tape` には等しく no-op
2288/// で決定性は未検証である(並行スレッドからの RNG 消費順も対象外)。
2289/// 設計判断・契約は `docs/autodiff-determinism-mode-design.md` §3 を参照。
2290///
2291/// ```
2292/// fandhe_ai::set_deterministic(true);
2293/// assert!(fandhe_ai::is_deterministic());
2294/// fandhe_ai::set_deterministic(false);
2295/// assert!(!fandhe_ai::is_deterministic());
2296/// ```
2297pub fn set_deterministic(enabled: bool) {
2298    fandhe_ai_autodiff::determinism::set_deterministic(enabled);
2299}
2300
2301/// [`set_deterministic`] で設定した決定論モードの現在値を返す(既定
2302/// `false`。イシュー #2507)。`fandhe_ai_autodiff::determinism::
2303/// is_deterministic` への薄い委譲で、保証範囲・no-op 契約は
2304/// [`set_deterministic`] を参照。
2305pub fn is_deterministic() -> bool {
2306    fandhe_ai_autodiff::determinism::is_deterministic()
2307}
2308
2309/// 標準正規分布 `N(0, 1)` に従う乱数テンソルを生成する(PyTorch
2310/// `torch.randn` 相当。イシュー #1725)。[`manual_seed`] が設定した
2311/// プロセスグローバル決定的 RNG をホスト側だけで消費し(`BackendOps` を
2312/// 経由しない。#1602 本文の設計方針)、返る [`Tensor`] は [`Tape::var`]
2313/// で任意のデバイスへアップロードできる。
2314///
2315/// `fandhe_ai_autodiff::randn`(実体は `fandhe_ai_tensor_core::rng::randn`)
2316/// への薄い委譲(composition root)。決定性の範囲(同一プロセス・同一
2317/// プラットフォーム限定)・アルゴリズムは `docs/rng-global-contract-design.md`
2318/// を参照。
2319pub fn randn(shape: &[usize]) -> Result<Tensor<f32>, ShapeError> {
2320    fandhe_ai_autodiff::randn(shape)
2321}
2322
2323/// `[0, 1)` の一様分布に従う乱数テンソルを生成する(PyTorch `torch.rand`
2324/// 相当。イシュー #1725)。設計・到達経路は [`randn`] と同じ。整数演算
2325/// のみで構成されるためプラットフォーム横断で bit 同一の決定性を持つ
2326/// (`fandhe_ai_tensor_core::rng` モジュール doc 参照)。
2327pub fn rand(shape: &[usize]) -> Result<Tensor<f32>, ShapeError> {
2328    fandhe_ai_autodiff::rand(shape)
2329}
2330
2331/// `[low, high)` の一様分布に従う整数乱数テンソルを生成する(PyTorch
2332/// `torch.randint` 相当。イシュー #1725)。dtype は `i32`
2333/// (本リポの index/targets 型契約に合わせた意図的な差異。
2334/// `docs/rng-global-contract-design.md`)。`low >= high` は
2335/// [`RngError::InvalidRange`] を返す。
2336pub fn randint(low: i32, high: i32, shape: &[usize]) -> Result<Tensor<i32>, RngError> {
2337    fandhe_ai_autodiff::randint(low, high, shape)
2338}
2339
2340/// 確率テンソル `probs` の各要素を成功確率とするベルヌーイ試行を行い、
2341/// 0.0/1.0 の `f32` テンソルを返す(PyTorch `torch.bernoulli` 相当。
2342/// イシュー #2593)。`fandhe_ai_autodiff::bernoulli`(実体は
2343/// `fandhe_ai_tensor_core::rng::bernoulli`)への薄い委譲で、ホスト側だけで
2344/// 完結し `BackendOps` を経由しない。[`manual_seed`] が設定したグローバル
2345/// RNG を消費する(独立した乱数源が必要なら [`Generator`] を使う)。
2346///
2347/// - 検証(各確率が有限かつ `[0, 1]`)を終えてから乱数を消費する。
2348///   違反は [`RngError`] の該当 variant を返す。
2349/// - 整数演算のみで構成されるためプラットフォーム横断で bit 同一の
2350///   決定性を持つ。版をまたぐ乱数列の安定性は保証しない。
2351/// - 乱数源(xorshift64*)は暗号論的に安全ではない。鍵・トークン等の
2352///   生成には使わないこと。
2353/// - 出力確保は `probs` の要素数に比例する。信頼できない入力をそのまま
2354///   渡さないこと。
2355///
2356/// # 例
2357///
2358/// ```
2359/// let probs = fandhe_ai::Tensor::new(vec![0.0f32, 1.0, 0.5], &[3]).unwrap();
2360/// fandhe_ai::manual_seed(7);
2361/// let a = fandhe_ai::bernoulli(&probs).unwrap().host_slice().to_vec();
2362/// // 同じシードの `Generator` と bit 一致する。
2363/// let mut g = fandhe_ai::Generator::new(7);
2364/// let b = g.bernoulli(&probs).unwrap().host_slice().to_vec();
2365/// assert_eq!(a, b);
2366/// assert_eq!(a[0], 0.0);
2367/// assert_eq!(a[1], 1.0);
2368/// ```
2369pub fn bernoulli(probs: &Tensor<f32>) -> Result<Tensor<f32>, RngError> {
2370    fandhe_ai_autodiff::bernoulli(probs)
2371}
2372
2373/// 重み `weights`(rank 1 または 2)に比例するカテゴリ抽出を行い、添字の
2374/// `i32` テンソルを返す(PyTorch `torch.multinomial` 相当。イシュー
2375/// #2593)。設計・到達経路・乱数源は [`bernoulli`] と同じ。
2376///
2377/// - 出力 dtype は `i32`(本リポの index 型契約に合わせた意図的な差異)。
2378///   rank 1 は `[num_samples]`、rank 2 は `[行数, num_samples]`。
2379/// - 検証を終えてから乱数を消費する。非復元(`replacement == false`)で
2380///   カテゴリ数が `num_samples` に満たない等は [`RngError`] を返す。
2381/// - 非復元抽出の計算量は `O(num_samples * n)`。信頼できない入力を
2382///   そのまま渡さないこと。
2383/// - プラットフォーム横断で bit 同一。暗号用途には使わない。
2384///
2385/// # 例
2386///
2387/// ```
2388/// let w = fandhe_ai::Tensor::new(vec![0.0f32, 1.0, 0.0, 1.0], &[4]).unwrap();
2389/// fandhe_ai::manual_seed(3);
2390/// let idx = fandhe_ai::multinomial(&w, 2, false).unwrap();
2391/// let mut v = idx.host_slice().to_vec();
2392/// v.sort();
2393/// assert_eq!(v, vec![1, 3]);
2394/// ```
2395pub fn multinomial(
2396    weights: &Tensor<f32>,
2397    num_samples: usize,
2398    replacement: bool,
2399) -> Result<Tensor<i32>, RngError> {
2400    fandhe_ai_autodiff::multinomial(weights, num_samples, replacement)
2401}
2402
2403/// 平均 `mean`・標準偏差 `std` の正規分布に従う乱数テンソルを生成する
2404/// (PyTorch `torch.normal(mean, std, size)` のスカラー版相当。イシュー
2405/// #2593)。設計・到達経路は [`bernoulli`] と同じ。
2406///
2407/// **注意**: `nn::init::normal`(PyTorch `nn.init.normal_` 相当)とは
2408/// 別機能で、引数順も異なる(本関数は `mean, std, shape`、`nn::init::normal`
2409/// は `shape, mean, std`)。本関数は `std == 0` でも乱数を消費し、エラー
2410/// 型は [`RngError`](負の `std` 等)である。`fandhe_ai::*` と
2411/// `fandhe_ai::nn::init::*` を両方 glob import して裸の `normal` を使うと
2412/// 曖昧になるため、修飾して呼ぶこと。
2413///
2414/// - 決定性は同一プロセス・同一プラットフォーム内に限る(超越関数を
2415///   含むため)。版をまたぐ乱数列の安定性は保証しない。
2416/// - 乱数源は暗号論的に安全ではない。鍵・トークン等の生成には使わない。
2417/// - 出力確保は `shape` の要素数に比例する。信頼できない入力をそのまま
2418///   渡さないこと。
2419///
2420/// # 例
2421///
2422/// ```
2423/// fandhe_ai::manual_seed(1);
2424/// let t = fandhe_ai::normal(2.0, 0.0, &[3]).unwrap();
2425/// assert_eq!(t.host_slice().to_vec(), vec![2.0f32, 2.0, 2.0]);
2426/// ```
2427pub fn normal(mean: f32, std: f32, shape: &[usize]) -> Result<Tensor<f32>, RngError> {
2428    fandhe_ai_autodiff::normal(mean, std, shape)
2429}
2430
2431/// `[start, end)` を `step` 刻みで並べたテンソルを生成する(PyTorch
2432/// `torch.arange` 相当。イシュー #1726)。[`randn`]/[`rand`]/
2433/// [`randint`] と同じくホスト側だけで完結し `BackendOps` を経由しない
2434/// (`Op`/VJP も追加しない。微分不能な葉値のため)。数値契約
2435/// (プラットフォーム横断で bit 同一)は
2436/// `fandhe_ai_tensor_core::creation` モジュール doc 参照。
2437///
2438/// `fandhe_ai_autodiff::arange`(実体は
2439/// `fandhe_ai_tensor_core::creation::arange`)への薄い委譲
2440/// (composition root)。
2441pub fn arange(start: f32, end: f32, step: f32) -> Result<Tensor<f32>, CreationError> {
2442    fandhe_ai_autodiff::arange(start, end, step)
2443}
2444
2445/// `[start, end]`(両端を含む)を `steps` 個の等間隔値で埋めたテンソルを
2446/// 生成する(PyTorch `torch.linspace` 相当。イシュー #1726)。設計・
2447/// 到達経路は [`arange`] と同じ。
2448pub fn linspace(start: f32, end: f32, steps: usize) -> Result<Tensor<f32>, CreationError> {
2449    fandhe_ai_autodiff::linspace(start, end, steps)
2450}
2451
2452/// `n x n` の単位行列を生成する(PyTorch `torch.eye` 相当。長方形版は
2453/// 対象外。イシュー #1726)。dtype は `f32` 固定(facade 公開面は他の
2454/// 生成系トップレベル関数と同じく `f32` 限定。汎用版は
2455/// `fandhe_ai_tensor_core::creation::eye::<T>` を参照)。
2456pub fn eye(n: usize) -> Result<Tensor<f32>, ShapeError> {
2457    fandhe_ai_autodiff::eye::<f32>(n)
2458}
2459
2460/// `like` と同じ shape・全要素 `0.0` の新規テンソルを生成する(PyTorch
2461/// `torch.zeros_like` 相当。イシュー #1726)。`like` が転置・broadcast
2462/// 由来の非 contiguous view であっても shape のみを引き継ぎ、strides
2463/// は保存しない新規 contiguous バッファを返す
2464/// (`fandhe_ai_tensor_core::creation` モジュール doc 参照)。
2465pub fn zeros_like(like: &Tensor<f32>) -> Result<Tensor<f32>, ShapeError> {
2466    fandhe_ai_autodiff::zeros_like(like)
2467}
2468
2469/// `like` と同じ shape・全要素 `1.0` の新規テンソルを生成する(PyTorch
2470/// `torch.ones_like` 相当。イシュー #1726)。契約は [`zeros_like`] と
2471/// 同じ。
2472pub fn ones_like(like: &Tensor<f32>) -> Result<Tensor<f32>, ShapeError> {
2473    fandhe_ai_autodiff::ones_like(like)
2474}
2475
2476/// 要素ごとの論理積(PyTorch `torch.logical_and` の bool 入力版。イシュー
2477/// #2596・親 #2594)。NumPy 互換ブロードキャストに対応し、非微分・tape
2478/// 非記録のホスト計算である。
2479///
2480/// `fandhe_ai_autodiff::bool_ops::logical_and`(#2141 実装)への 1 式委譲
2481/// (composition root の crate 直下自由関数。比較 6 種と `masked_select` が
2482/// `Var` 委譲である #2510 とは別形で、`docs/autodiff-bool-ops-exposure-
2483/// decision.md` §6.2 の承認形 B-1)。ブロードキャスト不能な shape は
2484/// `AutodiffError::Shape(..)` を返す。`Var`〈f32〉の入力は
2485/// `Var::cast::<bool>()` か `Var::gt_bool` 等で bool 化してから渡す。
2486///
2487/// ```
2488/// use fandhe_ai::{Tensor, logical_and, tape};
2489///
2490/// let t = tape();
2491/// let x = t.var(&Tensor::new(vec![1.0, 5.0, 9.0], &[3])?);
2492/// let lo = x.gt_bool(&t.var(&Tensor::new(vec![2.0; 3], &[3])?))?;
2493/// let hi = x.lt_bool(&t.var(&Tensor::new(vec![8.0; 3], &[3])?))?;
2494/// let mask = logical_and(&lo, &hi)?;
2495/// assert_eq!(mask.contiguous().host_slice().into_owned(), vec![false, true, false]);
2496/// # Ok::<(), Box<dyn std::error::Error>>(())
2497/// ```
2498pub fn logical_and(a: &Tensor<bool>, b: &Tensor<bool>) -> Result<Tensor<bool>, AutodiffError> {
2499    fandhe_ai_autodiff::bool_ops::logical_and(a, b)
2500}
2501
2502/// 要素ごとの論理和(PyTorch `torch.logical_or` の bool 入力版。イシュー
2503/// #2596)。契約は [`logical_and`] と同じ(ブロードキャスト・非微分・
2504/// `AutodiffError::Shape(..)`)。
2505///
2506/// ```
2507/// use fandhe_ai::{Tensor, logical_or};
2508///
2509/// let a = Tensor::new(vec![true, false, false], &[3])?;
2510/// let b = Tensor::new(vec![false, false, true], &[3])?;
2511/// let m = logical_or(&a, &b)?;
2512/// assert_eq!(m.contiguous().host_slice().into_owned(), vec![true, false, true]);
2513/// # Ok::<(), Box<dyn std::error::Error>>(())
2514/// ```
2515pub fn logical_or(a: &Tensor<bool>, b: &Tensor<bool>) -> Result<Tensor<bool>, AutodiffError> {
2516    fandhe_ai_autodiff::bool_ops::logical_or(a, b)
2517}
2518
2519/// 要素ごとの否定(PyTorch `torch.logical_not` の bool 入力版。イシュー
2520/// #2596)。契約は [`logical_and`] と同じ。巨大 broadcast view は確保前の
2521/// 要素数検査で `AutodiffError::Shape(..)` になる(panic しない)。
2522///
2523/// ```
2524/// use fandhe_ai::{Tensor, logical_not};
2525///
2526/// let a = Tensor::new(vec![true, false], &[2])?;
2527/// let m = logical_not(&a)?;
2528/// assert_eq!(m.contiguous().host_slice().into_owned(), vec![false, true]);
2529/// # Ok::<(), Box<dyn std::error::Error>>(())
2530/// ```
2531pub fn logical_not(a: &Tensor<bool>) -> Result<Tensor<bool>, AutodiffError> {
2532    fandhe_ai_autodiff::bool_ops::logical_not(a)
2533}
2534
2535/// `device` に対応する具体 `BackendOps` を解決する(非公開)。
2536///
2537/// composition root の中核: `Device` → 具体バックエンドクレートの
2538/// `BackendOps` 実装への唯一の変換点。呼び出し元は [`tape_for`] のみ。
2539fn resolve_ops(device: Device) -> Result<Box<dyn BackendOps + Send>, BackendError> {
2540    match device {
2541        Device::Cpu => Ok(Box::new(fandhe_ai_backend_cpu::CpuBackendOps::new())),
2542        Device::Cuda(ordinal) => {
2543            // `CudaDeviceProvider::select` で存在検証してから構築する
2544            // (driver 不在・範囲外 ordinal を fail-fast で弾く。
2545            // `crates/backend-cuda/src/device.rs::CudaDeviceProvider`)。
2546            let provider = fandhe_ai_backend_cuda::CudaDeviceProvider::new();
2547            let providers: [&dyn DeviceProvider; 1] = [&provider];
2548            select_from(&providers, device)?;
2549            Ok(Box::new(fandhe_ai_backend_cuda::CudaBackendOps::new(
2550                ordinal,
2551            )))
2552        }
2553        #[cfg(target_os = "macos")]
2554        Device::Metal => {
2555            // `MetalDeviceProvider::select` で存在検証してから構築する
2556            // (`crates/backend-metal/src/device.rs::MetalDeviceProvider`)。
2557            //
2558            // イシュー #2114: 存在確認(`probe_all` = IOKit + `MTLCopyAllDevices`)は
2559            // `tape_for`/`predict_resident` の呼び出しごとに走り、tape_build の主因と推定される。
2560            // `verify_device_cached` は既定 OFF で従来と同じく毎回 `select_from` を実行する。
2561            // opt-in(backend-metal 側の `#[doc(hidden)]` ガード)の ON 時のみ、成功済みの
2562            // 存在確認を再利用する(失敗はキャッシュしない。設計は
2563            // `docs/perf/metal-tape-build-infer-fixedcost.md`)。
2564            fandhe_ai_backend_metal::fixed_cost_diag::verify_device_cached(|| {
2565                let provider = fandhe_ai_backend_metal::MetalDeviceProvider::new();
2566                let providers: [&dyn DeviceProvider; 1] = [&provider];
2567                select_from(&providers, device).map(|_| ())
2568            })?;
2569            Ok(Box::new(fandhe_ai_backend_metal::MetalBackendOps::new()))
2570        }
2571    }
2572}
2573
2574/// REQ-14 の明示解放 API(イシュー #1018 ツリー・#1020 CUDA・#1021
2575/// Metal)。`device` に対応するバックエンドのデバイスメモリプール
2576/// (`backend-cuda`/`backend-metal` のサイズクラス別プール実装)が
2577/// アイドル保持している分を即座に実解放する。プールを持たない
2578/// バックエンド(CPU 等)は何もせず `Ok(())` を返す(`BackendOps::
2579/// release_cached_device_memory` の既定契約。`docs/device-memory-pool-
2580/// design.md` §3.1「facade からの再公開」)。
2581///
2582/// `fandhe_ai_tensor_core::BackendOps::release_cached_device_memory` への
2583/// 薄い委譲(composition root。`docs/compat-api-scope.md` §0 の確定
2584/// 公開面)。`Device` は `tensor-core` 由来の外部型(識別子 enum)の
2585/// ため facade は inherent メソッドを追加できず(orphan rule。
2586/// `docs/facade-device-handle-design.md` の「案 B のみ採用」方針)、
2587/// [`tape_for`] と同型の自由関数として公開する。存在しないデバイス・
2588/// 範囲外 ordinal・driver 不在は [`BackendError`] を返す(`tape_for` と
2589/// 同じ fail-fast。`resolve_ops` を経由するため検証規則も同一)。
2590pub fn release_cached_memory(device: Device) -> Result<(), BackendError> {
2591    resolve_ops(device)?.release_cached_device_memory()
2592}
2593
2594/// `device` のデバイスメモリプールの統計スナップショット(診断用。
2595/// イシュー #1020・#1021)。POD [`PoolStats`] のみを返し、内部ハンドル
2596/// 表現は含まない(`docs/device-memory-pool-design.md` §3.1「facade
2597/// からの再公開」)。プールを持たないバックエンドは `Ok(None)`
2598/// (`BackendOps::device_memory_pool_stats` の既定実装)。存在しない
2599/// デバイス・範囲外 ordinal・driver 不在は [`release_cached_memory`]
2600/// と同じく [`BackendError`] を返す。
2601pub fn memory_pool_stats(device: Device) -> Result<Option<PoolStats>, BackendError> {
2602    Ok(resolve_ops(device)?.device_memory_pool_stats())
2603}
2604
2605/// CUDA GEMM(`fandhe_ai::tape().var(a).matmul(b)` 等が最終的に到達する
2606/// `CudaBackendOps::gemm`)の TF32 Tensor Core 経路を opt-in で有効化・
2607/// 無効化する(イシュー #1042。親ツリー #1029 Phase 2)。
2608///
2609/// `fandhe_ai_backend_cuda::precision::set_tf32_gemm_enabled` への薄い
2610/// 委譲(composition root。`docs/compat-api-scope.md` §0 の確定公開面)。
2611/// **既定は無効(FP32 厳密)**。有効化すると以降の全スレッド・全 CUDA
2612/// device の `gemm` 呼び出しがプロセスワイドに TF32 Tensor Core 経路へ
2613/// 切り替わる(`Device` 単位ではない。`fandhe_ai_backend_cuda::precision`
2614/// モジュール冒頭コメントの契約参照)。有効時に TF32 カーネルが使用不能
2615/// (cc<8.0・NVRTC コンパイル失敗等)な環境では `gemm` 呼び出しが
2616/// [`BackendError`] を返す(fail-closed。FP32 への黙示フォールバックは
2617/// しない)。数値一致許容誤差(相対 1e-3 未満 または 絶対 1e-5 未満)・
2618/// 適用範囲(`gemm_bias_act`・`gemm_resident_*`・学習経路は対象外)は
2619/// 変更しない(`docs/cuda-tf32-optin-api-decision.md`)。
2620pub fn set_cuda_tf32_gemm_enabled(enabled: bool) {
2621    fandhe_ai_backend_cuda::precision::set_tf32_gemm_enabled(enabled);
2622}
2623
2624/// [`set_cuda_tf32_gemm_enabled`] で設定した現在の opt-in 状態を返す
2625/// (既定 `false`)。
2626pub fn cuda_tf32_gemm_enabled() -> bool {
2627    fandhe_ai_backend_cuda::precision::tf32_gemm_enabled()
2628}
2629
2630/// 学習 step の update 区間(`BackendOps::sgd_step_device_tracked`)を
2631/// CUDA Graph で capture・再利用する経路を opt-in で有効化・無効化する
2632/// (イシュー #1349。親 #1348・ルート #1341 → #1269)。
2633///
2634/// `fandhe_ai_backend_cuda::graph::set_step_graph_enabled` への薄い委譲
2635/// (composition root。`docs/compat-api-scope.md` §0 の確定公開面)。
2636/// **既定は無効**。有効化すると以降の全スレッド・全 CUDA device の学習
2637/// step update 区間がプロセスワイドに capture 対象となる(`Device` 単位
2638/// ではない。`fandhe_ai_backend_cuda::graph` モジュール冒頭コメントの
2639/// 契約参照)。
2640///
2641/// **重要な制約(設定タイミング)**: `CudaDevice` は ordinal ごとに
2642/// プロセス内で 1 回だけ構築・キャッシュされる(`context_cache::
2643/// cached_device`)ため、本関数は**最初の CUDA デバイス初期化より前**
2644/// (`fandhe_ai::tape_for(Device::Cuda(_))` の最初の呼び出しより前)に
2645/// 呼ぶ必要がある。有効化がデバイス初期化に間に合わなかった場合、以降の
2646/// 学習 step は `BackendError::Unsupported` を返し fail-closed に拒否
2647/// する(silent に非 capture 経路へフォールバックしない。`docs/backend-
2648/// cuda-graph-step-capture-design.md` §4.7)。
2649///
2650/// capture 対象は update 区間のみ(forward/backward は対象外。同 design
2651/// doc §1・§3.2)であり、`bit` 単位で非 capture 経路と同一の損失・勾配・
2652/// パラメータになることを受け入れ条件とする(同 doc §7 受け入れ (a))。
2653/// 非対応バックエンド(CPU/Metal)・opt-in OFF では
2654/// `BackendOps::captured_segment_key` が常に `Ok(None)` を返すため、
2655/// `DeviceParamStore::step` は現行の直接実行経路のまま動作する。
2656pub fn set_cuda_graph_step_enabled(enabled: bool) {
2657    fandhe_ai_backend_cuda::graph::set_step_graph_enabled(enabled);
2658}
2659
2660/// [`set_cuda_graph_step_enabled`] で設定した現在の opt-in 状態を返す
2661/// (既定 `false`)。
2662pub fn cuda_graph_step_enabled() -> bool {
2663    fandhe_ai_backend_cuda::graph::step_graph_enabled()
2664}
2665
2666/// [`fandhe_ai_backend_cuda::graph::StepGraphMode`] の再公開(composition
2667/// root。イシュー #1350)。`framework-compare` の `bench-fandhe` が
2668/// `--graph stream-only` 起動時に「環境変数 `FANDHE_AI_CUDA_GRAPH_STEP=
2669/// stream-only` が実際に反映されたか」を確認するために使う診断用途の
2670/// 公開面(`docs/compat-api-scope.md` §0)。`set_cuda_graph_step_enabled`
2671/// と異なり API からモードを設定する手段はない(`stream-only` は環境
2672/// 変数専用の中間状態。`fandhe_ai_backend_cuda::graph` モジュール冒頭
2673/// コメント参照)。
2674pub type CudaGraphStepMode = fandhe_ai_backend_cuda::graph::StepGraphMode;
2675
2676/// [`fandhe_ai_backend_cuda::graph::StepGraphStats`] の再公開(同上。
2677/// launch 固定費の診断用スナップショット)。
2678pub type CudaGraphStepStats = fandhe_ai_backend_cuda::graph::StepGraphStats;
2679
2680/// 現在の CUDA Graph step capture の opt-in モードを返す(イシュー
2681/// #1350。[`CudaGraphStepMode`] 参照)。
2682pub fn cuda_graph_step_mode() -> CudaGraphStepMode {
2683    fandhe_ai_backend_cuda::graph::step_graph_mode_public()
2684}
2685
2686/// launch 固定費の診断用スナップショットを返す(イシュー #1350。
2687/// [`CudaGraphStepStats`] 参照)。計測ウィンドウの外(`framework-compare`
2688/// の record 生成時)で 1 回だけ呼ぶことを想定しており、呼び出し自体は
2689/// 計測時間へ計上されない設計(`fandhe_ai_backend_cuda::graph::
2690/// step_graph_stats` doc コメント参照)。
2691pub fn cuda_graph_step_stats() -> CudaGraphStepStats {
2692    fandhe_ai_backend_cuda::graph::step_graph_stats()
2693}
2694
2695/// 推論 forward チェーンの CUDA Graph capture を opt-in で有効/無効にする
2696/// (イシュー #2115 が機構・#3115 が公開形・#3116 が公開。公開形の正は
2697/// `docs/facade-graph-tier-b-optin-exposure-decision.md` §3・§4)。
2698///
2699/// - **既定は無効**。有効化しない限り挙動は変わない。プロセスワイドの切替で
2700///   `Device` 単位ではない。優先順位は API 明示 > 環境変数
2701///   `FANDHE_AI_CUDA_GRAPH_INFER` > 既定 OFF
2702/// - **設定タイミング**: 最初の CUDA デバイス初期化より前に呼ぶ。間に合わ
2703///   なかった場合は拒否されず、非 capture 経路へ黙ってフォールバックする
2704///   (出力は同一)。遅れた場合に `BackendError::Unsupported` で拒否する
2705///   [`set_cuda_graph_step_enabled`] とは異なる
2706/// - **非対応環境**: CUDA 非搭載・CPU のみ・Metal の環境でも呼べる
2707///   (フラグを立てるだけで driver に触れない)。効果はなく、パニックもしない
2708/// - **利用者が融合を直接制御する API ではない**: TF32 の setter 等と同型の、
2709///   プロセスワイドな実行戦略トグルであり、融合する op や境界を指定する手段
2710///   でも汎用 `compile` の入口でもない(REQ-12。決定記録 §5)
2711///
2712/// ```
2713/// fandhe_ai::set_cuda_graph_infer_enabled(false);
2714/// assert!(!fandhe_ai::cuda_graph_infer_enabled());
2715/// ```
2716pub fn set_cuda_graph_infer_enabled(enabled: bool) {
2717    fandhe_ai_backend_cuda::graph::set_infer_graph_enabled(enabled);
2718}
2719
2720/// 推論チェーン capture の現在の opt-in 状態を返す
2721/// ([`set_cuda_graph_infer_enabled`] 参照。イシュー #3116)。
2722pub fn cuda_graph_infer_enabled() -> bool {
2723    fandhe_ai_backend_cuda::graph::infer_graph_enabled()
2724}
2725
2726/// GPU `run_fused` の elementwise allowlist 融合(区分 B-1)を CUDA で
2727/// opt-in 有効/無効にする(イシュー #2085 が機構・#3115 が公開形・#3385 が
2728/// 公開。公開形の正は `docs/facade-graph-tier-b-optin-exposure-decision.md`
2729/// §3・§13)。
2730///
2731/// - **既定は無効**。有効化しない限り挙動は変わない。プロセスワイドの切替で
2732///   `Device` 単位ではない。CUDA と Metal を一括で切り替える setter は設けない
2733/// - **無効のとき**: `run_fused` はデバイスに触れず `BackendError::Unsupported`
2734///   を返し、呼び出し元は per-op 経路へフォールバックする(導入前と bit 同一)
2735/// - **有効のとき**: 同一バックエンドの per-op 合成と bit 一致し、CPU とは
2736///   REQ-2 統一複合判定で一致する。tolerance は変更しない
2737/// - **設定タイミング**: 制約なし。ゲートは `run_fused` の呼び出しごとに判定される
2738/// - **非対応環境**: CUDA 非搭載・CPU のみ・Metal の環境でも呼べる
2739///   (フラグを立てるだけで driver に触れない)。効果はなく、パニックもしない
2740/// - **利用者が融合を直接制御する API ではない**: TF32 の setter 等と同型の、
2741///   プロセスワイドな実行戦略トグルであり、融合する op や境界を指定する手段
2742///   でも汎用 `compile` の入口でもない(REQ-12。決定記録 §5)
2743///
2744/// ```
2745/// fandhe_ai::set_cuda_elementwise_fusion_enabled(false);
2746/// assert!(!fandhe_ai::cuda_elementwise_fusion_enabled());
2747/// ```
2748pub fn set_cuda_elementwise_fusion_enabled(enabled: bool) {
2749    fandhe_ai_backend_cuda::fused_elementwise::set_gpu_elementwise_fusion_enabled(enabled);
2750}
2751
2752/// CUDA の elementwise 融合 opt-in の現在状態を返す
2753/// ([`set_cuda_elementwise_fusion_enabled`] 参照。イシュー #3385)。
2754pub fn cuda_elementwise_fusion_enabled() -> bool {
2755    fandhe_ai_backend_cuda::fused_elementwise::gpu_elementwise_fusion_enabled()
2756}
2757
2758/// Metal 版の elementwise 融合 opt-in(macOS 限定。契約・既定・制約は
2759/// [`set_cuda_elementwise_fusion_enabled`] と同じ。非 macOS ビルドには
2760/// 存在しない。イシュー #3385)。
2761#[cfg(target_os = "macos")]
2762pub fn set_metal_elementwise_fusion_enabled(enabled: bool) {
2763    fandhe_ai_backend_metal::fused_elementwise::set_gpu_elementwise_fusion_enabled(enabled);
2764}
2765
2766/// Metal の elementwise 融合 opt-in の現在状態を返す
2767/// ([`set_metal_elementwise_fusion_enabled`] 参照。macOS 限定。イシュー #3385)。
2768#[cfg(target_os = "macos")]
2769pub fn metal_elementwise_fusion_enabled() -> bool {
2770    fandhe_ai_backend_metal::fused_elementwise::gpu_elementwise_fusion_enabled()
2771}
2772
2773/// CUDA GEMM 精度モード(既定 `Fp32Strict`・単発 `Tf32`・3×TF32
2774/// `Tf32x3`。イシュー #1355。親ツリー #1354・承認元 #1338)の再公開。
2775/// `set_cuda_gemm_precision`/`cuda_gemm_precision` の戻り値・引数型
2776/// として使う(`fandhe_ai_backend_cuda::precision::CudaGemmPrecision` の
2777/// 薄い再公開。[`PoolStats`] と同じ前例)。
2778pub use fandhe_ai_backend_cuda::precision::CudaGemmPrecision;
2779
2780/// CUDA GEMM(`fandhe_ai::tape().var(a).matmul(b)` 等が最終的に到達する
2781/// `CudaBackendOps::gemm`)の精度モードを設定する(イシュー #1355。
2782/// [`set_cuda_tf32_gemm_enabled`] の 3 モード拡張版・同型の composition
2783/// root 委譲)。
2784///
2785/// `fandhe_ai_backend_cuda::precision::set_gemm_precision` への薄い委譲。
2786/// **既定は [`CudaGemmPrecision::Fp32Strict`]**。`CudaGemmPrecision::
2787/// Tf32x3` を指定すると、以降の全スレッド・全 CUDA device の `gemm`
2788/// 呼び出しが 3×TF32(split-single 法。hi/lo 分割・3 回の `mma.sync`
2789/// 累積)経路へプロセスワイドに切り替わる(`Device` 単位ではない。
2790/// `fandhe_ai_backend_cuda::precision` モジュール冒頭コメントの契約
2791/// 参照)。有効時にモード固有のカーネルが使用不能(cc<8.0・NVRTC
2792/// コンパイル失敗・整列制約不成立等)な環境では `gemm` 呼び出しが
2793/// [`BackendError`] を返す(fail-closed。FP32 への黙示フォールバックは
2794/// しない)。`Tf32x3` は f32 SIMT と bit 一致しない(
2795/// `.claude/rules/coding-rust.md` FMA 契約統一節の明示的例外。数値一致
2796/// 許容誤差自体は変更しない)。適用範囲(`gemm_bias_act`・
2797/// `gemm_resident_*`・学習経路は対象外)は [`set_cuda_tf32_gemm_enabled`]
2798/// と同じ(`docs/cuda-tf32-optin-api-decision.md`・
2799/// `docs/cuda-tf32x3-split-single-decision.md`)。
2800///
2801/// [`set_cuda_tf32_gemm_enabled`]/[`cuda_tf32_gemm_enabled`](旧 2 値
2802/// API)は互換ラッパーとして維持する: `set_cuda_tf32_gemm_enabled(false)`
2803/// はどのモードからでも `Fp32Strict` へ戻す。`cuda_tf32_gemm_enabled()`
2804/// は単発 `Tf32` のときのみ `true` を返す(`Tf32x3` では `false`)。
2805pub fn set_cuda_gemm_precision(mode: CudaGemmPrecision) {
2806    fandhe_ai_backend_cuda::precision::set_gemm_precision(mode);
2807}
2808
2809/// [`set_cuda_gemm_precision`] で設定した現在の精度モードを返す
2810/// (既定 [`CudaGemmPrecision::Fp32Strict`])。
2811pub fn cuda_gemm_precision() -> CudaGemmPrecision {
2812    fandhe_ai_backend_cuda::precision::gemm_precision()
2813}
2814
2815/// CUDA `DeviceBuffer` の確保配置(`alloc_zeroed`/`upload`)を managed
2816/// memory(`cuMemAllocManaged`)へ opt-in で切り替える(イシュー #1352。
2817/// 親 #1351「GB10 物理統合メモリ向けゼロコピー割当の試作・実測」)。
2818///
2819/// `fandhe_ai_backend_cuda::placement::set_managed_placement_enabled` への
2820/// 薄い委譲([`set_cuda_tf32_gemm_enabled`] と同型の composition root。
2821/// `docs/compat-api-scope.md` §0 の確定公開面)。**既定は無効
2822/// (`cuMemAlloc` による device-only 配置)**。有効化すると以降の全
2823/// スレッド・全 CUDA device の確保呼び出しがプロセスワイドに managed
2824/// 配置へ切り替わる(`Device` 単位ではない。`fandhe_ai_backend_cuda::
2825/// placement` モジュール冒頭コメントの契約参照)。
2826///
2827/// **本イシュー時点のスコープ**(`docs/backend-cuda-managed-placement-
2828/// decision.md` 参照): `MemoryOps::alloc_zeroed`/`upload`/`download`
2829/// と、これらを経由する GEMM/SGD 常駐経路
2830/// (`gemm_resident_rhs`/`gemm_resident_lhs`(NT 転置分岐を除く)/
2831/// `linear_forward_device`/`sgd_step_device`)は managed 配置に対応
2832/// 済み。fresh モードの素の `CudaBackendOps::gemm`(`run_tiled_f32` 系。
2833/// `CudaMemory` を経由せず `clone_htod`/`alloc_zeros` を直接呼ぶ)・
2834/// `gemm_resident_lhs` の NT 転置分岐・その他の演算(elementwise・
2835/// rmsnorm・softmax 等)は本イシューでは managed 化していない
2836/// (既定 device-only のまま変更なし。opt-in 時にこれらの経路を通ると
2837/// 従来どおり device-only 配置で動作する。managed 化の可否は #1353 の
2838/// 実測結果を踏まえ後続で判断する)。
2839///
2840/// 対象デバイスが managed memory 非対応(`CU_DEVICE_ATTRIBUTE_
2841/// MANAGED_MEMORY`/`CU_DEVICE_ATTRIBUTE_CONCURRENT_MANAGED_ACCESS` の
2842/// いずれかが 0)の場合、有効時の確保呼び出しは
2843/// [`BackendError::Unsupported`] を返す(fail-closed。device-only への
2844/// 黙示フォールバックはしない。`set_cuda_tf32_gemm_enabled` と同じ方針)。
2845///
2846/// 出力の数値契約: 配置はメモリの物理的な置き場所のみを変え、確保
2847/// バッファを読み書きするカーネル本体・起動 config は device-only/
2848/// managed の両配置で完全に共有するため、出力は配置に依らず bit
2849/// 同一となる(`fandhe_ai_backend_cuda::memory` モジュール冒頭コメント
2850/// 「配置(managed 拡張)」参照)。既定(無効)時の経路・出力は本
2851/// イシュー導入前と完全に不変。
2852pub fn set_cuda_managed_memory_enabled(enabled: bool) {
2853    fandhe_ai_backend_cuda::placement::set_managed_placement_enabled(enabled);
2854}
2855
2856/// [`set_cuda_managed_memory_enabled`] で設定した現在の opt-in 状態を
2857/// 返す(既定 `false`)。
2858pub fn cuda_managed_memory_enabled() -> bool {
2859    fandhe_ai_backend_cuda::placement::managed_placement_enabled()
2860}
2861
2862/// CUDA H2D(ホスト→デバイス転送)を、pageable ホストメモリからの直接
2863/// 転送ではなく pinned(page-locked)ステージングバッファ経由で発行する
2864/// opt-in スイッチ(イシュー #1585。低レイヤー診断
2865/// `docs/perf/lowlayer-diagnosis-2026-09-12.md` §7 表 B-3 行で起票された
2866/// 候補)。
2867///
2868/// `fandhe_ai_backend_cuda::{set_pinned_h2d_enabled}` への薄い委譲
2869/// ([`set_cuda_managed_memory_enabled`] と同型の composition root。
2870/// `docs/compat-api-scope.md` §0 の確定公開面)。**既定は無効**(pageable
2871/// ホストメモリからの `clone_htod`/`memcpy_htod` 直接発行。導入前と
2872/// 経路・出力は bit 同一)。有効化すると以降の全スレッド・全
2873/// `CudaMemory`/`CudaGemm` インスタンスの H2D 発行(`upload`/
2874/// `upload_into`・`Var::matmul` 等が最終的に到達する各 GEMM `run_*`
2875/// 系)がプロセスワイドに pinned staging 経由へ切り替わる。
2876///
2877/// **本イシュー時点のスコープ**(`docs/perf/cuda-h2d-pinned-staging.md`
2878/// 参照): f32 経路(`MemoryOps::upload`/`upload_into`・fresh/resident
2879/// GEMM の各 `run_*`/`launch_*` 系)のみ対応。TF32 Tensor Core 経路
2880/// (`run_wmma_tf32` が到達する `run_wmma_f32_kernel`/
2881/// `run_wmma_tf32_opt_kernel`/`run_wmma_tf32_staged_kernel`)は入力が
2882/// `&[f32]` のため `upload_h2d_new` を経由し、有効化時は pinned staging
2883/// の対象に含まれる。**対象外のまま**なのは f16 Tensor Core 経路
2884/// (`gemm_mma.rs` の `run_f16` 系・`gemm.rs::run_f16_kernel`。f16 データ
2885/// は `upload_h2d_new` の型〈`&[f32]`〉と一致しないため構造的に非到達)・
2886/// elementwise/rmsnorm/softmax/transpose/mse のみ(既定どおり
2887/// pageable のまま変更なし)。
2888///
2889/// 数値契約: pinned バッファへ同期コピーしてから DMA を発行するだけで
2890/// 転送対象の内容自体は変わらないため、出力は経路に依らず bit 同一
2891/// (`fandhe_ai_backend_cuda::host_staging` モジュール「H2D 用
2892/// ステージング」節)。既定(無効)時の経路・出力は本イシュー導入前と
2893/// 完全に不変。
2894pub fn set_cuda_pinned_h2d_enabled(enabled: bool) {
2895    fandhe_ai_backend_cuda::set_pinned_h2d_enabled(enabled);
2896}
2897
2898/// [`set_cuda_pinned_h2d_enabled`] で設定した現在の opt-in 状態を返す
2899/// (既定 `false`)。
2900pub fn cuda_pinned_h2d_enabled() -> bool {
2901    fandhe_ai_backend_cuda::pinned_h2d_enabled()
2902}
2903
2904/// Metal GEMM(`fandhe_ai::tape().var(a).matmul(b)` 等が最終的に到達する
2905/// `MetalBackendOps::gemm`)の split-K 2 パス経路(イシュー #1516 で
2906/// 本番結線・#1544 で既定有効化)を実行時に無効化する opt-out スイッチ
2907/// (イシュー #1545)。
2908///
2909/// `fandhe_ai_backend_metal::split_k_runtime::set_split_k_enabled` への
2910/// 薄い委譲([`set_cuda_tf32_gemm_enabled`] と同型の composition root。
2911/// `docs/compat-api-scope.md` §0 の確定公開面)。**既定は有効
2912/// (`true`)**——コンパイル時ゲート(`SPLIT_K_DISPATCH_AUTO_PRODUCTION_
2913/// ENABLED`)・インスタンス単位ゲート(`MetalGemm::split_k_auto_enabled`)
2914/// に続く 3 段目のゲートであり、本関数を呼ばない限り #1544 で確定した
2915/// 本番既定挙動は完全に不変。`false` にすると、以降の全スレッドの
2916/// `dispatch_auto`(`MetalBackendOps::gemm` が通る本番 NN 入口)が
2917/// split-K 到達形状も含めて常に classic 経路へ固定され、結線前
2918/// (`fandhe-ai =0.8.0` 相当)と bit 同一の出力を返す(fail-closed に
2919/// 「安全な既知の経路」へ倒す設計。`true` に戻すと従来どおりの経路選択
2920/// に戻る)。プロセスワイドな設定であり(`Device` 単位ではない)、
2921/// `fandhe_ai_backend_metal::split_k_runtime` モジュール冒頭コメントの
2922/// 3 段ゲートの関係・`docs/backend-metal-splitk-decision.md` §5
2923/// 「実行時トグル」を参照。
2924///
2925/// split-K 到達形状(K 支配的な非正方形状。`tile::should_split_k`)では
2926/// classic 経路と bit 一致しない(実測 baseline 非後退方式による受け入れ。
2927/// `docs/backend-metal-splitk-parity-judgment-decision.md` §7)。数値一致
2928/// 許容誤差そのものは変更しない。適用範囲は `dispatch_auto` を経由する
2929/// `MetalBackendOps::gemm` 系のみ(`gemm_bias_act` 融合カーネルは元々
2930/// classic 経路のみのため対象外)。
2931#[cfg(target_os = "macos")]
2932pub fn set_metal_split_k_gemm_enabled(enabled: bool) {
2933    fandhe_ai_backend_metal::split_k_runtime::set_split_k_enabled(enabled);
2934}
2935
2936/// [`set_metal_split_k_gemm_enabled`] で設定した現在の実行時トグル状態を
2937/// 返す(既定 `true`)。
2938#[cfg(target_os = "macos")]
2939pub fn metal_split_k_gemm_enabled() -> bool {
2940    fandhe_ai_backend_metal::split_k_runtime::split_k_enabled()
2941}
2942
2943/// [`crate::interop::onnx::OnnxModel::run`] の GPU 実行(CUDA)を opt-in
2944/// で有効化・無効化する(イシュー #2077。`docs/onnx-gpu-execution-
2945/// decision.md`)。
2946///
2947/// `crate::interop::onnx` の `pub(crate)` 状態への薄い委譲(composition
2948/// root。[`set_cuda_tf32_gemm_enabled`] と同型)。**既定は無効
2949/// (`false`)**——無効時の `OnnxModel::run` の経路・出力は本イシュー
2950/// 導入前と bit 完全に不変。有効化すると、以降の全スレッドの
2951/// `OnnxModel::run` 呼び出しが `fandhe_ai_backend_cuda::CudaBackendOps`
2952/// (ordinal 0 固定)経由の device 実行を試みる(プロセスワイド。
2953/// `Device` 単位の切替 API は設けない)。CUDA driver 不在・ordinal 0 が
2954/// 存在しない環境では `run` 自体が [`crate::interop::onnx::OnnxError::
2955/// Execution`] を返す(ホスト CPU への黙示フォールバックはしない。
2956/// fail-closed。OWASP A08)。両フラグ(本関数・
2957/// `set_metal_onnx_gpu_execution_enabled`〈macOS 限定 cfg のため非
2958/// macOS ビルドでは存在せずリンク化しない〉)が有効な場合は CUDA を
2959/// 優先する(評価順固定)。対象 op・数値契約(REQ-2 統一複合判定)は
2960/// `crate::interop::onnx::OnnxModel` のドキュメンテーションコメントを
2961/// 正とする。
2962pub fn set_cuda_onnx_gpu_execution_enabled(enabled: bool) {
2963    crate::interop::onnx::set_cuda_onnx_gpu_execution_enabled(enabled);
2964}
2965
2966/// [`set_cuda_onnx_gpu_execution_enabled`] で設定した現在の opt-in 状態を
2967/// 返す(既定 `false`)。
2968pub fn cuda_onnx_gpu_execution_enabled() -> bool {
2969    crate::interop::onnx::cuda_onnx_gpu_execution_enabled()
2970}
2971
2972/// [`set_cuda_onnx_gpu_execution_enabled`] の Metal 版(macOS 限定。
2973/// イシュー #2077)。既定・fail-closed 方針は同一で、有効化すると
2974/// `fandhe_ai_backend_metal::MetalBackendOps` 経由の device 実行を試みる。
2975#[cfg(target_os = "macos")]
2976pub fn set_metal_onnx_gpu_execution_enabled(enabled: bool) {
2977    crate::interop::onnx::set_metal_onnx_gpu_execution_enabled(enabled);
2978}
2979
2980/// [`set_metal_onnx_gpu_execution_enabled`] で設定した現在の opt-in 状態を
2981/// 返す(既定 `false`。macOS 限定)。
2982#[cfg(target_os = "macos")]
2983pub fn metal_onnx_gpu_execution_enabled() -> bool {
2984    crate::interop::onnx::metal_onnx_gpu_execution_enabled()
2985}
2986
2987/// `Var`/`Sequential` の `custom`/`add_custom` と `Tape::add_custom`
2988/// (ユーザー定義 forward/backward 抽象の合成入口。イシュー #2064
2989/// §12.5)が facade の公開面から到達不能であることを、
2990/// `crates/autodiff/tests/architecture_boundaries.rs`・`crates/facade/
2991/// tests/api_surface.rs` のソース文字列走査(heuristics)とは独立に、
2992/// **コンパイラそのもの**で固定するための非公開足場
2993/// (`docs/autodiff-custom-function-decision.md` 「否定ガードの多層防御」
2994/// 節参照)。
2995///
2996/// # 方針転換の経緯(2026-09。PR #2212 codex-review 指摘)
2997///
2998/// 旧実装は `custom`/`add_custom` を実際に呼び出す 3 本の
2999/// ```` ```compile_fail,E0599 ```` doctest ブロックだった。しかし
3000/// **stable rustdoc(実測 rustc 1.98.1)は `compile_fail,EXXXX` の
3001/// エラーコードを一切照合しない**(`E0599` を無関係な `E0308` へ書き
3002/// 換えても doctest は合格した。実測に基づく事実)。この特性下では、
3003/// facade の公開面へ引数付きシグネチャで `custom`/`add_custom` が
3004/// 漏れ出しても `.custom()` の呼び出しは「引数の個数が違う」
3005/// (E0061)・「モジュールが見つからない」(E0432)・「glob の衝突で
3006/// 名前が曖昧」(E0659)等、`E0599` 以外の何らかのエラーで**依然として
3007/// コンパイルに失敗する**ため、`compile_fail`(エラーコード不問)は
3008/// 空合格してしまい、部分公開を検出できない。
3009///
3010/// そこで本足場は「失敗するはずの例を用意する」方式から「**成功する
3011/// はずの正のプローブを 1 つ用意し、それが実際にコンパイルできること**
3012/// を固定する」方式へ転換した。原理: facade の全 `pub mod`(ネスト含む)
3013/// を glob import したスコープに、ローカルにのみ存在する
3014/// `__FandheHoldProbe` トレイト(`custom`/`add_custom` という名前の
3015/// メソッドを持つ)を用意し、`Var`/`Tape`/`compat::Sequential` へ実装
3016/// したうえで、各型に対しメソッド形・型パス形の両方で呼び出す。facade
3017/// 側にこれと同名の実体(trait 経由の公開・inherent メソッドとしての
3018/// 転送メソッド追加のいずれであっても)が漏れ出すと、
3019/// - 別の trait が同名メソッドを提供する形の漏れ → 呼び出しが
3020///   複数のトレイト実装のどちらを指すか一意に定まらず曖昧になり、
3021///   エラーコードに依存せず必ずコンパイルが失敗する
3022/// - facade 独自の inherent メソッドとして漏れる形の漏れ(`Tape::custom`
3023///   への転送メソッド追加。§12.4「入口」参照)→ inherent メソッドが
3024///   優先解決され、戻り値の型がプローブの期待型と一致せず型不一致で
3025///   必ずコンパイルが失敗する
3026/// のいずれかとなり、**特定のエラーコードに依存せず**部分公開を
3027/// fail-closed に検出できる。1 ブロックにまとめても検出できるため、
3028/// 旧実装が抱えていた「3 種の禁止呼び出しを独立ブロックへ分割する
3029/// 必要性」(部分公開の見逃し防止)はこの転換によって解消された。
3030///
3031/// **本プローブ単独の既知の限界**: `&Var`(`Var` そのものではなく
3032/// その参照型)に対する 2 段目の autoref を経由した trait 実装、および
3033/// facade 型が内部型への `Deref` を実装した場合のフィールドアクセス
3034/// 経由の到達は、本プローブの呼び出し形(メソッド形・型パス形の
3035/// いずれも `Var`/`Tape`/`compat::Sequential` 自体に対する呼び出し)
3036/// だけでは拾いきれない可能性がある。この限界は、[`crates/facade/
3037/// tests/api_surface.rs::workspace_declares_custom_fn_only_on_tape_and_facade_delegation`]
3038/// (workspace 全体を対象に `fn custom`/`fn add_custom` の**定義元**を
3039/// インベントリする多層防御)が、facade からの到達可能性とは独立に
3040/// 「そもそも `crates/autodiff/src/tape.rs`(`Tape::custom`)以外の
3041/// どこにも `custom`/`add_custom` を定義させない」という定義元側の
3042/// 制約で補完する。
3043///
3044/// glob import する `pub mod` 集合(下記 doctest 内の `use` 一覧)と
3045/// 本クレートの実際の `pub mod` 宣言(ネスト含めて `src/` 全体を再帰
3046/// 走査した集合)がドリフトしないことは `crates/facade/tests/
3047/// api_surface.rs::custom_function_hold_doctest_globs_all_pub_modules`
3048/// が機械的に固定する(`collect_public_module_paths` が `lib.rs` の
3049/// `pub mod` 宣言から解決先ファイルを再帰的にたどり `nn::rnn` 等の
3050/// ネストしたパスも含めた集合を得たうえで doctest 内の `use
3051/// fandhe_ai::<mod>::*;` の集合と突き合わせる)。加えて本ブロックの
3052/// フェンス・本文が固定文言からドリフトしていないことは同ファイルの
3053/// `custom_function_hold_doctest_probe_body_matches_fixed_contract`
3054/// が固定する。`crates/facade/tests/api_surface.
3055/// rs::facade_source_declares_no_custom_fn_in_any_context` は、可視性
3056/// キーワード・宣言文脈(inherent impl・trait impl・trait 定義・自由
3057/// 関数のいずれか)を問わず facade 全ソースに `fn custom`/
3058/// `fn add_custom` 宣言が存在しないことを固定する(本 doctest 内の
3059/// トレイト・関数宣言は `///` コメントの中身のため、コメント除去後の
3060/// トークン走査には現れず誤検出しない)。
3061///
3062/// `Tape::custom` はイシュー #2549(ルート #2499 の一括承認・
3063/// `docs/autodiff-custom-function-decision.md` §16.1)で承認形のまま公開済み
3064/// のため、`__probe_tape` から `Tape::custom` の 2 行だけを外した。本ガードは
3065/// 承認範囲外(`Var`/`Sequential` の `custom`/`add_custom`・
3066/// `Tape::add_custom`)の非公開を固定し続ける(§16.4)。
3067///
3068/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
3069/// できること
3070///
3071/// ```
3072/// use fandhe_ai::*;
3073/// use fandhe_ai::compat::*;
3074/// use fandhe_ai::optim::*;
3075/// use fandhe_ai::data::*;
3076/// use fandhe_ai::nn::*;
3077/// use fandhe_ai::nn::init::*;
3078/// use fandhe_ai::nn::rnn::*;
3079/// use fandhe_ai::nn::kv_cache::*;
3080/// use fandhe_ai::nn::loss::*;
3081/// use fandhe_ai::interop::*;
3082/// use fandhe_ai::interop::onnx::*;
3083/// use fandhe_ai::interop::safetensors::*;
3084/// use fandhe_ai::interop::npy::*;
3085/// use fandhe_ai::model::*;
3086/// use fandhe_ai::inference::*;
3087/// use fandhe_ai::text::*;
3088/// use fandhe_ai::models::*;
3089/// use fandhe_ai::distributed::*;
3090///
3091/// struct __FandheHoldMarker;
3092///
3093/// trait __FandheHoldProbe {
3094///     fn custom(&self) -> __FandheHoldMarker;
3095///     fn add_custom(&self) -> __FandheHoldMarker;
3096/// }
3097///
3098/// impl<'t> __FandheHoldProbe for fandhe_ai::Var<'t> {
3099///     fn custom(&self) -> __FandheHoldMarker {
3100///         __FandheHoldMarker
3101///     }
3102///     fn add_custom(&self) -> __FandheHoldMarker {
3103///         __FandheHoldMarker
3104///     }
3105/// }
3106///
3107/// impl __FandheHoldProbe for fandhe_ai::Tape {
3108///     fn custom(&self) -> __FandheHoldMarker {
3109///         __FandheHoldMarker
3110///     }
3111///     fn add_custom(&self) -> __FandheHoldMarker {
3112///         __FandheHoldMarker
3113///     }
3114/// }
3115///
3116/// impl __FandheHoldProbe for fandhe_ai::compat::Sequential {
3117///     fn custom(&self) -> __FandheHoldMarker {
3118///         __FandheHoldMarker
3119///     }
3120///     fn add_custom(&self) -> __FandheHoldMarker {
3121///         __FandheHoldMarker
3122///     }
3123/// }
3124///
3125/// fn __probe_var(x: &fandhe_ai::Var<'_>) {
3126///     let _: __FandheHoldMarker = fandhe_ai::Var::custom(x);
3127///     let _: __FandheHoldMarker = x.custom();
3128///     let _: __FandheHoldMarker = fandhe_ai::Var::add_custom(x);
3129///     let _: __FandheHoldMarker = x.add_custom();
3130/// }
3131///
3132/// fn __probe_tape(x: &fandhe_ai::Tape) {
3133///     let _: __FandheHoldMarker = fandhe_ai::Tape::add_custom(x);
3134///     let _: __FandheHoldMarker = x.add_custom();
3135/// }
3136///
3137/// fn __probe_sequential(x: &fandhe_ai::compat::Sequential) {
3138///     let _: __FandheHoldMarker = fandhe_ai::compat::Sequential::custom(x);
3139///     let _: __FandheHoldMarker = x.custom();
3140///     let _: __FandheHoldMarker = fandhe_ai::compat::Sequential::add_custom(x);
3141///     let _: __FandheHoldMarker = x.add_custom();
3142/// }
3143/// ```
3144#[cfg(doctest)]
3145#[allow(dead_code)]
3146struct VarCustomHoldDoctestGuard;
3147
3148/// イシュー #2141(親 #2131)の facade 公開保留を固定する doctest 足場。
3149/// #2510(ルート #2499 一括承認)で比較 6 種(`gt_bool`/`ge_bool`/
3150/// `lt_bool`/`le_bool`/`eq_bool`/`ne_bool`)と `masked_select` の 7 件は
3151/// `Var` の委譲メソッドとして公開済みのため、本ガードが固定するのは
3152/// 次の「承認形外」の配置に絞られる:
3153///
3154/// - logical 3 種(`logical_and`/`logical_or`/`logical_not`)の `Var`
3155///   への配置(承認形は crate 直下の委譲自由関数のみ。#2596 で公開済み)
3156/// - 10 関数の `Tensor<bool>`/`Tensor<f32>`/`Tape` 上への配置
3157/// - `bool_ops` モジュールの再エクスポート・別名 `pub use`
3158///
3159/// `VarCustomHoldDoctestGuard`/`NnModuleHoldDoctestGuard`(#2396 で削除
3160/// 済み)と同型の「正のプローブ 1 ブロック方式」を採る: facade の全
3161/// `pub mod` を glob import したスコープに、本ブロック内でのみ定義した
3162/// ローカルの自由関数群(`__fandhe_bool_hold_probe::bool_ops::*`)と
3163/// トレイト(`__FandheBoolHoldProbe`)を導入し、実際に使う関数を書く。
3164/// 未承認の経路でモジュール名・関数名が公開されると、ローカル定義との
3165/// glob 衝突(モジュール名の場合)または呼び出しシグネチャの不一致
3166/// (inherent メソッドがトレイトメソッドより優先解決されるため、引数なしの
3167/// `x.logical_and()` が inherent 側に解決されて型・引数数エラーになる)で
3168/// コンパイルが失敗する。`Var` 用トレイト impl の 7 件分は inherent に
3169/// 隠れて呼ばれないが、トレイトが 10 メソッドを要求するため残す。
3170///
3171/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
3172/// bool_ops_hold_doctest_globs_all_pub_modules`・`bool_ops_hold_
3173/// doctest_probe_body_matches_fixed_contract`・`facade_declares_logical_
3174/// fns_only_as_approved_root_delegations`・`workspace_declares_bool_ops_
3175/// fn_names_in_approved_places_only`)との多層防御の位置づけは
3176/// `docs/autodiff-bool-ops-exposure-decision.md` §6「承認事項」・§6.1
3177/// を参照。
3178///
3179/// 残置の根拠(#2596。決定記録 §6.2 (d)): logical 3 種は #2596 で
3180/// `fandhe_ai::logical_*`(crate 直下の 1 式委譲 `pub fn`)として公開済み
3181/// だが、本ガードは承認形外(`Var`/`Tensor`/`Tape` 上の配置と
3182/// `bool_ops` モジュールの再エクスポート)を拒む役割で残す。プローブ本体
3183/// は経路付き(`bool_ops::logical_and()`)・メソッド形・関連関数形でのみ
3184/// 3 名を使うため、直下の同名自由関数とは衝突しない。撤去条件は `Var`
3185/// 入力版等が別途承認されガードの前提が変わったときのみ。
3186///
3187/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
3188/// できること
3189///
3190/// ```
3191/// use fandhe_ai::*;
3192/// use fandhe_ai::compat::*;
3193/// use fandhe_ai::optim::*;
3194/// use fandhe_ai::data::*;
3195/// use fandhe_ai::nn::*;
3196/// use fandhe_ai::nn::init::*;
3197/// use fandhe_ai::nn::rnn::*;
3198/// use fandhe_ai::nn::kv_cache::*;
3199/// use fandhe_ai::nn::loss::*;
3200/// use fandhe_ai::interop::*;
3201/// use fandhe_ai::interop::onnx::*;
3202/// use fandhe_ai::interop::safetensors::*;
3203/// use fandhe_ai::interop::npy::*;
3204/// use fandhe_ai::model::*;
3205/// use fandhe_ai::inference::*;
3206/// use fandhe_ai::text::*;
3207/// use fandhe_ai::models::*;
3208/// use fandhe_ai::distributed::*;
3209///
3210/// mod __fandhe_bool_hold_probe {
3211///     pub mod bool_ops {
3212///         pub fn gt_bool() {}
3213///         pub fn ge_bool() {}
3214///         pub fn lt_bool() {}
3215///         pub fn le_bool() {}
3216///         pub fn eq_bool() {}
3217///         pub fn ne_bool() {}
3218///         pub fn logical_and() {}
3219///         pub fn logical_or() {}
3220///         pub fn logical_not() {}
3221///         pub fn masked_select() {}
3222///     }
3223/// }
3224/// use __fandhe_bool_hold_probe::*;
3225///
3226/// struct __FandheBoolMarker;
3227///
3228/// trait __FandheBoolHoldProbe {
3229///     fn gt_bool(&self) -> __FandheBoolMarker;
3230///     fn ge_bool(&self) -> __FandheBoolMarker;
3231///     fn lt_bool(&self) -> __FandheBoolMarker;
3232///     fn le_bool(&self) -> __FandheBoolMarker;
3233///     fn eq_bool(&self) -> __FandheBoolMarker;
3234///     fn ne_bool(&self) -> __FandheBoolMarker;
3235///     fn logical_and(&self) -> __FandheBoolMarker;
3236///     fn logical_or(&self) -> __FandheBoolMarker;
3237///     fn logical_not(&self) -> __FandheBoolMarker;
3238///     fn masked_select(&self) -> __FandheBoolMarker;
3239/// }
3240///
3241/// impl<'t> __FandheBoolHoldProbe for fandhe_ai::Var<'t> {
3242///     fn gt_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3243///     fn ge_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3244///     fn lt_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3245///     fn le_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3246///     fn eq_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3247///     fn ne_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3248///     fn logical_and(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3249///     fn logical_or(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3250///     fn logical_not(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3251///     fn masked_select(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3252/// }
3253///
3254/// impl __FandheBoolHoldProbe for fandhe_ai::Tensor<bool> {
3255///     fn gt_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3256///     fn ge_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3257///     fn lt_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3258///     fn le_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3259///     fn eq_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3260///     fn ne_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3261///     fn logical_and(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3262///     fn logical_or(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3263///     fn logical_not(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3264///     fn masked_select(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3265/// }
3266///
3267/// impl __FandheBoolHoldProbe for fandhe_ai::Tensor<f32> {
3268///     fn gt_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3269///     fn ge_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3270///     fn lt_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3271///     fn le_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3272///     fn eq_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3273///     fn ne_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3274///     fn logical_and(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3275///     fn logical_or(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3276///     fn logical_not(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3277///     fn masked_select(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3278/// }
3279///
3280/// impl __FandheBoolHoldProbe for fandhe_ai::Tape {
3281///     fn gt_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3282///     fn ge_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3283///     fn lt_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3284///     fn le_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3285///     fn eq_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3286///     fn ne_bool(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3287///     fn logical_and(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3288///     fn logical_or(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3289///     fn logical_not(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3290///     fn masked_select(&self) -> __FandheBoolMarker { __FandheBoolMarker }
3291/// }
3292///
3293/// fn __probe_free_fns() {
3294///     // `bool_ops::` を経由した経路解決(`use fandhe_ai::*;` が
3295///     // 同名モジュールを glob 公開していれば、名前解決自体が
3296///     // 曖昧になり E0659 でコンパイル失敗する。バレ識別子の
3297///     // 未使用 glob 衝突は rustc が検出しないため、経路として
3298///     // 実際に `bool_ops` を解決させる必要がある)。
3299///     bool_ops::gt_bool();
3300///     bool_ops::ge_bool();
3301///     bool_ops::lt_bool();
3302///     bool_ops::le_bool();
3303///     bool_ops::eq_bool();
3304///     bool_ops::ne_bool();
3305///     bool_ops::logical_and();
3306///     bool_ops::logical_or();
3307///     bool_ops::logical_not();
3308///     bool_ops::masked_select();
3309/// }
3310///
3311/// fn __probe_var(x: &fandhe_ai::Var<'_>) {
3312///     let _: __FandheBoolMarker = fandhe_ai::Var::logical_and(x);
3313///     let _: __FandheBoolMarker = x.logical_and();
3314///     let _: __FandheBoolMarker = fandhe_ai::Var::logical_or(x);
3315///     let _: __FandheBoolMarker = x.logical_or();
3316///     let _: __FandheBoolMarker = fandhe_ai::Var::logical_not(x);
3317///     let _: __FandheBoolMarker = x.logical_not();
3318/// }
3319///
3320/// fn __probe_tensor_bool(x: &fandhe_ai::Tensor<bool>) {
3321///     let _: __FandheBoolMarker = fandhe_ai::Tensor::logical_and(x);
3322///     let _: __FandheBoolMarker = x.logical_and();
3323///     let _: __FandheBoolMarker = fandhe_ai::Tensor::logical_not(x);
3324///     let _: __FandheBoolMarker = x.logical_not();
3325/// }
3326///
3327/// fn __probe_tensor_f32(x: &fandhe_ai::Tensor<f32>) {
3328///     let _: __FandheBoolMarker = fandhe_ai::Tensor::gt_bool(x);
3329///     let _: __FandheBoolMarker = x.gt_bool();
3330/// }
3331///
3332/// fn __probe_tape(x: &fandhe_ai::Tape) {
3333///     let _: __FandheBoolMarker = fandhe_ai::Tape::gt_bool(x);
3334///     let _: __FandheBoolMarker = x.gt_bool();
3335/// }
3336/// ```
3337#[cfg(doctest)]
3338#[allow(dead_code)]
3339struct VarBoolOpsHoldDoctestGuard;
3340
3341/// イシュー #2139(親 #2138・#2131)の facade 公開保留を固定していた doctest
3342/// 足場。#2587 で承認形(`Tape::{register_backward_hook, remove_hook}` の薄い委譲・
3343/// `HookHandle`/`nn::ForwardHooked`/`nn::ForwardHookCtx` の公開。
3344/// `docs/autodiff-forward-backward-hooks-design.md` §14.4・§18)を公開したため
3345/// **部分反転**した(`VarBoolOpsHoldDoctestGuard`・`VarActivationOpsHoldDoctestGuard` と
3346/// 同型。名称は据え置く)。承認形の正ガードは `crates/facade/tests/api_surface.rs` の
3347/// `facade_tape_hook_methods_are_thin_delegations`・
3348/// `facade_reexports_hook_items_only_in_approved_shape`・
3349/// `hooks_are_reachable_via_facade_only` ほかが担う。本ガードは承認形**外**の配置を
3350/// 引き続き fail-closed に固定する。2 種類の衝突プローブを併用する:
3351///
3352/// (a) モジュール名の衝突プローブ。facade の全 `pub mod` を glob import したスコープに、
3353/// 本ブロック内でのみ定義したモジュール(`__fandhe_hooks_hold_probe::hooks`)を導入し、
3354/// 実際に経路として解決させる。facade が `hooks` モジュールを公開すると(P4。承認形は
3355/// `pub mod hooks` を設けない)名前解決が曖昧になり(E0659)コンパイルが失敗する。
3356/// 型名(`HookHandle`/`ForwardHooked`/`ForwardHookCtx`)の衝突プローブは、承認形として
3357/// 公開済みのため撤去した。
3358///
3359/// (b) メソッド名の衝突プローブ(`VarBoolOpsHoldDoctestGuard` 方式)。
3360/// `register_forward_hook`/`register_backward_hook`/`register_hook`/
3361/// `remove_hook`/`remove_backward_hook` の 5 メソッドをトレイト
3362/// (`__FandheHooksHoldProbe`)として `fandhe_ai::Var<'t>`/
3363/// `fandhe_ai::Tape`/`fandhe_ai::compat::Sequential` に実装し、UFCS 形・
3364/// メソッド呼び出し形の両方で呼ぶ。inherent メソッドはトレイトメソッドより優先して
3365/// 解決されるため、同名の inherent メソッドが追加されると、引数の数や型の不一致で
3366/// コンパイルが失敗する。承認形で `Tape` に載った `register_backward_hook`・
3367/// `remove_hook` の呼び出しは `__probe_tape` から外した(トレイト実装は 5 件のまま)。
3368/// `Var`・`compat::Sequential` への 5 メソッド、`Tape` への `register_forward_hook`・
3369/// `register_hook`・`remove_backward_hook`(P8。承認形外)は引き続き拒否する。
3370///
3371/// facade の `Tape` は `pub struct Tape(pub(crate) fandhe_ai_autodiff::Tape)`
3372/// という newtype で `Deref` を持たないため(`crate::tape::Tape` 参照)、
3373/// 本プローブが検出できるのは facade 側に追加されたメソッドのみである。
3374/// autodiff 側の `Tape` に追加された定義は `crates/facade/tests/
3375/// api_surface.rs::workspace_declares_hook_registration_fns_only_on_autodiff_tape_and_facade_delegation`
3376/// (workspace 全体のソース走査)が捕捉する分担とする。
3377///
3378/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
3379/// hooks_hold_doctest_globs_all_pub_modules`・`hooks_hold_doctest_probe_
3380/// body_matches_fixed_contract`)との多層防御の位置づけ・承認の経緯は
3381/// `docs/autodiff-forward-backward-hooks-design.md` §13・§18 を参照。
3382///
3383/// 撤去条件: P8 の承認外メソッド(`register_forward_hook`・`register_hook`・
3384/// `remove_backward_hook`、`Var`/`compat::Sequential` への hook 登録メソッド)や
3385/// `pub mod hooks` の公開が承認されたら、該当プローブを外す(ソース走査側の
3386/// 対応する否定ガードと同時に)。
3387///
3388/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
3389/// できること
3390///
3391/// ```
3392/// use fandhe_ai::*;
3393/// use fandhe_ai::compat::*;
3394/// use fandhe_ai::optim::*;
3395/// use fandhe_ai::data::*;
3396/// use fandhe_ai::nn::*;
3397/// use fandhe_ai::nn::init::*;
3398/// use fandhe_ai::nn::rnn::*;
3399/// use fandhe_ai::nn::kv_cache::*;
3400/// use fandhe_ai::nn::loss::*;
3401/// use fandhe_ai::interop::*;
3402/// use fandhe_ai::interop::onnx::*;
3403/// use fandhe_ai::interop::safetensors::*;
3404/// use fandhe_ai::interop::npy::*;
3405/// use fandhe_ai::model::*;
3406/// use fandhe_ai::inference::*;
3407/// use fandhe_ai::text::*;
3408/// use fandhe_ai::models::*;
3409/// use fandhe_ai::distributed::*;
3410///
3411/// mod __fandhe_hooks_hold_probe {
3412///     pub mod hooks {
3413///         pub fn __probe() {}
3414///     }
3415/// }
3416/// use __fandhe_hooks_hold_probe::*;
3417///
3418/// fn __probe_types() {
3419///     hooks::__probe();
3420/// }
3421///
3422/// struct __FandheHooksMarker;
3423///
3424/// trait __FandheHooksHoldProbe {
3425///     fn register_forward_hook(&self) -> __FandheHooksMarker;
3426///     fn register_backward_hook(&self) -> __FandheHooksMarker;
3427///     fn register_hook(&self) -> __FandheHooksMarker;
3428///     fn remove_hook(&self) -> __FandheHooksMarker;
3429///     fn remove_backward_hook(&self) -> __FandheHooksMarker;
3430/// }
3431///
3432/// impl<'t> __FandheHooksHoldProbe for fandhe_ai::Var<'t> {
3433///     fn register_forward_hook(&self) -> __FandheHooksMarker { __FandheHooksMarker }
3434///     fn register_backward_hook(&self) -> __FandheHooksMarker { __FandheHooksMarker }
3435///     fn register_hook(&self) -> __FandheHooksMarker { __FandheHooksMarker }
3436///     fn remove_hook(&self) -> __FandheHooksMarker { __FandheHooksMarker }
3437///     fn remove_backward_hook(&self) -> __FandheHooksMarker { __FandheHooksMarker }
3438/// }
3439///
3440/// impl __FandheHooksHoldProbe for fandhe_ai::Tape {
3441///     fn register_forward_hook(&self) -> __FandheHooksMarker { __FandheHooksMarker }
3442///     fn register_backward_hook(&self) -> __FandheHooksMarker { __FandheHooksMarker }
3443///     fn register_hook(&self) -> __FandheHooksMarker { __FandheHooksMarker }
3444///     fn remove_hook(&self) -> __FandheHooksMarker { __FandheHooksMarker }
3445///     fn remove_backward_hook(&self) -> __FandheHooksMarker { __FandheHooksMarker }
3446/// }
3447///
3448/// impl __FandheHooksHoldProbe for fandhe_ai::compat::Sequential {
3449///     fn register_forward_hook(&self) -> __FandheHooksMarker { __FandheHooksMarker }
3450///     fn register_backward_hook(&self) -> __FandheHooksMarker { __FandheHooksMarker }
3451///     fn register_hook(&self) -> __FandheHooksMarker { __FandheHooksMarker }
3452///     fn remove_hook(&self) -> __FandheHooksMarker { __FandheHooksMarker }
3453///     fn remove_backward_hook(&self) -> __FandheHooksMarker { __FandheHooksMarker }
3454/// }
3455///
3456/// fn __probe_var(x: &fandhe_ai::Var<'_>) {
3457///     let _: __FandheHooksMarker = fandhe_ai::Var::register_forward_hook(x);
3458///     let _: __FandheHooksMarker = x.register_forward_hook();
3459///     let _: __FandheHooksMarker = fandhe_ai::Var::register_backward_hook(x);
3460///     let _: __FandheHooksMarker = x.register_backward_hook();
3461///     let _: __FandheHooksMarker = fandhe_ai::Var::register_hook(x);
3462///     let _: __FandheHooksMarker = x.register_hook();
3463///     let _: __FandheHooksMarker = fandhe_ai::Var::remove_hook(x);
3464///     let _: __FandheHooksMarker = x.remove_hook();
3465///     let _: __FandheHooksMarker = fandhe_ai::Var::remove_backward_hook(x);
3466///     let _: __FandheHooksMarker = x.remove_backward_hook();
3467/// }
3468///
3469/// fn __probe_tape(x: &fandhe_ai::Tape) {
3470///     let _: __FandheHooksMarker = fandhe_ai::Tape::register_forward_hook(x);
3471///     let _: __FandheHooksMarker = x.register_forward_hook();
3472///     let _: __FandheHooksMarker = fandhe_ai::Tape::register_hook(x);
3473///     let _: __FandheHooksMarker = x.register_hook();
3474///     let _: __FandheHooksMarker = fandhe_ai::Tape::remove_backward_hook(x);
3475///     let _: __FandheHooksMarker = x.remove_backward_hook();
3476/// }
3477///
3478/// fn __probe_sequential(x: &fandhe_ai::compat::Sequential) {
3479///     let _: __FandheHooksMarker = fandhe_ai::compat::Sequential::register_forward_hook(x);
3480///     let _: __FandheHooksMarker = x.register_forward_hook();
3481///     let _: __FandheHooksMarker = fandhe_ai::compat::Sequential::register_backward_hook(x);
3482///     let _: __FandheHooksMarker = x.register_backward_hook();
3483///     let _: __FandheHooksMarker = fandhe_ai::compat::Sequential::register_hook(x);
3484///     let _: __FandheHooksMarker = x.register_hook();
3485///     let _: __FandheHooksMarker = fandhe_ai::compat::Sequential::remove_hook(x);
3486///     let _: __FandheHooksMarker = x.remove_hook();
3487///     let _: __FandheHooksMarker = fandhe_ai::compat::Sequential::remove_backward_hook(x);
3488///     let _: __FandheHooksMarker = x.remove_backward_hook();
3489/// }
3490/// ```
3491#[cfg(doctest)]
3492#[allow(dead_code)]
3493struct VarHooksHoldDoctestGuard;
3494
3495/// イシュー #2146(親 #2131)の facade 公開のうち、承認形外の配置を引き続き
3496/// 固定する doctest 足場(#2516 で `Var` 委譲メソッド 5 件を公開したため部分反転。
3497/// `VarBoolOpsHoldDoctestGuard` と同じ #2510 型の部分反転)。承認形は
3498/// `Var::{mish, hardtanh, relu6, prelu, glu}` の 1 行委譲のみで、その正ガードは
3499/// `crates/facade/tests/api_surface.rs::var_activation_ops_methods_are_thin_delegations`・
3500/// `var_activation_ops_are_reachable_via_facade_only` が担う。本ガードは 2 種類の
3501/// 衝突プローブを併用する(`VarHooksHoldDoctestGuard` と同じ理由):
3502///
3503/// (a) 承認形外の配置の衝突プローブ。facade の全 `pub mod` を glob import した
3504/// スコープに、本ブロック内でのみ定義したローカルの自由関数群
3505/// (`__fandhe_activation_hold_probe::activation_ops::{mish, hardtanh,
3506/// relu6, prelu, glu}`)とトレイト(`__FandheActivationHoldProbe`)を
3507/// 導入し、`Tensor<f32>`/`Tape` に実装して実際に使う。facade が
3508/// `activation_ops` というモジュール名や 5 個の関数名を `Tensor<f32>`/`Tape`
3509/// 上へ公開しても、ローカル定義との glob 衝突、または呼び出しシグネチャの
3510/// 不一致(inherent メソッドがトレイトメソッドより優先解決されるため)で
3511/// コンパイルが失敗する。`Var` への実装と `__probe_var` は、`Var` に inherent
3512/// メソッドが載ったことで引数なし呼び出しが inherent 側へ解決され型エラーに
3513/// なるため削除した。
3514///
3515/// (b) `compat::Sequential::add_*` 5 種は #2529 で承認形(`add_mish`・
3516/// `add_hardtanh`・`add_relu6`・`add_glu`・`add_prelu`)として公開済みのため、
3517/// 衝突プローブ(`__FandheActivationAddProbe`)は撤去した。承認形の正ガードは
3518/// `crates/facade/tests/api_surface.rs::
3519/// compat_sequential_activation_layers_add_methods_have_approved_signatures` が担う。
3520///
3521/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
3522/// activation_ops_hold_doctest_globs_all_pub_modules`・
3523/// `activation_ops_hold_doctest_probe_body_matches_fixed_contract`・
3524/// `facade_does_not_reexport_or_declare_activation_ops`・
3525/// `workspace_declares_activation_ops_fn_names_only_in_approved_locations`)
3526/// との多層防御の位置づけは `docs/autodiff-activation-ops-decision.md` §6
3527/// 「承認事項」を参照。
3528///
3529/// 撤去条件: `activation_ops` モジュールの再エクスポート・`Tensor<f32>`/`Tape` 上への
3530/// 配置が承認されたら、本 doctest 自体を削除する(ソース走査側の対応する否定ガードと
3531/// 同時に外す)。`compat::Sequential::add_*` の部分は #2529 で正ガードへ反転済み
3532/// (#2528 の `DropoutEmbeddingBagHoldDoctestGuard` 縮小と同じ部分反転)。
3533///
3534/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
3535/// できること
3536///
3537/// ```
3538/// use fandhe_ai::*;
3539/// use fandhe_ai::compat::*;
3540/// use fandhe_ai::optim::*;
3541/// use fandhe_ai::data::*;
3542/// use fandhe_ai::nn::*;
3543/// use fandhe_ai::nn::init::*;
3544/// use fandhe_ai::nn::rnn::*;
3545/// use fandhe_ai::nn::kv_cache::*;
3546/// use fandhe_ai::nn::loss::*;
3547/// use fandhe_ai::interop::*;
3548/// use fandhe_ai::interop::onnx::*;
3549/// use fandhe_ai::interop::safetensors::*;
3550/// use fandhe_ai::interop::npy::*;
3551/// use fandhe_ai::model::*;
3552/// use fandhe_ai::inference::*;
3553/// use fandhe_ai::text::*;
3554/// use fandhe_ai::models::*;
3555/// use fandhe_ai::distributed::*;
3556///
3557/// mod __fandhe_activation_hold_probe {
3558///     pub mod activation_ops {
3559///         pub fn mish() {}
3560///         pub fn hardtanh() {}
3561///         pub fn relu6() {}
3562///         pub fn prelu() {}
3563///         pub fn glu() {}
3564///     }
3565/// }
3566/// use __fandhe_activation_hold_probe::*;
3567///
3568/// struct __FandheActivationMarker;
3569///
3570/// trait __FandheActivationHoldProbe {
3571///     fn mish(&self) -> __FandheActivationMarker;
3572///     fn hardtanh(&self) -> __FandheActivationMarker;
3573///     fn relu6(&self) -> __FandheActivationMarker;
3574///     fn prelu(&self) -> __FandheActivationMarker;
3575///     fn glu(&self) -> __FandheActivationMarker;
3576/// }
3577///
3578/// impl __FandheActivationHoldProbe for fandhe_ai::Tensor<f32> {
3579///     fn mish(&self) -> __FandheActivationMarker { __FandheActivationMarker }
3580///     fn hardtanh(&self) -> __FandheActivationMarker { __FandheActivationMarker }
3581///     fn relu6(&self) -> __FandheActivationMarker { __FandheActivationMarker }
3582///     fn prelu(&self) -> __FandheActivationMarker { __FandheActivationMarker }
3583///     fn glu(&self) -> __FandheActivationMarker { __FandheActivationMarker }
3584/// }
3585///
3586/// impl __FandheActivationHoldProbe for fandhe_ai::Tape {
3587///     fn mish(&self) -> __FandheActivationMarker { __FandheActivationMarker }
3588///     fn hardtanh(&self) -> __FandheActivationMarker { __FandheActivationMarker }
3589///     fn relu6(&self) -> __FandheActivationMarker { __FandheActivationMarker }
3590///     fn prelu(&self) -> __FandheActivationMarker { __FandheActivationMarker }
3591///     fn glu(&self) -> __FandheActivationMarker { __FandheActivationMarker }
3592/// }
3593///
3594/// fn __probe_free_fns() {
3595///     // `activation_ops::` を経由した経路解決(`use fandhe_ai::*;` が
3596///     // 同名モジュールを glob 公開していれば、名前解決自体が曖昧に
3597///     // なり E0659 でコンパイル失敗する)。
3598///     activation_ops::mish();
3599///     activation_ops::hardtanh();
3600///     activation_ops::relu6();
3601///     activation_ops::prelu();
3602///     activation_ops::glu();
3603/// }
3604///
3605/// fn __probe_tensor_f32(x: &fandhe_ai::Tensor<f32>) {
3606///     let _: __FandheActivationMarker = fandhe_ai::Tensor::hardtanh(x);
3607///     let _: __FandheActivationMarker = x.hardtanh();
3608/// }
3609///
3610/// fn __probe_tape(x: &fandhe_ai::Tape) {
3611///     let _: __FandheActivationMarker = fandhe_ai::Tape::prelu(x);
3612///     let _: __FandheActivationMarker = x.prelu();
3613/// }
3614/// ```
3615#[cfg(doctest)]
3616#[allow(dead_code)]
3617struct VarActivationOpsHoldDoctestGuard;
3618
3619/// イシュー #2156(親 #2131)の RNG 分布・`Generator` の facade 公開を
3620/// 巡る doctest 足場。自由関数 `bernoulli`/`multinomial`/`normal` と
3621/// `Generator` は**イシュー #2593 で承認形(crate ルートの委譲 `pub fn`
3622/// 3 件と `pub use fandhe_ai_tensor_core::Generator;` 1 行。承認の根拠は
3623/// ルート #2499 のコメント)として公開済み**のため、旧保留版にあった
3624/// ローカル定義との glob 衝突プローブと入れ子スコープは撤去した。
3625/// 本ガードは、`Var`/`Tensor<f32>` に同名の inherent メソッド
3626/// (`bernoulli`/`multinomial`/`normal`)が追加されること(承認外。
3627/// `docs/rng-distributions-generator-decision.md` §5.1.3 P4)だけを検出する
3628/// 「正のプローブ 1 ブロック方式」を維持する: facade の全 `pub mod` を
3629/// glob import したスコープに、トレイト(`__FandheRngDistHoldProbe`)を
3630/// 導入しメソッド/パス構文で呼ぶ。inherent メソッドはトレイトメソッドより
3631/// 優先解決されるため、実際に追加されると引数数・型の不一致でコンパイルが
3632/// 失敗する。メソッド/パス構文のため、ルートの `normal` と
3633/// `nn::init::normal` を両方 glob しても曖昧にならない。
3634///
3635/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
3636/// rng_distributions_hold_doctest_globs_all_pub_modules`・`rng_
3637/// distributions_hold_doctest_probe_body_matches_fixed_contract`・
3638/// `facade_declares_rng_distributions_only_as_approved_root_delegations`・
3639/// `workspace_declares_rng_distribution_names_only_in_allowed_locations`)
3640/// との多層防御の位置づけ・承認の経緯は
3641/// `docs/rng-distributions-generator-decision.md` §5 を参照。
3642///
3643/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
3644/// できること
3645///
3646/// ```
3647/// use fandhe_ai::*;
3648/// use fandhe_ai::compat::*;
3649/// use fandhe_ai::optim::*;
3650/// use fandhe_ai::data::*;
3651/// use fandhe_ai::nn::*;
3652/// use fandhe_ai::nn::init::*;
3653/// use fandhe_ai::nn::rnn::*;
3654/// use fandhe_ai::nn::kv_cache::*;
3655/// use fandhe_ai::nn::loss::*;
3656/// use fandhe_ai::interop::*;
3657/// use fandhe_ai::interop::onnx::*;
3658/// use fandhe_ai::interop::safetensors::*;
3659/// use fandhe_ai::interop::npy::*;
3660/// use fandhe_ai::model::*;
3661/// use fandhe_ai::inference::*;
3662/// use fandhe_ai::text::*;
3663/// use fandhe_ai::models::*;
3664/// use fandhe_ai::distributed::*;
3665///
3666/// struct __FandheRngDistMarker;
3667///
3668/// trait __FandheRngDistHoldProbe {
3669///     fn bernoulli(&self) -> __FandheRngDistMarker;
3670///     fn multinomial(&self) -> __FandheRngDistMarker;
3671///     fn normal(&self) -> __FandheRngDistMarker;
3672/// }
3673///
3674/// impl<'t> __FandheRngDistHoldProbe for fandhe_ai::Var<'t> {
3675///     fn bernoulli(&self) -> __FandheRngDistMarker { __FandheRngDistMarker }
3676///     fn multinomial(&self) -> __FandheRngDistMarker { __FandheRngDistMarker }
3677///     fn normal(&self) -> __FandheRngDistMarker { __FandheRngDistMarker }
3678/// }
3679///
3680/// impl __FandheRngDistHoldProbe for fandhe_ai::Tensor<f32> {
3681///     fn bernoulli(&self) -> __FandheRngDistMarker { __FandheRngDistMarker }
3682///     fn multinomial(&self) -> __FandheRngDistMarker { __FandheRngDistMarker }
3683///     fn normal(&self) -> __FandheRngDistMarker { __FandheRngDistMarker }
3684/// }
3685///
3686/// fn __probe_var(x: &fandhe_ai::Var<'_>) {
3687///     let _: __FandheRngDistMarker = fandhe_ai::Var::bernoulli(x);
3688///     let _: __FandheRngDistMarker = x.bernoulli();
3689///     let _: __FandheRngDistMarker = fandhe_ai::Var::normal(x);
3690///     let _: __FandheRngDistMarker = x.normal();
3691/// }
3692///
3693/// fn __probe_tensor_f32(x: &fandhe_ai::Tensor<f32>) {
3694///     let _: __FandheRngDistMarker = fandhe_ai::Tensor::multinomial(x);
3695///     let _: __FandheRngDistMarker = x.multinomial();
3696/// }
3697/// ```
3698#[cfg(doctest)]
3699#[allow(dead_code)]
3700struct RngDistributionsHoldDoctestGuard;
3701
3702/// イシュー #2159(親 #2131。設計正本 `docs/autodiff-spatial-layers-
3703/// decision.md` §6 承認事項 1)の facade 公開保留を固定する doctest
3704/// 足場。`KvCacheHoldDoctestGuard`(#2084。#2579 で削除済み)と同型の「正のプローブ 1
3705/// ブロック方式」を採る。**イシュー #2522 で `add_upsample`/
3706/// `add_zero_pad2d`/`add_identity` の 3 メソッドは承認・公開済み**のため
3707/// メソッド/自由関数プローブから外した(型名 `Upsample`/`ZeroPad2d`/
3708/// `Identity` の再エクスポートは未承認のため型名プローブは維持する。
3709/// 公開済み 3 メソッドは `api_surface.rs::compat_sequential_exposes_
3710/// spatial_layer_add_methods_issue_2522` が正ガードで固定する)。残る保留は
3711/// `ConvTranspose1d`/`Unflatten` 系と 5 型名。facade の全 `pub mod` を
3712/// glob import したスコープに、本ブロック内でのみ定義したローカル
3713/// `__fandhe_spatial_hold_probe::{ConvTranspose1d, Upsample, ZeroPad2d,
3714/// Identity, Unflatten, add_conv_transpose1d, add_unflatten}` を導入し、実際に使う
3715/// 関数を書く。facade がどの経路(単一行・複数行・ネストした group で
3716/// の `pub use`・別名エクスポート・facade 独自の `struct`/`type`
3717/// 宣言・`compat::Sequential`/`Var` への inherent メソッド追加)でこれら
3718/// の名前を公開しても、ローカル定義との glob 衝突(型名の場合。E0659
3719/// 等)または呼び出しシグネチャの不一致(`compat::Sequential`/`Var`
3720/// への inherent メソッドはトレイトメソッドより優先解決されるため、
3721/// 本プローブの trait 経由呼び出しが型・引数不一致でコンパイル失敗
3722/// する)でエラーコードに依存せずコンパイルが失敗する。
3723///
3724/// **イシュー #2521・#2522 での更新**: 5 層すべての `add_*`/`Var` メソッド
3725/// (`add_conv_transpose1d`/`add_unflatten`/`add_upsample`/`add_zero_pad2d`/
3726/// `add_identity`・`Var::conv_transpose1d`/`Var::unflatten`)は承認形として
3727/// 公開済みのため、trait 経由プローブ(`__FandheSpatialAddProbe`・
3728/// `__FandheSpatialVarProbe`)は本ブロックから外した(承認形だけを許す正ガードは
3729/// `api_surface.rs` の `*_spatial_*` テスト群)。型名の衝突プローブと自由関数の
3730/// プローブは、型の再エクスポート・自由関数での公開が未承認のまま残るため維持する。
3731///
3732/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
3733/// spatial_layers_hold_doctest_globs_all_pub_modules`・`spatial_
3734/// layers_hold_doctest_probe_body_matches_fixed_contract`)との
3735/// 多層防御の位置づけ・承認未取得の経緯は
3736/// `docs/autodiff-spatial-layers-decision.md` §6「承認事項」節を参照。
3737///
3738/// 型の再エクスポート・自由関数での公開は引き続き未承認のため、型名・自由関数の
3739/// 衝突プローブのみを本 doctest に残す。
3740///
3741/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
3742/// できること
3743///
3744/// ```
3745/// use fandhe_ai::*;
3746/// use fandhe_ai::compat::*;
3747/// use fandhe_ai::optim::*;
3748/// use fandhe_ai::data::*;
3749/// use fandhe_ai::nn::*;
3750/// use fandhe_ai::nn::init::*;
3751/// use fandhe_ai::nn::rnn::*;
3752/// use fandhe_ai::nn::kv_cache::*;
3753/// use fandhe_ai::nn::loss::*;
3754/// use fandhe_ai::interop::*;
3755/// use fandhe_ai::interop::onnx::*;
3756/// use fandhe_ai::interop::safetensors::*;
3757/// use fandhe_ai::interop::npy::*;
3758/// use fandhe_ai::model::*;
3759/// use fandhe_ai::inference::*;
3760/// use fandhe_ai::text::*;
3761/// use fandhe_ai::models::*;
3762/// use fandhe_ai::distributed::*;
3763///
3764/// mod __fandhe_spatial_hold_probe {
3765///     pub struct ConvTranspose1d;
3766///     pub struct Upsample;
3767///     pub struct ZeroPad2d;
3768///     pub struct Identity;
3769///     pub struct Unflatten;
3770///     pub struct __FandheSpatialHoldMarker;
3771///     pub fn add_conv_transpose1d() -> __FandheSpatialHoldMarker {
3772///         __FandheSpatialHoldMarker
3773///     }
3774///     pub fn add_unflatten() -> __FandheSpatialHoldMarker {
3775///         __FandheSpatialHoldMarker
3776///     }
3777/// }
3778/// use __fandhe_spatial_hold_probe::*;
3779///
3780/// fn __probe(
3781///     _: ConvTranspose1d,
3782///     _: Upsample,
3783///     _: ZeroPad2d,
3784///     _: Identity,
3785///     _: Unflatten,
3786/// ) {
3787///     let _: __FandheSpatialHoldMarker = add_conv_transpose1d();
3788///     let _: __FandheSpatialHoldMarker = add_unflatten();
3789/// }
3790/// ```
3791#[cfg(doctest)]
3792#[allow(dead_code)]
3793struct SpatialLayersHoldDoctestGuard;
3794
3795/// イシュー #2158(親 #2131)の facade 公開保留を固定する doctest 足場。
3796/// イシュー #2524(ルート #2499 の一括承認)で `Var::conv3d`(委譲メソッド)と
3797/// `compat::Sequential::add_conv3d` の 2 形を公開したため、本ガードは
3798/// **承認済みの 2 形のプローブだけを外して縮小**し、承認外の形への衝突
3799/// プローブを残している(#2716 の `SpatialLayersHoldDoctestGuard` と同じ判断)。
3800/// `VarActivationOpsHoldDoctestGuard`(イシュー #2146)と同型の「正の
3801/// プローブ 1 ブロック方式」を採り、2 種類の衝突プローブを併用する:
3802///
3803/// (a) 自由関数の衝突プローブ(`conv3d_ops::conv3d`。`VarActivationOps
3804/// HoldDoctestGuard` の `__probe_free_fns` と同方式)。facade の全
3805/// `pub mod` を glob import したスコープに、本ブロック内でのみ定義した
3806/// ローカルの自由関数(`__fandhe_conv3d_hold_probe::conv3d_ops::
3807/// conv3d`)を導入し、`conv3d_ops::conv3d()` という経路解決で使う。
3808/// facade が `pub use fandhe_ai_autodiff::conv3d_ops;` のようなモジュール
3809/// 再エクスポートで `conv3d_ops` を公開すれば、ローカル定義との glob
3810/// 衝突(E0659)でコンパイルが失敗する(承認範囲外のため引き続き禁止)。
3811///
3812/// (b) `Tensor<f32>`/`Tape` への `conv3d` メソッド衝突プローブ
3813/// (`__FandheConv3dHoldProbe` トレイト。`VarActivationOpsHoldDoctestGuard`
3814/// の `__FandheActivationHoldProbe` と同方式)。`Tensor::conv3d`/
3815/// `Tape::conv3d` の inherent メソッドが追加されれば、トレイトメソッドより
3816/// 優先解決されるため戻り値型が `__FandheConv3dMarker` ではなくなり型エラー
3817/// になる(`Var::conv3d` は承認済みのためプローブから外した)。
3818///
3819/// 撤去した項目(イシュー #2524 で承認・公開済み。以降の正ガードは
3820/// `api_surface.rs` の `add_conv3d_signature_matches_approved_contract` 等が担う):
3821/// `Var` への `__FandheConv3dHoldProbe` impl と `__probe_var`、
3822/// `__FandheConv3dAddProbe` トレイトと `__probe_sequential_add`。
3823///
3824/// facade の `nn` は `pub mod rnn;` にのみ固定済み
3825/// (`nn_mod_declares_only_rnn_submodule`)のため、`Conv3d` 型自体の
3826/// glob 衝突プローブは不要(`nn::Conv3d` を追加しても `nn` モジュール
3827/// 自体の公開面〈`pub mod rnn;` のみ〉には現れない)。
3828///
3829/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
3830/// conv3d_hold_doctest_globs_all_pub_modules`・`conv3d_hold_doctest_
3831/// probe_body_matches_fixed_contract`・`facade_declares_conv3d_names_only_
3832/// in_approved_form`・`workspace_declares_conv3d_fn_names_only_in_
3833/// allowed_locations`)との多層防御の位置づけは `docs/conv-ops-
3834/// design.md` §16.7 を参照。
3835///
3836/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
3837/// できること
3838///
3839/// ```
3840/// use fandhe_ai::*;
3841/// use fandhe_ai::compat::*;
3842/// use fandhe_ai::optim::*;
3843/// use fandhe_ai::data::*;
3844/// use fandhe_ai::nn::*;
3845/// use fandhe_ai::nn::init::*;
3846/// use fandhe_ai::nn::rnn::*;
3847/// use fandhe_ai::nn::kv_cache::*;
3848/// use fandhe_ai::nn::loss::*;
3849/// use fandhe_ai::interop::*;
3850/// use fandhe_ai::interop::onnx::*;
3851/// use fandhe_ai::interop::safetensors::*;
3852/// use fandhe_ai::interop::npy::*;
3853/// use fandhe_ai::model::*;
3854/// use fandhe_ai::inference::*;
3855/// use fandhe_ai::text::*;
3856/// use fandhe_ai::models::*;
3857/// use fandhe_ai::distributed::*;
3858///
3859/// mod __fandhe_conv3d_hold_probe {
3860///     pub mod conv3d_ops {
3861///         pub fn conv3d() {}
3862///     }
3863/// }
3864/// use __fandhe_conv3d_hold_probe::*;
3865///
3866/// struct __FandheConv3dMarker;
3867///
3868/// trait __FandheConv3dHoldProbe {
3869///     fn conv3d(&self) -> __FandheConv3dMarker;
3870/// }
3871///
3872/// impl __FandheConv3dHoldProbe for fandhe_ai::Tensor<f32> {
3873///     fn conv3d(&self) -> __FandheConv3dMarker { __FandheConv3dMarker }
3874/// }
3875///
3876/// impl __FandheConv3dHoldProbe for fandhe_ai::Tape {
3877///     fn conv3d(&self) -> __FandheConv3dMarker { __FandheConv3dMarker }
3878/// }
3879///
3880/// fn __probe_free_fns() {
3881///     // `conv3d_ops::` を経由した経路解決(`use fandhe_ai::*;` が
3882///     // 同名モジュールを glob 公開していれば、名前解決自体が曖昧に
3883///     // なり E0659 でコンパイル失敗する)。
3884///     conv3d_ops::conv3d();
3885/// }
3886///
3887/// fn __probe_tensor_f32(x: &fandhe_ai::Tensor<f32>) {
3888///     let _: __FandheConv3dMarker = fandhe_ai::Tensor::conv3d(x);
3889///     let _: __FandheConv3dMarker = x.conv3d();
3890/// }
3891///
3892/// fn __probe_tape(x: &fandhe_ai::Tape) {
3893///     let _: __FandheConv3dMarker = fandhe_ai::Tape::conv3d(x);
3894///     let _: __FandheConv3dMarker = x.conv3d();
3895/// }
3896/// ```
3897#[cfg(doctest)]
3898#[allow(dead_code)]
3899struct VarConv3dHoldDoctestGuard;
3900
3901/// イシュー #2160(親 #2131)の facade 公開保留のうち、イシュー #2527
3902/// (親 #2520・ルート #2499 の一括承認)の後も残る分を固定する doctest
3903/// 足場。`VarConv3dHoldDoctestGuard`(#2524 の縮小形)と同型の「正のプローブ
3904/// 1 ブロック方式」を採る。
3905///
3906/// イシュー #2527 で公開済みの `Var::adaptive_max_pool2d`/
3907/// `adaptive_max_pool1d`・`compat::Sequential::add_adaptive_max_pool2d`/
3908/// `add_adaptive_max_pool1d`/`add_global_pool` のプローブ(inherent メソッド
3909/// 追加を trait 経由呼び出しの不一致で検出していた
3910/// `__FandheAdaptiveMaxPoolAddProbe` と `__probe_var`/
3911/// `__probe_sequential_add`)は撤去した。これらの承認形(定義元集合・1 行
3912/// 委譲本体・シグネチャ・実値)は `crates/facade/tests/api_surface.rs` の
3913/// 正ガード群(`workspace_declares_adaptive_max_global_pool_facade_fn_names_
3914/// only_in_approved_locations` ほか)が固定する。
3915///
3916/// まだ承認していない `Tensor<f32>`/`Tape` への同名メソッド追加は、
3917/// `__FandheAdaptiveMaxPoolHoldProbe` トレイトの衝突プローブ(inherent
3918/// メソッドはトレイトメソッドより優先解決されるため、追加されれば戻り値型が
3919/// `__FandheAdaptiveMaxPoolMarker` ではなくなり型エラーになる)で引き続き
3920/// 禁止する。層型(`AdaptiveMaxPool2d`/`AdaptiveMaxPool1d`/`GlobalPool`)の
3921/// facade 再エクスポートは未承認で、`api_surface.rs` の
3922/// `facade_reexports_global_pool_mode_only_in_approved_shape` が固定する
3923/// (facade の `nn` は `pub mod rnn;` にのみ固定済みのため glob 衝突プローブは
3924/// 不要。`GlobalPoolMode` だけがルート再エクスポートの承認対象)。
3925///
3926/// ソース走査ガード(`api_surface.rs::adaptive_max_global_pool_hold_doctest_
3927/// globs_all_pub_modules`・`adaptive_max_global_pool_hold_doctest_probe_body_
3928/// matches_fixed_contract`)との多層防御の位置づけ・承認の経緯は
3929/// `docs/autodiff-adaptive-max-global-pool-decision.md` §6・§8 を参照。
3930///
3931/// `Tensor<f32>`/`Tape` への追加が承認される日が来たら、本モジュール・本
3932/// doctest 自体を削除する(対応する固定文言も同時に正ガードへ置き換える)。
3933///
3934/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
3935/// できること
3936///
3937/// ```
3938/// use fandhe_ai::*;
3939/// use fandhe_ai::compat::*;
3940/// use fandhe_ai::optim::*;
3941/// use fandhe_ai::data::*;
3942/// use fandhe_ai::nn::*;
3943/// use fandhe_ai::nn::init::*;
3944/// use fandhe_ai::nn::rnn::*;
3945/// use fandhe_ai::nn::kv_cache::*;
3946/// use fandhe_ai::nn::loss::*;
3947/// use fandhe_ai::interop::*;
3948/// use fandhe_ai::interop::onnx::*;
3949/// use fandhe_ai::interop::safetensors::*;
3950/// use fandhe_ai::interop::npy::*;
3951/// use fandhe_ai::model::*;
3952/// use fandhe_ai::inference::*;
3953/// use fandhe_ai::text::*;
3954/// use fandhe_ai::models::*;
3955/// use fandhe_ai::distributed::*;
3956///
3957/// struct __FandheAdaptiveMaxPoolMarker;
3958///
3959/// trait __FandheAdaptiveMaxPoolHoldProbe {
3960///     fn adaptive_max_pool2d(&self) -> __FandheAdaptiveMaxPoolMarker;
3961///     fn adaptive_max_pool1d(&self) -> __FandheAdaptiveMaxPoolMarker;
3962/// }
3963///
3964/// impl __FandheAdaptiveMaxPoolHoldProbe for fandhe_ai::Tensor<f32> {
3965///     fn adaptive_max_pool2d(&self) -> __FandheAdaptiveMaxPoolMarker { __FandheAdaptiveMaxPoolMarker }
3966///     fn adaptive_max_pool1d(&self) -> __FandheAdaptiveMaxPoolMarker { __FandheAdaptiveMaxPoolMarker }
3967/// }
3968///
3969/// impl __FandheAdaptiveMaxPoolHoldProbe for fandhe_ai::Tape {
3970///     fn adaptive_max_pool2d(&self) -> __FandheAdaptiveMaxPoolMarker { __FandheAdaptiveMaxPoolMarker }
3971///     fn adaptive_max_pool1d(&self) -> __FandheAdaptiveMaxPoolMarker { __FandheAdaptiveMaxPoolMarker }
3972/// }
3973///
3974/// fn __probe_tensor_f32(x: &fandhe_ai::Tensor<f32>) {
3975///     let _: __FandheAdaptiveMaxPoolMarker = fandhe_ai::Tensor::adaptive_max_pool2d(x);
3976///     let _: __FandheAdaptiveMaxPoolMarker = x.adaptive_max_pool2d();
3977///     let _: __FandheAdaptiveMaxPoolMarker = fandhe_ai::Tensor::adaptive_max_pool1d(x);
3978///     let _: __FandheAdaptiveMaxPoolMarker = x.adaptive_max_pool1d();
3979/// }
3980///
3981/// fn __probe_tape(x: &fandhe_ai::Tape) {
3982///     let _: __FandheAdaptiveMaxPoolMarker = fandhe_ai::Tape::adaptive_max_pool2d(x);
3983///     let _: __FandheAdaptiveMaxPoolMarker = x.adaptive_max_pool2d();
3984///     let _: __FandheAdaptiveMaxPoolMarker = fandhe_ai::Tape::adaptive_max_pool1d(x);
3985///     let _: __FandheAdaptiveMaxPoolMarker = x.adaptive_max_pool1d();
3986/// }
3987/// ```
3988#[cfg(doctest)]
3989#[allow(dead_code)]
3990struct AdaptiveMaxGlobalPoolHoldDoctestGuard;
3991
3992/// イシュー #2161(親 #2131。設計正本 `docs/autodiff-dropout-embedding-
3993/// bag-decision.md` §6 承認事項)の facade 公開保留のうち、イシュー #2528
3994/// (親 #2520・ルート #2499 の一括承認)の後も残る分を固定する doctest
3995/// 足場。`PixelShuffleHoldDoctestGuard`(#2526 の縮小形)と同型の「正の
3996/// プローブ 1 ブロック方式」を採る: facade の全 `pub mod` を glob
3997/// import したスコープに、本ブロック内でのみ定義したローカル
3998/// `__fandhe_dropout_embedding_bag_hold_probe::{Dropout2d, AlphaDropout,
3999/// EmbeddingBag, EmbeddingBagVars, add_dropout2d, add_alpha_dropout,
4000/// add_embedding_bag}` を導入し、実際に使う関数を書く。facade がどの経路
4001/// (`pub use`・別名エクスポート・facade 独自の `struct`/`type` 宣言・
4002/// 自由関数での公開)でこれらの名前を公開しても、ローカル定義との glob
4003/// 衝突でエラーコードに依存せずコンパイルが失敗する。
4004///
4005/// イシュー #2528 で公開済みの `compat::Sequential::add_dropout2d`/
4006/// `add_alpha_dropout`/`add_embedding_bag`・`Var::dropout2d`/
4007/// `alpha_dropout`/`embedding_bag`・ルートの `EmbeddingBagMode` 再エクスポート
4008/// のプローブ(inherent メソッド追加を trait 経由呼び出しの不一致で検出して
4009/// いた `__FandheDropoutEmbeddingBagAddProbe`/`__FandheDropoutEmbeddingBagVarProbe`
4010/// と `seq.*`/`v.*` の呼び出し・`EmbeddingBagMode` の型プローブ)は撤去した。
4011/// これらの承認形(定義元集合・1 行委譲本体・シグネチャ・再エクスポート形・
4012/// 実値)は `crates/facade/tests/api_surface.rs` の正ガード群
4013/// (`workspace_declares_dropout_embedding_bag_facade_fn_names_only_in_
4014/// approved_locations` ほか)が固定する。層型の再エクスポートと自由関数での
4015/// 公開は未承認のため、本プローブで引き続き禁止する。
4016///
4017/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
4018/// dropout_embedding_bag_hold_doctest_globs_all_pub_modules`・
4019/// `dropout_embedding_bag_hold_doctest_probe_body_matches_fixed_
4020/// contract`)との多層防御の位置づけ・承認の経緯は
4021/// `docs/autodiff-dropout-embedding-bag-decision.md` §6・§8 を参照。
4022///
4023/// 層型の再エクスポート・自由関数公開が承認される日が来たら、本モジュール・
4024/// 本 doctest 自体を削除する(対応する固定文言も同時に正ガードへ置き換える)。
4025///
4026/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
4027/// できること
4028///
4029/// ```
4030/// use fandhe_ai::*;
4031/// use fandhe_ai::compat::*;
4032/// use fandhe_ai::optim::*;
4033/// use fandhe_ai::data::*;
4034/// use fandhe_ai::nn::*;
4035/// use fandhe_ai::nn::init::*;
4036/// use fandhe_ai::nn::rnn::*;
4037/// use fandhe_ai::nn::kv_cache::*;
4038/// use fandhe_ai::nn::loss::*;
4039/// use fandhe_ai::interop::*;
4040/// use fandhe_ai::interop::onnx::*;
4041/// use fandhe_ai::interop::safetensors::*;
4042/// use fandhe_ai::interop::npy::*;
4043/// use fandhe_ai::model::*;
4044/// use fandhe_ai::inference::*;
4045/// use fandhe_ai::text::*;
4046/// use fandhe_ai::models::*;
4047/// use fandhe_ai::distributed::*;
4048///
4049/// mod __fandhe_dropout_embedding_bag_hold_probe {
4050///     pub struct Dropout2d;
4051///     pub struct AlphaDropout;
4052///     pub struct EmbeddingBag;
4053///     pub struct EmbeddingBagVars;
4054///     pub struct __FandheDropoutEmbeddingBagHoldMarker;
4055///     pub fn add_dropout2d() -> __FandheDropoutEmbeddingBagHoldMarker {
4056///         __FandheDropoutEmbeddingBagHoldMarker
4057///     }
4058///     pub fn add_alpha_dropout() -> __FandheDropoutEmbeddingBagHoldMarker {
4059///         __FandheDropoutEmbeddingBagHoldMarker
4060///     }
4061///     pub fn add_embedding_bag() -> __FandheDropoutEmbeddingBagHoldMarker {
4062///         __FandheDropoutEmbeddingBagHoldMarker
4063///     }
4064/// }
4065/// use __fandhe_dropout_embedding_bag_hold_probe::*;
4066///
4067/// fn __probe(
4068///     _: Dropout2d,
4069///     _: AlphaDropout,
4070///     _: EmbeddingBag,
4071///     _: EmbeddingBagVars,
4072/// ) {
4073///     let _: __FandheDropoutEmbeddingBagHoldMarker = add_dropout2d();
4074///     let _: __FandheDropoutEmbeddingBagHoldMarker = add_alpha_dropout();
4075///     let _: __FandheDropoutEmbeddingBagHoldMarker = add_embedding_bag();
4076/// }
4077/// ```
4078#[cfg(doctest)]
4079#[allow(dead_code)]
4080struct DropoutEmbeddingBagHoldDoctestGuard;
4081
4082/// イシュー #2164(親 #2131。設計正本 `docs/autodiff-rnn-stacked-config-
4083/// decision.md` §8)の facade 公開保留のうち、イシュー #2535(親 #2534・
4084/// ルート #2499 の一括承認)の後も残る分を固定する doctest 足場
4085/// (`PixelShuffleHoldDoctestGuard` の #2526 縮小形と同型)。
4086///
4087/// #2535 で公開済みのもの(`RnnConfig`・`Stacked*` 6 型の再エクスポートと
4088/// `Tape::{stacked_rnn_forward_seq, stacked_lstm_forward_seq,
4089/// stacked_gru_forward_seq}`)の保留プローブは撤去した。承認形は
4090/// `crates/facade/tests/api_surface.rs` の正ガード
4091/// (`nn_rnn_module_reexports_exactly_expected_surface`・
4092/// `nn_rnn_stacked_types_are_reachable_via_facade_only`・
4093/// `tape_stacked_rnn_methods_are_thin_delegations` 等)が固定する。
4094///
4095/// 残す保留は `fandhe_ai::nn::rnn::{Rnn, Lstm, Gru}::with_config`(既存型への
4096/// `RnnConfig` 引数付きコンストラクタ追加)のみ。決定記録 §2.1 で不採用、
4097/// §8 の承認範囲にも含まれない(trait 経由のプローブ呼び出しが inherent
4098/// メソッドの型・引数不一致でコンパイル失敗する)。
4099///
4100/// ソース走査ガード(`rnn_config_hold_doctest_globs_all_pub_modules`・
4101/// `rnn_config_hold_doctest_probe_body_matches_fixed_contract`・
4102/// `workspace_declares_no_rnn_with_config_fn`)との多層防御。
4103///
4104/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
4105/// できること
4106///
4107/// ```
4108/// use fandhe_ai::*;
4109/// use fandhe_ai::compat::*;
4110/// use fandhe_ai::optim::*;
4111/// use fandhe_ai::data::*;
4112/// use fandhe_ai::nn::*;
4113/// use fandhe_ai::nn::init::*;
4114/// use fandhe_ai::nn::rnn::*;
4115/// use fandhe_ai::nn::kv_cache::*;
4116/// use fandhe_ai::nn::loss::*;
4117/// use fandhe_ai::interop::*;
4118/// use fandhe_ai::interop::onnx::*;
4119/// use fandhe_ai::interop::safetensors::*;
4120/// use fandhe_ai::interop::npy::*;
4121/// use fandhe_ai::model::*;
4122/// use fandhe_ai::inference::*;
4123/// use fandhe_ai::text::*;
4124/// use fandhe_ai::models::*;
4125/// use fandhe_ai::distributed::*;
4126///
4127/// struct __FandheRnnConfigMarker;
4128///
4129/// trait __FandheRnnConfigWithConfigProbe {
4130///     fn with_config(&self) -> __FandheRnnConfigMarker;
4131/// }
4132///
4133/// impl __FandheRnnConfigWithConfigProbe for fandhe_ai::nn::rnn::Rnn {
4134///     fn with_config(&self) -> __FandheRnnConfigMarker {
4135///         __FandheRnnConfigMarker
4136///     }
4137/// }
4138///
4139/// impl __FandheRnnConfigWithConfigProbe for fandhe_ai::nn::rnn::Lstm {
4140///     fn with_config(&self) -> __FandheRnnConfigMarker {
4141///         __FandheRnnConfigMarker
4142///     }
4143/// }
4144///
4145/// impl __FandheRnnConfigWithConfigProbe for fandhe_ai::nn::rnn::Gru {
4146///     fn with_config(&self) -> __FandheRnnConfigMarker {
4147///         __FandheRnnConfigMarker
4148///     }
4149/// }
4150///
4151/// fn __probe(
4152///     rnn: &fandhe_ai::nn::rnn::Rnn,
4153///     lstm: &fandhe_ai::nn::rnn::Lstm,
4154///     gru: &fandhe_ai::nn::rnn::Gru,
4155/// ) {
4156///     let _: __FandheRnnConfigMarker = fandhe_ai::nn::rnn::Rnn::with_config(rnn);
4157///     let _: __FandheRnnConfigMarker = rnn.with_config();
4158///     let _: __FandheRnnConfigMarker = fandhe_ai::nn::rnn::Lstm::with_config(lstm);
4159///     let _: __FandheRnnConfigMarker = lstm.with_config();
4160///     let _: __FandheRnnConfigMarker = fandhe_ai::nn::rnn::Gru::with_config(gru);
4161///     let _: __FandheRnnConfigMarker = gru.with_config();
4162/// }
4163/// ```
4164#[cfg(doctest)]
4165#[allow(dead_code)]
4166struct RnnConfigHoldDoctestGuard;
4167
4168/// イシュー #2162(親 #2131)の facade 公開保留のうち、イシュー #2526
4169/// (親 #2520・ルート #2499 の一括承認)の後も残る分を固定する doctest
4170/// 足場。`SpatialLayersHoldDoctestGuard`(#2521 の縮小形)と同型の「正の
4171/// プローブ 1 ブロック方式」を採る: facade の全 `pub mod` を glob
4172/// import したスコープに、本ブロック内でのみ定義したローカル
4173/// `__fandhe_pixel_shuffle_hold_probe::{PixelShuffle, PixelUnshuffle,
4174/// add_pixel_shuffle, add_pixel_unshuffle}` を導入し、実際に使う関数を
4175/// 書く。facade がどの経路(`pub use`・別名エクスポート・facade 独自の
4176/// `struct`/`type` 宣言・自由関数での公開)でこれらの名前を公開しても、
4177/// ローカル定義との glob 衝突でエラーコードに依存せずコンパイルが失敗する。
4178///
4179/// イシュー #2526 で公開済みの `compat::Sequential::add_pixel_shuffle`/
4180/// `add_pixel_unshuffle`・`Var::pixel_shuffle`/`pixel_unshuffle` のプローブ
4181/// (inherent メソッド追加を trait 経由呼び出しの不一致で検出していた
4182/// `__FandhePixelShuffleAddProbe`/`__FandhePixelShuffleVarProbe` と
4183/// `seq.*`/`v.*` の呼び出し)は撤去した。これらの承認形(定義元集合・
4184/// 1 行委譲本体・シグネチャ・実値)は `crates/facade/tests/api_surface.rs`
4185/// の正ガード群(`workspace_declares_pixel_shuffle_facade_fn_names_only_in_
4186/// approved_locations` ほか)が固定する。型の再エクスポートと自由関数での
4187/// 公開は未承認のため、本プローブで引き続き禁止する。
4188///
4189/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
4190/// pixel_shuffle_hold_doctest_globs_all_pub_modules`・`pixel_shuffle_
4191/// hold_doctest_probe_body_matches_fixed_contract`)との多層防御の位置
4192/// づけ・承認の経緯は `docs/autodiff-pixel-shuffle-decision.md` §6 を参照。
4193///
4194/// 型の再エクスポート・自由関数公開が承認される日が来たら、本モジュール・
4195/// 本 doctest 自体を削除する(対応する固定文言も同時に正ガードへ置き換える)。
4196///
4197/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
4198/// できること
4199///
4200/// ```
4201/// use fandhe_ai::*;
4202/// use fandhe_ai::compat::*;
4203/// use fandhe_ai::optim::*;
4204/// use fandhe_ai::data::*;
4205/// use fandhe_ai::nn::*;
4206/// use fandhe_ai::nn::init::*;
4207/// use fandhe_ai::nn::rnn::*;
4208/// use fandhe_ai::nn::kv_cache::*;
4209/// use fandhe_ai::nn::loss::*;
4210/// use fandhe_ai::interop::*;
4211/// use fandhe_ai::interop::onnx::*;
4212/// use fandhe_ai::interop::safetensors::*;
4213/// use fandhe_ai::interop::npy::*;
4214/// use fandhe_ai::model::*;
4215/// use fandhe_ai::inference::*;
4216/// use fandhe_ai::text::*;
4217/// use fandhe_ai::models::*;
4218/// use fandhe_ai::distributed::*;
4219///
4220/// mod __fandhe_pixel_shuffle_hold_probe {
4221///     pub struct PixelShuffle;
4222///     pub struct PixelUnshuffle;
4223///     pub struct __FandhePixelShuffleHoldMarker;
4224///     pub fn add_pixel_shuffle() -> __FandhePixelShuffleHoldMarker {
4225///         __FandhePixelShuffleHoldMarker
4226///     }
4227///     pub fn add_pixel_unshuffle() -> __FandhePixelShuffleHoldMarker {
4228///         __FandhePixelShuffleHoldMarker
4229///     }
4230/// }
4231/// use __fandhe_pixel_shuffle_hold_probe::*;
4232///
4233/// fn __probe(
4234///     _: PixelShuffle,
4235///     _: PixelUnshuffle,
4236/// ) {
4237///     let _: __FandhePixelShuffleHoldMarker = add_pixel_shuffle();
4238///     let _: __FandhePixelShuffleHoldMarker = add_pixel_unshuffle();
4239/// }
4240/// ```
4241#[cfg(doctest)]
4242#[allow(dead_code)]
4243struct PixelShuffleHoldDoctestGuard;
4244
4245/// イシュー #2166(親 #2131)の facade 公開保留を固定する doctest 足場。
4246/// イシュー #2167(親 #2131)で、距離ベースの損失 3 種
4247/// (`cosine_embedding_loss`・`margin_ranking_loss`・
4248/// `triplet_margin_loss`)と `poisson_nll_loss` を同じ保留対象へ追加
4249/// した。イシュー #2168(親 #2131)で `ctc_loss`(CTC 損失)を追加した
4250/// (7 関数名。`crate::loss_ops` モジュール doc「facade 非公開
4251/// (意図的)」と同じ判断枠組み)。
4252/// `VarReduceOpsHoldDoctestGuard`(イシュー #2147。#2514 で削除済み)と同型の「正の
4253/// プローブ 1 ブロック方式」を採る: facade の全 `pub mod` を glob
4254/// import したスコープに、本ブロック内でのみ定義したローカルの自由
4255/// 関数群(`__fandhe_loss_hold_probe::loss_ops::{l1_loss,
4256/// cross_entropy_loss_with, cosine_embedding_loss, margin_ranking_loss,
4257/// triplet_margin_loss, poisson_nll_loss, ctc_loss}`)とトレイト
4258/// (`__FandheLossHoldProbe`)を導入し、実際に使う関数を書く。facade が
4259/// どの経路(`pub use fandhe_ai_autodiff::loss_ops;` のようなモジュール
4260/// 再エクスポート・`Var` への inherent メソッド追加・別名 `pub use`)で
4261/// `loss_ops` という名前や 7 個の関数名を公開しても、ローカル定義との
4262/// glob 衝突(モジュール名の場合)または呼び出しシグネチャの不一致
4263/// (inherent メソッドがトレイトメソッドより優先解決されるため、引数
4264/// なしの `x.cosine_embedding_loss()` 呼び出しが実際の inherent メソッド
4265/// 〈引数数不一致〉に解決されて型・引数数エラーになる)で
4266/// コンパイルが失敗する。
4267///
4268/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
4269/// loss_ops_hold_doctest_globs_all_pub_modules`・`loss_ops_hold_
4270/// doctest_probe_body_matches_fixed_contract`・`facade_does_not_
4271/// reexport_or_declare_loss_ops`・`workspace_declares_loss_ops_
4272/// fn_names_only_in_approved_locations`)との多層防御の位置づけは
4273/// `docs/autodiff-loss-ops-decision.md` §5「承認事項」を参照。
4274///
4275/// **#2538 での部分反転**(ルート #2499 一括承認。`VarActivationOpsHoldDoctestGuard`
4276/// の #2516 型): `Var::l1_loss`・`Var::cross_entropy_loss_with` は委譲メソッド
4277/// として facade 公開済みのため、`__probe_var` から該当 4 行だけを削除した
4278/// (正ガードは `api_surface.rs::var_loss_ops_methods_are_thin_delegations`・
4279/// `var_loss_ops_are_reachable_via_facade_var`)。`loss_ops` モジュール・
4280/// `Tensor`/`Tape` 上の同名メソッド・残り 5 名の `Var` への公開は引き続き拒否する。
4281///
4282/// **#2539 での追加の部分反転**(同一の一括承認): `Var::cosine_embedding_loss`・
4283/// `Var::margin_ranking_loss`・`Var::triplet_margin_loss`・`Var::poisson_nll_loss`
4284/// も委譲メソッドとして公開済みのため、`__probe_var` から該当 8 行を削除した
4285/// (正ガードは `var_loss_ops_methods_are_thin_delegations` 6 件化・
4286/// `var_distance_poisson_loss_ops_are_reachable_via_facade_var`)。`__probe_var` には
4287/// `ctc_loss` の 2 行のみが残っていた。
4288///
4289/// **#2540 での反転**(同一の一括承認): `Var::ctc_loss` を委譲メソッドとして公開した
4290/// ため、`__probe_var` と `Var` 向けトレイト impl を撤去した(正ガードは
4291/// `var_loss_ops_methods_are_thin_delegations` 7 件化・`var_ctc_loss_is_reachable_via_facade_var`)。
4292///
4293/// **#2602 での追加の反転**(親 #2600・ルート #2499 の一括承認。決定記録
4294/// `docs/facade-nn-loss-structs-exposure-decision.md` §4・§6): `Reduction` と
4295/// オプション型 4 種(`CrossEntropyOptions`・`TripletMarginOptions`・`PoissonNllOptions`・
4296/// `CtcLossOptions`)は、損失構造体 14 種とともに `nn::loss` 経由**のみ**で公開済み
4297/// (crate ルート・`nn` 直下・`loss_ops` 経由では出さない)。
4298///
4299/// 撤去条件: `Var` 側の撤去は #2540 で完了。`Tensor`/`Tape` 上の同名メソッドと
4300/// `loss_ops` モジュール再エクスポートの拒否は維持する(解除には別途承認が必要)。
4301///
4302/// **#2854 での追記**: オプション型 5 つ(`BceWithLogitsOptions`・`GaussianNllOptions`・`MultiMarginOptions`・
4303/// `MultiLabelSoftMarginOptions`・`SigmoidFocalLossOptions`)も同じ `nn::loss` の 1 経路で公開済み(上は #2602 時点の記録)。
4304///
4305/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
4306/// できること
4307///
4308/// ```
4309/// use fandhe_ai::*;
4310/// use fandhe_ai::compat::*;
4311/// use fandhe_ai::optim::*;
4312/// use fandhe_ai::data::*;
4313/// use fandhe_ai::nn::*;
4314/// use fandhe_ai::nn::init::*;
4315/// use fandhe_ai::nn::rnn::*;
4316/// use fandhe_ai::nn::kv_cache::*;
4317/// use fandhe_ai::nn::loss::*;
4318/// use fandhe_ai::interop::*;
4319/// use fandhe_ai::interop::onnx::*;
4320/// use fandhe_ai::interop::safetensors::*;
4321/// use fandhe_ai::interop::npy::*;
4322/// use fandhe_ai::model::*;
4323/// use fandhe_ai::inference::*;
4324/// use fandhe_ai::text::*;
4325/// use fandhe_ai::models::*;
4326/// use fandhe_ai::distributed::*;
4327///
4328/// mod __fandhe_loss_hold_probe {
4329///     pub mod loss_ops {
4330///         pub fn l1_loss() {}
4331///         pub fn cross_entropy_loss_with() {}
4332///         pub fn cosine_embedding_loss() {}
4333///         pub fn margin_ranking_loss() {}
4334///         pub fn triplet_margin_loss() {}
4335///         pub fn poisson_nll_loss() {}
4336///         pub fn ctc_loss() {}
4337///     }
4338/// }
4339/// use __fandhe_loss_hold_probe::*;
4340///
4341/// struct __FandheLossMarker;
4342///
4343/// trait __FandheLossHoldProbe {
4344///     fn l1_loss(&self) -> __FandheLossMarker;
4345///     fn cross_entropy_loss_with(&self) -> __FandheLossMarker;
4346///     fn cosine_embedding_loss(&self) -> __FandheLossMarker;
4347///     fn margin_ranking_loss(&self) -> __FandheLossMarker;
4348///     fn triplet_margin_loss(&self) -> __FandheLossMarker;
4349///     fn poisson_nll_loss(&self) -> __FandheLossMarker;
4350///     fn ctc_loss(&self) -> __FandheLossMarker;
4351/// }
4352///
4353/// impl __FandheLossHoldProbe for fandhe_ai::Tensor<f32> {
4354///     fn l1_loss(&self) -> __FandheLossMarker { __FandheLossMarker }
4355///     fn cross_entropy_loss_with(&self) -> __FandheLossMarker { __FandheLossMarker }
4356///     fn cosine_embedding_loss(&self) -> __FandheLossMarker { __FandheLossMarker }
4357///     fn margin_ranking_loss(&self) -> __FandheLossMarker { __FandheLossMarker }
4358///     fn triplet_margin_loss(&self) -> __FandheLossMarker { __FandheLossMarker }
4359///     fn poisson_nll_loss(&self) -> __FandheLossMarker { __FandheLossMarker }
4360///     fn ctc_loss(&self) -> __FandheLossMarker { __FandheLossMarker }
4361/// }
4362///
4363/// impl __FandheLossHoldProbe for fandhe_ai::Tape {
4364///     fn l1_loss(&self) -> __FandheLossMarker { __FandheLossMarker }
4365///     fn cross_entropy_loss_with(&self) -> __FandheLossMarker { __FandheLossMarker }
4366///     fn cosine_embedding_loss(&self) -> __FandheLossMarker { __FandheLossMarker }
4367///     fn margin_ranking_loss(&self) -> __FandheLossMarker { __FandheLossMarker }
4368///     fn triplet_margin_loss(&self) -> __FandheLossMarker { __FandheLossMarker }
4369///     fn poisson_nll_loss(&self) -> __FandheLossMarker { __FandheLossMarker }
4370///     fn ctc_loss(&self) -> __FandheLossMarker { __FandheLossMarker }
4371/// }
4372///
4373/// fn __probe_free_fns() {
4374///     // `loss_ops::` を経由した経路解決(`use fandhe_ai::*;` が
4375///     // 同名モジュールを glob 公開していれば、名前解決自体が曖昧に
4376///     // なり E0659 でコンパイル失敗する)。
4377///     loss_ops::l1_loss();
4378///     loss_ops::cross_entropy_loss_with();
4379///     loss_ops::cosine_embedding_loss();
4380///     loss_ops::margin_ranking_loss();
4381///     loss_ops::triplet_margin_loss();
4382///     loss_ops::poisson_nll_loss();
4383///     loss_ops::ctc_loss();
4384/// }
4385///
4386/// fn __probe_tensor_f32(x: &fandhe_ai::Tensor<f32>) {
4387///     let _: __FandheLossMarker = fandhe_ai::Tensor::l1_loss(x);
4388///     let _: __FandheLossMarker = x.l1_loss();
4389///     let _: __FandheLossMarker = fandhe_ai::Tensor::cosine_embedding_loss(x);
4390///     let _: __FandheLossMarker = x.cosine_embedding_loss();
4391///     let _: __FandheLossMarker = fandhe_ai::Tensor::margin_ranking_loss(x);
4392///     let _: __FandheLossMarker = x.margin_ranking_loss();
4393///     let _: __FandheLossMarker = fandhe_ai::Tensor::ctc_loss(x);
4394///     let _: __FandheLossMarker = x.ctc_loss();
4395/// }
4396///
4397/// fn __probe_tape(x: &fandhe_ai::Tape) {
4398///     let _: __FandheLossMarker = fandhe_ai::Tape::cross_entropy_loss_with(x);
4399///     let _: __FandheLossMarker = x.cross_entropy_loss_with();
4400///     let _: __FandheLossMarker = fandhe_ai::Tape::triplet_margin_loss(x);
4401///     let _: __FandheLossMarker = x.triplet_margin_loss();
4402///     let _: __FandheLossMarker = fandhe_ai::Tape::poisson_nll_loss(x);
4403///     let _: __FandheLossMarker = x.poisson_nll_loss();
4404///     let _: __FandheLossMarker = fandhe_ai::Tape::ctc_loss(x);
4405///     let _: __FandheLossMarker = x.ctc_loss();
4406/// }
4407/// ```
4408#[cfg(doctest)]
4409#[allow(dead_code)]
4410struct LossOpsHoldDoctestGuard;
4411
4412/// イシュー #2179(親 #2131「PyTorch/TF 置き換えの API 網羅」)で導入し、#2560 の公開後は
4413/// **禁止経路専用**として維持する doctest 足場(`TrainStepHoldDoctestGuard`〈#2569〉と同じ扱い。
4414/// 構造体名は `*HoldDoctestGuard` の統一と固定文言ドリフト検査の対象名を保つため変えない。
4415/// 判断は `docs/autodiff-ema-decision.md` §14.3)。
4416///
4417/// 承認形は #2560 で公開済み: `optim::ExponentialMovingAverage`(facade 独自ラッパー)と
4418/// `compat::EmaCallback`/`Callback::Ema`(`fit_with_callbacks` への結線)。
4419/// 本足場が固定するのは**残る禁止経路**、すなわち `compat::FitConfig`(`fit(use_ema=true)` 相当)・
4420/// `compat::Sequential`(EMA 適用・復元)への `use_ema`/`ema_decay` inherent メソッド追加
4421/// (決定記録 §10.2 (d) で不採用)だけである。`VarCustomHoldDoctestGuard`〈#2064〉と同じ
4422/// マーカー型トレイト方式で、ローカル `__FandheEmaHoldProbe` トレイトを両型へ実装し、
4423/// メソッド形・型パス形の両方で呼び出す。facade がどちらかの型へ同名の inherent メソッドを
4424/// 追加すると、優先解決される inherent メソッドの戻り値の型がプローブの期待型と一致せず
4425/// 型不一致でコンパイルが失敗する。
4426///
4427/// ソース走査の正ガード(#2561 で反転済み。`crates/facade/tests/api_surface.rs::
4428/// facade_exposes_ema_only_in_approved_shape`・
4429/// `facade_exposes_ema_only_in_approved_shape_detects_each_category`・
4430/// `ema_types_are_reachable_via_facade_only`・
4431/// `ema_usage_doctests_are_present_and_compiled`)が承認形の存在と形を固定し、
4432/// 本 doctest は禁止経路専用として型検査レベルで維持する
4433/// (`ema_hold_doctest_globs_all_pub_modules`・
4434/// `ema_hold_doctest_probe_body_matches_fixed_contract` がドリフトを検出)。
4435/// 多層防御の位置づけは `docs/autodiff-ema-decision.md` §4・§13・§14 を参照。
4436///
4437/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
4438/// できること
4439///
4440/// ```
4441/// use fandhe_ai::*;
4442/// use fandhe_ai::compat::*;
4443/// use fandhe_ai::optim::*;
4444/// use fandhe_ai::data::*;
4445/// use fandhe_ai::nn::*;
4446/// use fandhe_ai::nn::init::*;
4447/// use fandhe_ai::nn::rnn::*;
4448/// use fandhe_ai::nn::kv_cache::*;
4449/// use fandhe_ai::nn::loss::*;
4450/// use fandhe_ai::interop::*;
4451/// use fandhe_ai::interop::onnx::*;
4452/// use fandhe_ai::interop::safetensors::*;
4453/// use fandhe_ai::interop::npy::*;
4454/// use fandhe_ai::model::*;
4455/// use fandhe_ai::inference::*;
4456/// use fandhe_ai::text::*;
4457/// use fandhe_ai::models::*;
4458/// use fandhe_ai::distributed::*;
4459///
4460/// struct __FandheEmaHoldMarker;
4461///
4462/// trait __FandheEmaHoldProbe {
4463///     fn use_ema(&self) -> __FandheEmaHoldMarker;
4464///     fn ema_decay(&self) -> __FandheEmaHoldMarker;
4465/// }
4466///
4467/// impl __FandheEmaHoldProbe for fandhe_ai::compat::FitConfig {
4468///     fn use_ema(&self) -> __FandheEmaHoldMarker {
4469///         __FandheEmaHoldMarker
4470///     }
4471///     fn ema_decay(&self) -> __FandheEmaHoldMarker {
4472///         __FandheEmaHoldMarker
4473///     }
4474/// }
4475///
4476/// impl __FandheEmaHoldProbe for fandhe_ai::compat::Sequential {
4477///     fn use_ema(&self) -> __FandheEmaHoldMarker {
4478///         __FandheEmaHoldMarker
4479///     }
4480///     fn ema_decay(&self) -> __FandheEmaHoldMarker {
4481///         __FandheEmaHoldMarker
4482///     }
4483/// }
4484///
4485/// fn __probe_fit_config(x: &fandhe_ai::compat::FitConfig) {
4486///     let _: __FandheEmaHoldMarker = fandhe_ai::compat::FitConfig::use_ema(x);
4487///     let _: __FandheEmaHoldMarker = x.use_ema();
4488///     let _: __FandheEmaHoldMarker = fandhe_ai::compat::FitConfig::ema_decay(x);
4489///     let _: __FandheEmaHoldMarker = x.ema_decay();
4490/// }
4491///
4492/// fn __probe_sequential(x: &fandhe_ai::compat::Sequential) {
4493///     let _: __FandheEmaHoldMarker = fandhe_ai::compat::Sequential::use_ema(x);
4494///     let _: __FandheEmaHoldMarker = x.use_ema();
4495///     let _: __FandheEmaHoldMarker = fandhe_ai::compat::Sequential::ema_decay(x);
4496///     let _: __FandheEmaHoldMarker = x.ema_decay();
4497/// }
4498/// ```
4499#[cfg(doctest)]
4500#[allow(dead_code)]
4501struct EmaHoldDoctestGuard;
4502
4503/// イシュー #2658(親 #2657)で導入し、イシュー #2679 で承認形の公開
4504/// (`optim::AveragedModel`=facade 独自ラッパー、`optim::{SwaLr, SwaAnneal}`=素の
4505/// 再エクスポート。`docs/autodiff-swa-decision.md` §7)へ部分反転した SWA の保留
4506/// ガード(`EmaHoldDoctestGuard` と同型の「正のプローブ 1 ブロック方式」)。
4507///
4508/// 型名の glob 衝突プローブは承認形の公開に伴い削除した。残すのは**未承認の経路**
4509/// である `compat::FitConfig`/`compat::Sequential` への inherent メソッド追加
4510/// (`fit` への SWA 結線)専用のプローブだけである: ローカル `__FandheSwaHoldProbe`
4511/// (`use_swa`/`swa_start`/`swa_lr`)を両型へ実装し、UFCS 形とメソッド呼び出し形の
4512/// 両方で呼ぶ。同名の inherent メソッドが生えると戻り値型の不一致で失敗する。
4513///
4514/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
4515/// swa_hold_doctest_globs_all_pub_modules`・
4516/// `swa_hold_doctest_probe_body_matches_fixed_contract`・
4517/// `facade_exposes_swa_only_in_approved_shape`)との多層防御の位置づけと検出範囲
4518/// (列挙名のみ。マクロ生成・別名経由までは保証しない)は
4519/// `docs/autodiff-swa-decision.md` §9 を参照。
4520///
4521/// イシュー #3058 で `Callback::Swa(SwaCallback)` として結線が公開されたが(決定記録 §16・§17)、
4522/// `FitConfig`/`Sequential` へは SWA 用メソッドを足さない契約(§16)は不変のため、プローブは維持する
4523/// (`SwaCallback` の accessor `swa_start`/`swa_lr` は別型の inherent メソッドで衝突しない)。
4524/// 将来これらの契約自体が変わる日が来たら、本構造体・本 doctest を削除する。
4525///
4526/// イシュー #3060 で `Callback::Swa(SwaCallback)` の形の正ガード(`api_surface.rs` の
4527/// `callback_swa_variant_*`・`compat_callback_swa_variant_has_exact_approved_shape`・
4528/// `fit_config_declares_no_swa_fields`)が揃い、SWA の保留は解消した。本構造体は
4529/// `EmaHoldDoctestGuard` と同じく禁止経路(`FitConfig`/`Sequential` への SWA 用メソッド追加)
4530/// 専用のプローブとして残す。公開した名前に当たるプローブは #2679 で削除済みで、#3060 で外すものは無い
4531/// (決定記録 §19)。
4532///
4533/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
4534/// できること
4535///
4536/// ```
4537/// use fandhe_ai::*;
4538/// use fandhe_ai::compat::*;
4539/// use fandhe_ai::optim::*;
4540/// use fandhe_ai::data::*;
4541/// use fandhe_ai::nn::*;
4542/// use fandhe_ai::nn::init::*;
4543/// use fandhe_ai::nn::rnn::*;
4544/// use fandhe_ai::nn::kv_cache::*;
4545/// use fandhe_ai::nn::loss::*;
4546/// use fandhe_ai::interop::*;
4547/// use fandhe_ai::interop::onnx::*;
4548/// use fandhe_ai::interop::safetensors::*;
4549/// use fandhe_ai::interop::npy::*;
4550/// use fandhe_ai::model::*;
4551/// use fandhe_ai::inference::*;
4552/// use fandhe_ai::text::*;
4553/// use fandhe_ai::models::*;
4554/// use fandhe_ai::distributed::*;
4555///
4556/// struct __FandheSwaHoldMarker;
4557///
4558/// trait __FandheSwaHoldProbe {
4559///     fn use_swa(&self) -> __FandheSwaHoldMarker;
4560///     fn swa_start(&self) -> __FandheSwaHoldMarker;
4561///     fn swa_lr(&self) -> __FandheSwaHoldMarker;
4562/// }
4563///
4564/// impl __FandheSwaHoldProbe for fandhe_ai::compat::FitConfig {
4565///     fn use_swa(&self) -> __FandheSwaHoldMarker {
4566///         __FandheSwaHoldMarker
4567///     }
4568///     fn swa_start(&self) -> __FandheSwaHoldMarker {
4569///         __FandheSwaHoldMarker
4570///     }
4571///     fn swa_lr(&self) -> __FandheSwaHoldMarker {
4572///         __FandheSwaHoldMarker
4573///     }
4574/// }
4575///
4576/// impl __FandheSwaHoldProbe for fandhe_ai::compat::Sequential {
4577///     fn use_swa(&self) -> __FandheSwaHoldMarker {
4578///         __FandheSwaHoldMarker
4579///     }
4580///     fn swa_start(&self) -> __FandheSwaHoldMarker {
4581///         __FandheSwaHoldMarker
4582///     }
4583///     fn swa_lr(&self) -> __FandheSwaHoldMarker {
4584///         __FandheSwaHoldMarker
4585///     }
4586/// }
4587///
4588/// fn __probe_fit_config(x: &fandhe_ai::compat::FitConfig) {
4589///     let _: __FandheSwaHoldMarker = fandhe_ai::compat::FitConfig::use_swa(x);
4590///     let _: __FandheSwaHoldMarker = x.use_swa();
4591///     let _: __FandheSwaHoldMarker = fandhe_ai::compat::FitConfig::swa_start(x);
4592///     let _: __FandheSwaHoldMarker = x.swa_start();
4593///     let _: __FandheSwaHoldMarker = fandhe_ai::compat::FitConfig::swa_lr(x);
4594///     let _: __FandheSwaHoldMarker = x.swa_lr();
4595/// }
4596///
4597/// fn __probe_sequential(x: &fandhe_ai::compat::Sequential) {
4598///     let _: __FandheSwaHoldMarker = fandhe_ai::compat::Sequential::use_swa(x);
4599///     let _: __FandheSwaHoldMarker = x.use_swa();
4600///     let _: __FandheSwaHoldMarker = fandhe_ai::compat::Sequential::swa_start(x);
4601///     let _: __FandheSwaHoldMarker = x.swa_start();
4602///     let _: __FandheSwaHoldMarker = fandhe_ai::compat::Sequential::swa_lr(x);
4603///     let _: __FandheSwaHoldMarker = x.swa_lr();
4604/// }
4605/// ```
4606#[cfg(doctest)]
4607#[allow(dead_code)]
4608struct SwaHoldDoctestGuard;
4609
4610/// イシュー #2177(親 #2131)の fit 重み付け公開の**残る禁止経路**を固定する
4611/// doctest 足場(#2564 で承認形を公開済み)。承認形は `compat::FitWeights`・
4612/// inherent `FitConfig::validation_split`・`FitWeights::{new, class_weight,
4613/// sample_weight}`・inherent `Sequential::fit_with_weights` で、
4614/// `docs/compat-fit-sample-weighting-decision.md` §11.1 の確定形(ルート #2499 の
4615/// 承認コメント)に限る。旧版が持っていたローカル `FitWeights` 型プローブと
4616/// `FitConfig::validation_split`/`Sequential::fit_with_weights` の UFCS 行は、
4617/// 実在する inherent に解決され本 doctest 自体が壊れるため撤去した(§11.6)。
4618///
4619/// 「正のプローブ 1 ブロック方式」で、facade の全 `pub mod` を glob import
4620/// したスコープに `__FandheFitWeightHoldProbe` トレイトを導入し、承認形に
4621/// **ない**場所の名前を UFCS で呼ぶ: `FitConfig::{class_weight, sample_weight,
4622/// fit_with_weights, fit_weighted}`(`FitConfig` は `Copy + Eq` を公開契約と
4623/// するため重みを直接持たせる実装経路は不可)、`Sequential::{validation_split,
4624/// class_weight, sample_weight, fit_weighted}`。facade が同名の inherent メソッドを
4625/// 足すと inherent が優先解決され、引数なし `&self` のトレイト呼び出しが型・
4626/// 引数不一致でコンパイル失敗する(メソッド呼び出し形だと衝突を検出できない
4627/// ため UFCS のみ)。
4628///
4629/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
4630/// fit_weighting_hold_doctest_globs_all_pub_modules`・
4631/// `fit_weighting_hold_doctest_probe_body_matches_fixed_contract`・
4632/// `fit_config_keeps_copy_eq_for_0_9_0_compat`)に加え、#2565 で承認形を固定する
4633/// 正ガード(`facade_fit_weighting_public_surface_matches_approved_contract`〈承認した
4634/// 形が承認した場所に所有型の `impl` ごとちょうど 1 件ずつあること〉・
4635/// `facade_fit_weights_shape_matches_approved_contract`〈`FitWeights` の形状〉・
4636/// `workspace_declares_fit_weighting_fn_names_only_in_approved_location`〈workspace
4637/// インベントリ〉・`fit_weighting_items_are_reachable_via_facade_only`〈facade 単独
4638/// import での到達性〉)へ反転済み。本 doctest は残る禁止経路専用で、多層防御の
4639/// 位置づけは同 doc §7・§11.6・§15 を参照。
4640///
4641/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
4642/// できること
4643///
4644/// ```
4645/// use fandhe_ai::*;
4646/// use fandhe_ai::compat::*;
4647/// use fandhe_ai::optim::*;
4648/// use fandhe_ai::data::*;
4649/// use fandhe_ai::nn::*;
4650/// use fandhe_ai::nn::init::*;
4651/// use fandhe_ai::nn::rnn::*;
4652/// use fandhe_ai::nn::kv_cache::*;
4653/// use fandhe_ai::nn::loss::*;
4654/// use fandhe_ai::interop::*;
4655/// use fandhe_ai::interop::onnx::*;
4656/// use fandhe_ai::interop::safetensors::*;
4657/// use fandhe_ai::interop::npy::*;
4658/// use fandhe_ai::model::*;
4659/// use fandhe_ai::inference::*;
4660/// use fandhe_ai::text::*;
4661/// use fandhe_ai::models::*;
4662/// use fandhe_ai::distributed::*;
4663///
4664/// struct __FandheFitWeightHoldMarker;
4665///
4666/// trait __FandheFitWeightHoldProbe {
4667///     fn validation_split(&self) -> __FandheFitWeightHoldMarker;
4668///     fn class_weight(&self) -> __FandheFitWeightHoldMarker;
4669///     fn sample_weight(&self) -> __FandheFitWeightHoldMarker;
4670///     fn fit_with_weights(&self) -> __FandheFitWeightHoldMarker;
4671///     fn fit_weighted(&self) -> __FandheFitWeightHoldMarker;
4672/// }
4673///
4674/// impl __FandheFitWeightHoldProbe for fandhe_ai::compat::FitConfig {
4675///     fn validation_split(&self) -> __FandheFitWeightHoldMarker {
4676///         __FandheFitWeightHoldMarker
4677///     }
4678///     fn class_weight(&self) -> __FandheFitWeightHoldMarker {
4679///         __FandheFitWeightHoldMarker
4680///     }
4681///     fn sample_weight(&self) -> __FandheFitWeightHoldMarker {
4682///         __FandheFitWeightHoldMarker
4683///     }
4684///     fn fit_with_weights(&self) -> __FandheFitWeightHoldMarker {
4685///         __FandheFitWeightHoldMarker
4686///     }
4687///     fn fit_weighted(&self) -> __FandheFitWeightHoldMarker {
4688///         __FandheFitWeightHoldMarker
4689///     }
4690/// }
4691///
4692/// impl __FandheFitWeightHoldProbe for fandhe_ai::compat::Sequential {
4693///     fn validation_split(&self) -> __FandheFitWeightHoldMarker {
4694///         __FandheFitWeightHoldMarker
4695///     }
4696///     fn class_weight(&self) -> __FandheFitWeightHoldMarker {
4697///         __FandheFitWeightHoldMarker
4698///     }
4699///     fn sample_weight(&self) -> __FandheFitWeightHoldMarker {
4700///         __FandheFitWeightHoldMarker
4701///     }
4702///     fn fit_with_weights(&self) -> __FandheFitWeightHoldMarker {
4703///         __FandheFitWeightHoldMarker
4704///     }
4705///     fn fit_weighted(&self) -> __FandheFitWeightHoldMarker {
4706///         __FandheFitWeightHoldMarker
4707///     }
4708/// }
4709///
4710/// fn __probe(cfg: &fandhe_ai::compat::FitConfig, seq: &fandhe_ai::compat::Sequential) {
4711///     let _: __FandheFitWeightHoldMarker =
4712///         fandhe_ai::compat::FitConfig::class_weight(cfg);
4713///     let _: __FandheFitWeightHoldMarker =
4714///         fandhe_ai::compat::FitConfig::sample_weight(cfg);
4715///     let _: __FandheFitWeightHoldMarker =
4716///         fandhe_ai::compat::FitConfig::fit_with_weights(cfg);
4717///     let _: __FandheFitWeightHoldMarker =
4718///         fandhe_ai::compat::FitConfig::fit_weighted(cfg);
4719///     let _: __FandheFitWeightHoldMarker =
4720///         fandhe_ai::compat::Sequential::validation_split(seq);
4721///     let _: __FandheFitWeightHoldMarker =
4722///         fandhe_ai::compat::Sequential::class_weight(seq);
4723///     let _: __FandheFitWeightHoldMarker =
4724///         fandhe_ai::compat::Sequential::sample_weight(seq);
4725///     let _: __FandheFitWeightHoldMarker =
4726///         fandhe_ai::compat::Sequential::fit_weighted(seq);
4727/// }
4728/// ```
4729#[cfg(doctest)]
4730#[allow(dead_code)]
4731struct FitWeightingHoldDoctestGuard;
4732
4733/// イシュー #2184(親 #2131)・#2568 の train_step フック公開形を固定する
4734/// doctest 足場。承認形(`TrainStepFn`/`TrainStepOptimizer`/
4735/// `TrainStepOutput` の 3 型と inherent `Sequential::fit_with_train_step`)
4736/// は #2568 で公開済みのため、本プローブは**残る禁止経路**だけを固定する:
4737/// `FitConfig::train_step_fn`(フックを設定へ持たせる形。`FitConfig` は
4738/// `Copy + Eq` を維持するため不可)・`FitConfig::fit_with_train_step`・
4739/// `Sequential::train_step_fn`(承認形にない名前)。
4740/// `FitWeightingHoldDoctestGuard`(#2177)と同型の「正のプローブ 1 ブロック
4741/// 方式」で、facade の全 `pub mod` を glob import したスコープに、これらの
4742/// 名前を持つトレイト(`__FandheTrainStepHoldProbe`)を導入して UFCS で
4743/// 呼ぶ。facade が inherent メソッドとして公開すると trait 経由呼び出しが
4744/// 型・引数不一致でコンパイル失敗する(inherent が優先解決されるため)。
4745///
4746/// ソース走査の正ガード(#2569 で反転済み。`crates/facade/tests/api_surface.rs::
4747/// facade_train_step_public_surface_matches_approved_contract`・
4748/// `facade_train_step_optimizer_and_output_shapes_match_approved_contract`・
4749/// `workspace_declares_train_step_fn_names_only_in_approved_location`・
4750/// `train_step_types_are_reachable_via_facade_only`)が承認形の存在と形を固定し、
4751/// 本 doctest は禁止経路専用として型検査レベルで維持する
4752/// (`train_step_hold_doctest_globs_all_pub_modules`・
4753/// `train_step_hold_doctest_probe_body_matches_fixed_contract` がドリフトを検出)。
4754/// 多層防御の位置づけは `docs/compat-train-step-hook-decision.md` §8.4・§9 を参照。
4755///
4756/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
4757/// できること
4758///
4759/// ```
4760/// use fandhe_ai::*;
4761/// use fandhe_ai::compat::*;
4762/// use fandhe_ai::optim::*;
4763/// use fandhe_ai::data::*;
4764/// use fandhe_ai::nn::*;
4765/// use fandhe_ai::nn::init::*;
4766/// use fandhe_ai::nn::rnn::*;
4767/// use fandhe_ai::nn::kv_cache::*;
4768/// use fandhe_ai::nn::loss::*;
4769/// use fandhe_ai::interop::*;
4770/// use fandhe_ai::interop::onnx::*;
4771/// use fandhe_ai::interop::safetensors::*;
4772/// use fandhe_ai::interop::npy::*;
4773/// use fandhe_ai::model::*;
4774/// use fandhe_ai::inference::*;
4775/// use fandhe_ai::text::*;
4776/// use fandhe_ai::models::*;
4777/// use fandhe_ai::distributed::*;
4778///
4779/// struct __FandheTrainStepHoldMarker;
4780///
4781/// trait __FandheTrainStepHoldProbe {
4782///     fn train_step_fn(&self) -> __FandheTrainStepHoldMarker;
4783///     fn fit_with_train_step(&self) -> __FandheTrainStepHoldMarker;
4784/// }
4785///
4786/// impl __FandheTrainStepHoldProbe for fandhe_ai::compat::FitConfig {
4787///     fn train_step_fn(&self) -> __FandheTrainStepHoldMarker {
4788///         __FandheTrainStepHoldMarker
4789///     }
4790///     fn fit_with_train_step(&self) -> __FandheTrainStepHoldMarker {
4791///         __FandheTrainStepHoldMarker
4792///     }
4793/// }
4794///
4795/// impl __FandheTrainStepHoldProbe for fandhe_ai::compat::Sequential {
4796///     fn train_step_fn(&self) -> __FandheTrainStepHoldMarker {
4797///         __FandheTrainStepHoldMarker
4798///     }
4799///     fn fit_with_train_step(&self) -> __FandheTrainStepHoldMarker {
4800///         __FandheTrainStepHoldMarker
4801///     }
4802/// }
4803///
4804/// fn __probe(cfg: &fandhe_ai::compat::FitConfig, seq: &fandhe_ai::compat::Sequential) {
4805///     let _: __FandheTrainStepHoldMarker =
4806///         fandhe_ai::compat::FitConfig::train_step_fn(cfg);
4807///     let _: __FandheTrainStepHoldMarker =
4808///         fandhe_ai::compat::FitConfig::fit_with_train_step(cfg);
4809///     let _: __FandheTrainStepHoldMarker =
4810///         fandhe_ai::compat::Sequential::train_step_fn(seq);
4811/// }
4812/// ```
4813#[cfg(doctest)]
4814#[allow(dead_code)]
4815struct TrainStepHoldDoctestGuard;
4816
4817/// イシュー #2189(親 #2131)で導入し、イシュー #2590(親 #2588)で**代替案専用へ縮小**
4818/// した facade 公開保留の doctest 足場。
4819/// `ModelIoHoldDoctestGuard`(#2369 で縮小)と同型の「正のプローブ 1
4820/// ブロック方式」を採る。自由関数 4 件と `NpyError` は #2590 で
4821/// `fandhe_ai::interop::npy` として公開済み(承認形は
4822/// `docs/tensor-core-npy-npz-io-decision.md` §10.4)のため、自由関数・
4823/// モジュール名・型名の glob 衝突プローブは成立しなくなり削除した。
4824/// 残すのは承認範囲外の代替案(`Tensor<f32>` への inherent メソッド追加)
4825/// を検出する足場のみ: 本ブロック内でのみ定義したトレイト
4826/// `__FandheNpyIoHoldProbe` を `fandhe_ai::Tensor<f32>` に実装し、
4827/// `Tensor::load_npy`/`save_npy`/`load_npz`/`save_npz` を呼ぶ。
4828/// inherent メソッドがトレイトメソッドより優先解決されるため、`Tensor` に同名
4829/// メソッドが足されると呼び出しシグネチャの不一致でエラーコードに依存せず
4830/// コンパイルが失敗する。`Tensor` に inherent メソッドを追加しないのは
4831/// facade が `pub use fandhe_ai_tensor_core::{..., Tensor, ...};` で `Tensor`
4832/// を再エクスポートしているため、追加がそれだけで公開面を広げてしまうから
4833/// (#2156 の前例。`docs/rng-distributions-generator-decision.md:28`)。
4834///
4835/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
4836/// npy_io_hold_doctest_globs_all_pub_modules`・`npy_io_hold_doctest_
4837/// probe_body_matches_fixed_contract`・`facade_reexports_npy_io_only_from_
4838/// interop_npy`・`workspace_declares_npy_io_names_only_in_allowed_
4839/// locations`)との多層防御の位置づけは
4840/// `docs/tensor-core-npy-npz-io-decision.md` §12 を参照。
4841///
4842/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
4843/// できること
4844///
4845/// ```
4846/// use fandhe_ai::*;
4847/// use fandhe_ai::compat::*;
4848/// use fandhe_ai::optim::*;
4849/// use fandhe_ai::data::*;
4850/// use fandhe_ai::nn::*;
4851/// use fandhe_ai::nn::init::*;
4852/// use fandhe_ai::nn::rnn::*;
4853/// use fandhe_ai::nn::kv_cache::*;
4854/// use fandhe_ai::nn::loss::*;
4855/// use fandhe_ai::interop::*;
4856/// use fandhe_ai::interop::onnx::*;
4857/// use fandhe_ai::interop::safetensors::*;
4858/// use fandhe_ai::interop::npy::*;
4859/// use fandhe_ai::model::*;
4860/// use fandhe_ai::inference::*;
4861/// use fandhe_ai::text::*;
4862/// use fandhe_ai::models::*;
4863/// use fandhe_ai::distributed::*;
4864///
4865/// struct __FandheNpyIoHoldMarker;
4866///
4867/// trait __FandheNpyIoHoldProbe {
4868///     fn load_npy(&self) -> __FandheNpyIoHoldMarker;
4869///     fn save_npy(&self) -> __FandheNpyIoHoldMarker;
4870///     fn load_npz(&self) -> __FandheNpyIoHoldMarker;
4871///     fn save_npz(&self) -> __FandheNpyIoHoldMarker;
4872/// }
4873///
4874/// impl __FandheNpyIoHoldProbe for fandhe_ai::Tensor<f32> {
4875///     fn load_npy(&self) -> __FandheNpyIoHoldMarker { __FandheNpyIoHoldMarker }
4876///     fn save_npy(&self) -> __FandheNpyIoHoldMarker { __FandheNpyIoHoldMarker }
4877///     fn load_npz(&self) -> __FandheNpyIoHoldMarker { __FandheNpyIoHoldMarker }
4878///     fn save_npz(&self) -> __FandheNpyIoHoldMarker { __FandheNpyIoHoldMarker }
4879/// }
4880///
4881/// fn __probe_tensor(x: &fandhe_ai::Tensor<f32>) {
4882///     let _: __FandheNpyIoHoldMarker = fandhe_ai::Tensor::load_npy(x);
4883///     let _: __FandheNpyIoHoldMarker = x.save_npy();
4884///     let _: __FandheNpyIoHoldMarker = fandhe_ai::Tensor::load_npz(x);
4885///     let _: __FandheNpyIoHoldMarker = x.save_npz();
4886/// }
4887/// ```
4888#[cfg(doctest)]
4889#[allow(dead_code)]
4890struct NpyIoHoldDoctestGuard;
4891
4892/// イシュー #2188(親 #2131「PyTorch/TF 置き換えの API 網羅(対応表の
4893/// 行内深掘り)」)で導入し、イシュー #2369(親 #2362)で**代替案専用へ縮小**
4894/// した facade 公開保留の doctest 足場。
4895/// `TrainStepHoldDoctestGuard`(#2184)と同型の「正のプローブ 1 ブロック
4896/// 方式」を採る: facade の全 `pub mod` を glob import したスコープに、
4897/// 本ブロック内でのみ定義した、`fandhe_ai::compat::Sequential` への inherent
4898/// メソッドを装うトレイト(`__FandheModelIoHoldProbe`)を導入し、実際に使う
4899/// 呼び出しを書く。facade が `Sequential` へ inherent メソッド
4900/// (`save`/`load`/`save_model`/`load_model`)を追加すると、inherent メソッドが
4901/// トレイトメソッドより優先解決されるため、本プローブの trait 経由呼び出しが
4902/// 型・引数不一致でエラーコードに依存せずコンパイル失敗する。
4903///
4904/// `docs/compat-model-io-decision.md` §2 は代替公開 API 案として
4905/// `Sequential::save(&self, dir)`/`Sequential::load(dir)`(`_model`
4906/// 接尾辞なしの inherent メソッド)も併記しているため、本トレイトは
4907/// `save_model`/`load_model` に加えて `save`/`load` も
4908/// `__FandheModelIoHoldProbe` のメソッドとして持つ(PR #2317 review
4909/// 指摘: 旧版は `_model` 接尾辞ありの 2 名だけを検出しており、代替名
4910/// `Sequential::save`/`Sequential::load` を facade が追加しても本
4911/// プローブ・`api_surface.rs` のソース走査のいずれも検出できなかった)。
4912///
4913/// **#2369 で自由関数 `compat::save_model`/`compat::load_model` と
4914/// `compat::ModelIoError` は公開済み**(親 #2362 でユーザー承認済みの主案。
4915/// 承認事項 1)。そのため、旧版が持っていたローカル定義(`model_io` モジュール・
4916/// 自由関数・エラー型のプローブ)は glob 衝突で本 doctest 自体を壊すため撤去し、
4917/// 正の確認は `api_surface.rs` の正ガード
4918/// (`model_io_items_are_reachable_via_facade` 等)へ移した。**残る保留**は
4919/// 代替案の inherent メソッド `Sequential::save`/`Sequential::load`(および
4920/// 同じく承認外の `Sequential::save_model`/`Sequential::load_model`)で、
4921/// 本 doctest と `api_surface.rs` の `Sequential` 内 `fn save`/`fn load`
4922/// 走査・workspace インベントリ(0 件固定)が固定する
4923/// (`docs/compat-model-io-decision.md` §7・§10)。
4924///
4925/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
4926/// model_io_hold_doctest_globs_all_pub_modules`・
4927/// `model_io_hold_doctest_probe_body_matches_fixed_contract`・
4928/// `workspace_declares_sequential_alt_save_load_fn_names_only_in_allowed_locations`)
4929/// との多層防御の位置づけは同 doc §7 を参照。
4930///
4931/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
4932/// できること
4933///
4934/// ```
4935/// use fandhe_ai::*;
4936/// use fandhe_ai::compat::*;
4937/// use fandhe_ai::optim::*;
4938/// use fandhe_ai::data::*;
4939/// use fandhe_ai::nn::*;
4940/// use fandhe_ai::nn::init::*;
4941/// use fandhe_ai::nn::rnn::*;
4942/// use fandhe_ai::nn::kv_cache::*;
4943/// use fandhe_ai::nn::loss::*;
4944/// use fandhe_ai::interop::*;
4945/// use fandhe_ai::interop::onnx::*;
4946/// use fandhe_ai::interop::safetensors::*;
4947/// use fandhe_ai::interop::npy::*;
4948/// use fandhe_ai::model::*;
4949/// use fandhe_ai::inference::*;
4950/// use fandhe_ai::text::*;
4951/// use fandhe_ai::models::*;
4952/// use fandhe_ai::distributed::*;
4953///
4954/// struct __FandheModelIoHoldMarker;
4955///
4956/// trait __FandheModelIoHoldProbe {
4957///     fn save_model(&self) -> __FandheModelIoHoldMarker;
4958///     fn load_model(&self) -> __FandheModelIoHoldMarker;
4959///     fn save(&self) -> __FandheModelIoHoldMarker;
4960///     fn load(&self) -> __FandheModelIoHoldMarker;
4961/// }
4962///
4963/// impl __FandheModelIoHoldProbe for fandhe_ai::compat::Sequential {
4964///     fn save_model(&self) -> __FandheModelIoHoldMarker {
4965///         __FandheModelIoHoldMarker
4966///     }
4967///     fn load_model(&self) -> __FandheModelIoHoldMarker {
4968///         __FandheModelIoHoldMarker
4969///     }
4970///     fn save(&self) -> __FandheModelIoHoldMarker {
4971///         __FandheModelIoHoldMarker
4972///     }
4973///     fn load(&self) -> __FandheModelIoHoldMarker {
4974///         __FandheModelIoHoldMarker
4975///     }
4976/// }
4977///
4978/// fn __probe_inherent_method(seq: &fandhe_ai::compat::Sequential) {
4979///     let _: __FandheModelIoHoldMarker =
4980///         fandhe_ai::compat::Sequential::save_model(seq);
4981///     let _: __FandheModelIoHoldMarker =
4982///         fandhe_ai::compat::Sequential::load_model(seq);
4983///     let _: __FandheModelIoHoldMarker =
4984///         fandhe_ai::compat::Sequential::save(seq);
4985///     let _: __FandheModelIoHoldMarker =
4986///         fandhe_ai::compat::Sequential::load(seq);
4987/// }
4988/// ```
4989#[cfg(doctest)]
4990#[allow(dead_code)]
4991struct ModelIoHoldDoctestGuard;
4992
4993/// FFT(`rfft`/`irfft`/`fft`/`ifft`/`stft`/`istft`。イシュー #2631〜#2633・親 #2630・ルート #2499 Phase 4)の
4994/// 未承認経路を固定する doctest 足場(承認形は #2678 で公開済み)。`VarActivationOpsHoldDoctestGuard` と
4995/// 同型の「正のプローブ 1 ブロック方式」を採る。
4996///
4997/// 下の doctest は全 `pub mod` を glob import したスコープへ、未承認経路に対応するローカル定義(モジュール `fft_ops`・`fft`)と、
4998/// 同名メソッドを持つプローブ用トレイト(受け手: `Tape`)を置き、修飾なしの関数呼び出しと修飾付き(UFCS)のメソッド呼び出しの両方を行う。
4999/// facade が同名のモジュール・関数・型を glob 可能な位置へ公開するか、上の受け手へ同名の inherent メソッドを公開すると、
5000/// 名前解決の曖昧性または呼び出しシグネチャの不一致でエラーコードに依存せずコンパイルが失敗する。
5001///
5002/// **#2678 での部分反転**(ルート #2499 の一括承認 `issuecomment-6033824965`・`docs/compat-api-scope.md` §5.1。
5003/// `VarActivationOpsHoldDoctestGuard` の #2516 部分反転と同型): `Var::{rfft,irfft,fft,ifft,stft,istft}` と `FftNorm`・`StftPadMode`・`StftOptions`・`IstftOptions` の再エクスポートは承認形どおり公開済みのため、
5004/// 該当する UFCS 行と、受け手 `Var` の `impl` ブロック、型 `FftNorm`・`StftOptions`・`IstftOptions`・`StftPadMode` のローカル定義(ルート再エクスポートと glob 衝突するため)を外した(残すと公開した inherent メソッドや再エクスポート型との衝突でコンパイルが失敗する)。残した受け手の `impl` ブロックは、同じトレイトの別メソッド分のプローブとして維持する。
5005/// 引き続き拒否する未承認経路: モジュール `fft_ops`・`fft`・残した受け手(`Tape`)上の、公開していない名前の同名メソッド。
5006/// **#2847 での部分反転**(ルート #2499 の `issuecomment-6052732061`・決定記録 §11.5・§12): `Tape::gradcheck`(関連関数)と型 `GradcheckOptions`・`GradcheckReport`(ルート再エクスポート)を承認形どおり公開したため、
5007/// 型 2 つのローカル定義・`__probe_types`・`Tape::gradcheck` の UFCS 行を外した。モジュール名・裸の自由関数・`Var`/`Tensor<f32>` 上の同名メソッドの保留は維持する(`Tape` の `impl` ブロックは #2678 の先例どおり残す)。
5008/// **検出範囲の限定**: 列挙した名前・型・受け手に限り、マクロ生成や別名経由の公開までは保証しない。
5009/// 公開済み側の正ガード(薄い委譲・シグネチャ・到達性)は `crates/facade/tests/api_surface.rs` が固定する。
5010///
5011/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
5012/// fft_ops_hold_doctest_globs_all_pub_modules`・
5013/// `fft_ops_hold_doctest_probe_body_matches_fixed_contract`・
5014/// `facade_does_not_reexport_or_declare_fft_ops`・
5015/// `workspace_declares_fft_ops_fn_names_only_in_allowed_locations`)との
5016/// 多層防御の位置づけは同決定記録 §9 を参照。
5017///
5018/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
5019/// できること
5020///
5021/// ```
5022/// use fandhe_ai::*;
5023/// use fandhe_ai::compat::*;
5024/// use fandhe_ai::optim::*;
5025/// use fandhe_ai::data::*;
5026/// use fandhe_ai::nn::*;
5027/// use fandhe_ai::nn::init::*;
5028/// use fandhe_ai::nn::rnn::*;
5029/// use fandhe_ai::nn::kv_cache::*;
5030/// use fandhe_ai::nn::loss::*;
5031/// use fandhe_ai::interop::*;
5032/// use fandhe_ai::interop::onnx::*;
5033/// use fandhe_ai::interop::safetensors::*;
5034/// use fandhe_ai::interop::npy::*;
5035/// use fandhe_ai::model::*;
5036/// use fandhe_ai::inference::*;
5037/// use fandhe_ai::text::*;
5038/// use fandhe_ai::models::*;
5039/// use fandhe_ai::distributed::*;
5040///
5041/// mod __fandhe_fft_hold_probe {
5042///     pub mod fft_ops {
5043///         pub fn rfft() {}
5044///         pub fn irfft() {}
5045///         pub fn fft() {}
5046///         pub fn ifft() {}
5047///         pub fn stft() {}
5048///         pub fn istft() {}
5049///     }
5050///     pub mod fft {
5051///         pub fn __mark() {}
5052///     }
5053/// }
5054/// use __fandhe_fft_hold_probe::*;
5055///
5056/// struct __FandheFftHoldMarker;
5057///
5058/// trait __FandheFftHoldProbe {
5059///     fn rfft(&self) -> __FandheFftHoldMarker;
5060///     fn irfft(&self) -> __FandheFftHoldMarker;
5061///     fn fft(&self) -> __FandheFftHoldMarker;
5062///     fn ifft(&self) -> __FandheFftHoldMarker;
5063///     fn stft(&self) -> __FandheFftHoldMarker;
5064///     fn istft(&self) -> __FandheFftHoldMarker;
5065/// }
5066///
5067/// impl __FandheFftHoldProbe for fandhe_ai::Tape {
5068///     fn rfft(&self) -> __FandheFftHoldMarker {
5069///         __FandheFftHoldMarker
5070///     }
5071///     fn irfft(&self) -> __FandheFftHoldMarker {
5072///         __FandheFftHoldMarker
5073///     }
5074///     fn fft(&self) -> __FandheFftHoldMarker {
5075///         __FandheFftHoldMarker
5076///     }
5077///     fn ifft(&self) -> __FandheFftHoldMarker {
5078///         __FandheFftHoldMarker
5079///     }
5080///     fn stft(&self) -> __FandheFftHoldMarker {
5081///         __FandheFftHoldMarker
5082///     }
5083///     fn istft(&self) -> __FandheFftHoldMarker {
5084///         __FandheFftHoldMarker
5085///     }
5086/// }
5087///
5088/// fn __probe_free_fns() {
5089///     // 修飾なし呼び出し(`use fandhe_ai::*;` が同名を glob 公開して
5090///     // いれば、名前解決自体が曖昧になり E0659 でコンパイル失敗する)。
5091///     fft_ops::rfft();
5092///     fft_ops::irfft();
5093///     fft_ops::fft();
5094///     fft_ops::ifft();
5095///     fft_ops::stft();
5096///     fft_ops::istft();
5097///     fft::__mark();
5098/// }
5099///
5100/// fn __probe_methods(_v: &fandhe_ai::Var<'_>, tape: &fandhe_ai::Tape) {
5101///     let _: __FandheFftHoldMarker = fandhe_ai::Tape::rfft(tape);
5102///     let _: __FandheFftHoldMarker = fandhe_ai::Tape::irfft(tape);
5103///     let _: __FandheFftHoldMarker = fandhe_ai::Tape::fft(tape);
5104///     let _: __FandheFftHoldMarker = fandhe_ai::Tape::ifft(tape);
5105///     let _: __FandheFftHoldMarker = fandhe_ai::Tape::stft(tape);
5106///     let _: __FandheFftHoldMarker = fandhe_ai::Tape::istft(tape);
5107/// }
5108/// ```
5109#[cfg(doctest)]
5110#[allow(dead_code)]
5111struct FftOpsHoldDoctestGuard;
5112
5113/// 逆三角関数・双曲線関数(`atan`・`asin`・`acos`・`atan2`・`sinh`・`cosh`・
5114/// `asinh`・`acosh`・`atanh`。イシュー #2634・親 #2625・ルート #2499
5115/// Phase 4)のうち未承認の経路を facade 公開面から締め出す保留ガード(`FftOpsHoldDoctestGuard`
5116/// と同型の正のプローブ 1 ブロック方式)。
5117///
5118/// 下の doctest は全 `pub mod` を glob import したスコープへ、未承認経路に対応するローカル定義(モジュール `trig_ops`)と、
5119/// 同名メソッドを持つプローブ用トレイト(受け手: `Tape`)を置き、修飾なしの関数呼び出しと修飾付き(UFCS)のメソッド呼び出しの両方を行う。
5120/// facade が同名のモジュール・関数・型を glob 可能な位置へ公開するか、上の受け手へ同名の inherent メソッドを公開すると、
5121/// 名前解決の曖昧性または呼び出しシグネチャの不一致でエラーコードに依存せずコンパイルが失敗する。
5122///
5123/// **#2678 での部分反転**(ルート #2499 の一括承認 `issuecomment-6033824965`・`docs/compat-api-scope.md` §5.1。
5124/// `VarActivationOpsHoldDoctestGuard` の #2516 部分反転と同型): `Var::{atan,asin,acos,sinh,cosh,asinh,acosh,atanh,atan2}` は承認形どおり公開済みのため、
5125/// 該当する UFCS 行と、受け手 `Var` の `impl` ブロックを外した(残すと公開した inherent メソッドや再エクスポート型との衝突でコンパイルが失敗する)。残した受け手の `impl` ブロックは、同じトレイトの別メソッド分のプローブとして維持する。
5126/// 引き続き拒否する未承認経路: モジュール `trig_ops`・残した受け手(`Tape`)上の、公開していない名前の同名メソッド。
5127/// **検出範囲の限定**: 列挙した名前・型・受け手に限り、マクロ生成や別名経由の公開までは保証しない。
5128/// 公開済み側の正ガード(薄い委譲・シグネチャ・到達性)は `crates/facade/tests/api_surface.rs` が固定する。
5129///
5130/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
5131/// trig_ops_hold_doctest_globs_all_pub_modules`・
5132/// `trig_ops_hold_doctest_probe_body_matches_fixed_contract`・
5133/// `facade_does_not_reexport_or_declare_trig_ops`・
5134/// `workspace_declares_trig_ops_fn_names_only_in_allowed_locations`)との
5135/// 多層防御として働く。
5136///
5137/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
5138/// できること
5139///
5140/// ```
5141/// use fandhe_ai::*;
5142/// use fandhe_ai::compat::*;
5143/// use fandhe_ai::optim::*;
5144/// use fandhe_ai::data::*;
5145/// use fandhe_ai::nn::*;
5146/// use fandhe_ai::nn::init::*;
5147/// use fandhe_ai::nn::rnn::*;
5148/// use fandhe_ai::nn::kv_cache::*;
5149/// use fandhe_ai::nn::loss::*;
5150/// use fandhe_ai::interop::*;
5151/// use fandhe_ai::interop::onnx::*;
5152/// use fandhe_ai::interop::safetensors::*;
5153/// use fandhe_ai::interop::npy::*;
5154/// use fandhe_ai::model::*;
5155/// use fandhe_ai::inference::*;
5156/// use fandhe_ai::text::*;
5157/// use fandhe_ai::models::*;
5158/// use fandhe_ai::distributed::*;
5159///
5160/// mod __fandhe_trig_ops_hold_probe {
5161///     pub mod trig_ops {
5162///         pub fn atan() {}
5163///         pub fn asin() {}
5164///         pub fn acos() {}
5165///         pub fn sinh() {}
5166///         pub fn cosh() {}
5167///         pub fn asinh() {}
5168///         pub fn acosh() {}
5169///         pub fn atanh() {}
5170///         pub fn atan2() {}
5171///     }
5172/// }
5173/// use __fandhe_trig_ops_hold_probe::*;
5174///
5175/// struct __FandheTrigOpsHoldMarker;
5176///
5177/// trait __FandheTrigOpsHoldProbe {
5178///     fn atan(&self) -> __FandheTrigOpsHoldMarker;
5179///     fn asin(&self) -> __FandheTrigOpsHoldMarker;
5180///     fn acos(&self) -> __FandheTrigOpsHoldMarker;
5181///     fn sinh(&self) -> __FandheTrigOpsHoldMarker;
5182///     fn cosh(&self) -> __FandheTrigOpsHoldMarker;
5183///     fn asinh(&self) -> __FandheTrigOpsHoldMarker;
5184///     fn acosh(&self) -> __FandheTrigOpsHoldMarker;
5185///     fn atanh(&self) -> __FandheTrigOpsHoldMarker;
5186///     fn atan2(&self) -> __FandheTrigOpsHoldMarker;
5187/// }
5188///
5189/// impl __FandheTrigOpsHoldProbe for fandhe_ai::Tape {
5190///     fn atan(&self) -> __FandheTrigOpsHoldMarker {
5191///         __FandheTrigOpsHoldMarker
5192///     }
5193///     fn asin(&self) -> __FandheTrigOpsHoldMarker {
5194///         __FandheTrigOpsHoldMarker
5195///     }
5196///     fn acos(&self) -> __FandheTrigOpsHoldMarker {
5197///         __FandheTrigOpsHoldMarker
5198///     }
5199///     fn sinh(&self) -> __FandheTrigOpsHoldMarker {
5200///         __FandheTrigOpsHoldMarker
5201///     }
5202///     fn cosh(&self) -> __FandheTrigOpsHoldMarker {
5203///         __FandheTrigOpsHoldMarker
5204///     }
5205///     fn asinh(&self) -> __FandheTrigOpsHoldMarker {
5206///         __FandheTrigOpsHoldMarker
5207///     }
5208///     fn acosh(&self) -> __FandheTrigOpsHoldMarker {
5209///         __FandheTrigOpsHoldMarker
5210///     }
5211///     fn atanh(&self) -> __FandheTrigOpsHoldMarker {
5212///         __FandheTrigOpsHoldMarker
5213///     }
5214///     fn atan2(&self) -> __FandheTrigOpsHoldMarker {
5215///         __FandheTrigOpsHoldMarker
5216///     }
5217/// }
5218///
5219/// fn __probe_free_fns() {
5220///     // 修飾なし呼び出し(`use fandhe_ai::*;` が同名を glob 公開して
5221///     // いれば、名前解決自体が曖昧になり E0659 でコンパイル失敗する)。
5222///     trig_ops::atan();
5223///     trig_ops::asin();
5224///     trig_ops::acos();
5225///     trig_ops::sinh();
5226///     trig_ops::cosh();
5227///     trig_ops::asinh();
5228///     trig_ops::acosh();
5229///     trig_ops::atanh();
5230///     trig_ops::atan2();
5231/// }
5232///
5233/// fn __probe_methods(_v: &fandhe_ai::Var<'_>, tape: &fandhe_ai::Tape) {
5234///     let _: __FandheTrigOpsHoldMarker = fandhe_ai::Tape::atan(tape);
5235///     let _: __FandheTrigOpsHoldMarker = fandhe_ai::Tape::asin(tape);
5236///     let _: __FandheTrigOpsHoldMarker = fandhe_ai::Tape::acos(tape);
5237///     let _: __FandheTrigOpsHoldMarker = fandhe_ai::Tape::sinh(tape);
5238///     let _: __FandheTrigOpsHoldMarker = fandhe_ai::Tape::cosh(tape);
5239///     let _: __FandheTrigOpsHoldMarker = fandhe_ai::Tape::asinh(tape);
5240///     let _: __FandheTrigOpsHoldMarker = fandhe_ai::Tape::acosh(tape);
5241///     let _: __FandheTrigOpsHoldMarker = fandhe_ai::Tape::atanh(tape);
5242///     let _: __FandheTrigOpsHoldMarker = fandhe_ai::Tape::atan2(tape);
5243/// }
5244/// ```
5245#[cfg(doctest)]
5246#[allow(dead_code)]
5247struct TrigOpsHoldDoctestGuard;
5248
5249/// 非有限値の判定・置換(`isnan`・`isinf`・`isfinite`・`nan_to_num`。イシュー #2635・
5250/// 親 #2625・ルート #2499 Phase 4)のうち未承認の経路を facade 公開面から締め出す保留ガード
5251/// (`TrigOpsHoldDoctestGuard` と同型の正のプローブ 1 ブロック方式)。
5252///
5253/// 下の doctest は全 `pub mod` を glob import したスコープへ、未承認経路に対応するローカル定義(モジュール `nonfinite_ops`)と、
5254/// 同名メソッドを持つプローブ用トレイト(受け手: `Tape`・`Tensor<f32>`)を置き、修飾なしの関数呼び出しと修飾付き(UFCS)のメソッド呼び出しの両方を行う。
5255/// facade が同名のモジュール・関数・型を glob 可能な位置へ公開するか、上の受け手へ同名の inherent メソッドを公開すると、
5256/// 名前解決の曖昧性または呼び出しシグネチャの不一致でエラーコードに依存せずコンパイルが失敗する(`Tensor` は facade から再エクスポートされるため、`tensor-core` 側への同名メソッド追加も検出する)。
5257///
5258/// **#2678 での部分反転**(ルート #2499 の一括承認 `issuecomment-6033824965`・`docs/compat-api-scope.md` §5.1。
5259/// `VarActivationOpsHoldDoctestGuard` の #2516 部分反転と同型): `Var::{isnan,isinf,isfinite,nan_to_num}` は承認形どおり公開済みのため、
5260/// 該当する UFCS 行と、受け手 `Var` の `impl` ブロックを外した(残すと公開した inherent メソッドや再エクスポート型との衝突でコンパイルが失敗する)。残した受け手の `impl` ブロックは、同じトレイトの別メソッド分のプローブとして維持する。
5261/// 引き続き拒否する未承認経路: モジュール `nonfinite_ops`・残した受け手(`Tape`・`Tensor<f32>`)上の、公開していない名前の同名メソッド。
5262/// **検出範囲の限定**: 列挙した名前・型・受け手に限り、マクロ生成や別名経由の公開までは保証しない。
5263/// 公開済み側の正ガード(薄い委譲・シグネチャ・到達性)は `crates/facade/tests/api_surface.rs` が固定する。
5264///
5265/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
5266/// nonfinite_ops_hold_doctest_globs_all_pub_modules`・
5267/// `nonfinite_ops_hold_doctest_probe_body_matches_fixed_contract`・
5268/// `facade_does_not_reexport_or_declare_nonfinite_ops`・
5269/// `workspace_declares_nonfinite_ops_fn_names_only_in_allowed_locations`)との
5270/// 多層防御として働く。
5271///
5272/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
5273/// できること
5274///
5275/// ```
5276/// use fandhe_ai::*;
5277/// use fandhe_ai::compat::*;
5278/// use fandhe_ai::optim::*;
5279/// use fandhe_ai::data::*;
5280/// use fandhe_ai::nn::*;
5281/// use fandhe_ai::nn::init::*;
5282/// use fandhe_ai::nn::rnn::*;
5283/// use fandhe_ai::nn::kv_cache::*;
5284/// use fandhe_ai::nn::loss::*;
5285/// use fandhe_ai::interop::*;
5286/// use fandhe_ai::interop::onnx::*;
5287/// use fandhe_ai::interop::safetensors::*;
5288/// use fandhe_ai::interop::npy::*;
5289/// use fandhe_ai::model::*;
5290/// use fandhe_ai::inference::*;
5291/// use fandhe_ai::text::*;
5292/// use fandhe_ai::models::*;
5293/// use fandhe_ai::distributed::*;
5294///
5295/// mod __fandhe_nonfinite_hold_probe {
5296///     pub mod nonfinite_ops {
5297///         pub fn isnan() {}
5298///         pub fn isinf() {}
5299///         pub fn isfinite() {}
5300///         pub fn nan_to_num() {}
5301///     }
5302/// }
5303/// use __fandhe_nonfinite_hold_probe::*;
5304///
5305/// struct __FandheNonfiniteOpsHoldMarker;
5306///
5307/// trait __FandheNonfiniteOpsHoldProbe {
5308///     fn isnan(&self) -> __FandheNonfiniteOpsHoldMarker;
5309///     fn isinf(&self) -> __FandheNonfiniteOpsHoldMarker;
5310///     fn isfinite(&self) -> __FandheNonfiniteOpsHoldMarker;
5311///     fn nan_to_num(&self) -> __FandheNonfiniteOpsHoldMarker;
5312/// }
5313///
5314/// impl __FandheNonfiniteOpsHoldProbe for fandhe_ai::Tape {
5315///     fn isnan(&self) -> __FandheNonfiniteOpsHoldMarker {
5316///         __FandheNonfiniteOpsHoldMarker
5317///     }
5318///     fn isinf(&self) -> __FandheNonfiniteOpsHoldMarker {
5319///         __FandheNonfiniteOpsHoldMarker
5320///     }
5321///     fn isfinite(&self) -> __FandheNonfiniteOpsHoldMarker {
5322///         __FandheNonfiniteOpsHoldMarker
5323///     }
5324///     fn nan_to_num(&self) -> __FandheNonfiniteOpsHoldMarker {
5325///         __FandheNonfiniteOpsHoldMarker
5326///     }
5327/// }
5328///
5329/// impl __FandheNonfiniteOpsHoldProbe for fandhe_ai::Tensor<f32> {
5330///     fn isnan(&self) -> __FandheNonfiniteOpsHoldMarker {
5331///         __FandheNonfiniteOpsHoldMarker
5332///     }
5333///     fn isinf(&self) -> __FandheNonfiniteOpsHoldMarker {
5334///         __FandheNonfiniteOpsHoldMarker
5335///     }
5336///     fn isfinite(&self) -> __FandheNonfiniteOpsHoldMarker {
5337///         __FandheNonfiniteOpsHoldMarker
5338///     }
5339///     fn nan_to_num(&self) -> __FandheNonfiniteOpsHoldMarker {
5340///         __FandheNonfiniteOpsHoldMarker
5341///     }
5342/// }
5343///
5344/// impl __FandheNonfiniteOpsHoldProbe for fandhe_ai::Tensor<bool> {
5345///     fn isnan(&self) -> __FandheNonfiniteOpsHoldMarker {
5346///         __FandheNonfiniteOpsHoldMarker
5347///     }
5348///     fn isinf(&self) -> __FandheNonfiniteOpsHoldMarker {
5349///         __FandheNonfiniteOpsHoldMarker
5350///     }
5351///     fn isfinite(&self) -> __FandheNonfiniteOpsHoldMarker {
5352///         __FandheNonfiniteOpsHoldMarker
5353///     }
5354///     fn nan_to_num(&self) -> __FandheNonfiniteOpsHoldMarker {
5355///         __FandheNonfiniteOpsHoldMarker
5356///     }
5357/// }
5358///
5359/// fn __probe_free_fns() {
5360///     // 修飾なし呼び出し(`use fandhe_ai::*;` が同名を glob 公開して
5361///     // いれば、名前解決自体が曖昧になり E0659 でコンパイル失敗する)。
5362///     nonfinite_ops::isnan();
5363///     nonfinite_ops::isinf();
5364///     nonfinite_ops::isfinite();
5365///     nonfinite_ops::nan_to_num();
5366/// }
5367///
5368/// fn __probe_methods(
5369///     _v: &fandhe_ai::Var<'_>,
5370///     tape: &fandhe_ai::Tape,
5371///     tf: &fandhe_ai::Tensor<f32>,
5372///     tb: &fandhe_ai::Tensor<bool>,
5373/// ) {
5374///     let _: __FandheNonfiniteOpsHoldMarker = fandhe_ai::Tape::isnan(tape);
5375///     let _: __FandheNonfiniteOpsHoldMarker = fandhe_ai::Tape::isinf(tape);
5376///     let _: __FandheNonfiniteOpsHoldMarker = fandhe_ai::Tape::isfinite(tape);
5377///     let _: __FandheNonfiniteOpsHoldMarker = fandhe_ai::Tape::nan_to_num(tape);
5378///     let _: __FandheNonfiniteOpsHoldMarker = fandhe_ai::Tensor::<f32>::isnan(tf);
5379///     let _: __FandheNonfiniteOpsHoldMarker = fandhe_ai::Tensor::<f32>::isinf(tf);
5380///     let _: __FandheNonfiniteOpsHoldMarker = fandhe_ai::Tensor::<f32>::isfinite(tf);
5381///     let _: __FandheNonfiniteOpsHoldMarker = fandhe_ai::Tensor::<f32>::nan_to_num(tf);
5382///     let _: __FandheNonfiniteOpsHoldMarker = fandhe_ai::Tensor::<bool>::isnan(tb);
5383///     let _: __FandheNonfiniteOpsHoldMarker = fandhe_ai::Tensor::<bool>::isinf(tb);
5384///     let _: __FandheNonfiniteOpsHoldMarker = fandhe_ai::Tensor::<bool>::isfinite(tb);
5385///     let _: __FandheNonfiniteOpsHoldMarker = fandhe_ai::Tensor::<bool>::nan_to_num(tb);
5386/// }
5387/// ```
5388#[cfg(doctest)]
5389#[allow(dead_code)]
5390struct NonfiniteOpsHoldDoctestGuard;
5391
5392/// 累積最大・最小・累積 logsumexp(`cummax`・`cummin`・`logcumsumexp`。イシュー
5393/// #2636・親 #2625・ルート #2499 Phase 4)のうち未承認の経路を facade 公開面から締め出す保留ガード
5394/// (`NonfiniteOpsHoldDoctestGuard` と同型の正のプローブ 1 ブロック方式)。
5395///
5396/// 下の doctest は全 `pub mod` を glob import したスコープへ、未承認経路に対応するローカル定義(モジュール `cumulative_ops`・`cumulative`)と、
5397/// 同名メソッドを持つプローブ用トレイト(受け手: `Tape`・`Tensor<f32>`)を置き、修飾なしの関数呼び出しと修飾付き(UFCS)のメソッド呼び出しの両方を行う。
5398/// facade が同名のモジュール・関数・型を glob 可能な位置へ公開するか、上の受け手へ同名の inherent メソッドを公開すると、
5399/// 名前解決の曖昧性または呼び出しシグネチャの不一致でエラーコードに依存せずコンパイルが失敗する(`Tensor` は facade から再エクスポートされるため、`tensor-core` 側への同名メソッド追加も検出する)。
5400///
5401/// **#2678 での部分反転**(ルート #2499 の一括承認 `issuecomment-6033824965`・`docs/compat-api-scope.md` §5.1。
5402/// `VarActivationOpsHoldDoctestGuard` の #2516 部分反転と同型): `Var::{cummax,cummin,logcumsumexp}` は承認形どおり公開済みのため、
5403/// 該当する UFCS 行と、受け手 `Var` の `impl` ブロックを外した(残すと公開した inherent メソッドや再エクスポート型との衝突でコンパイルが失敗する)。残した受け手の `impl` ブロックは、同じトレイトの別メソッド分のプローブとして維持する。
5404/// 引き続き拒否する未承認経路: モジュール `cumulative_ops`・`cumulative`・残した受け手(`Tape`・`Tensor<f32>`)上の、公開していない名前の同名メソッド。
5405/// **検出範囲の限定**: 列挙した名前・型・受け手に限り、マクロ生成や別名経由の公開までは保証しない。
5406/// 公開済み側の正ガード(薄い委譲・シグネチャ・到達性)は `crates/facade/tests/api_surface.rs` が固定する。
5407///
5408/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
5409/// cumulative_ops_hold_doctest_globs_all_pub_modules`・
5410/// `cumulative_ops_hold_doctest_probe_body_matches_fixed_contract`・
5411/// `facade_does_not_reexport_or_declare_cumulative_ops`・
5412/// `workspace_declares_cumulative_ops_fn_names_only_in_allowed_locations`)との
5413/// 多層防御として働く。
5414///
5415/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
5416/// できること
5417///
5418/// ```
5419/// use fandhe_ai::*;
5420/// use fandhe_ai::compat::*;
5421/// use fandhe_ai::optim::*;
5422/// use fandhe_ai::data::*;
5423/// use fandhe_ai::nn::*;
5424/// use fandhe_ai::nn::init::*;
5425/// use fandhe_ai::nn::rnn::*;
5426/// use fandhe_ai::nn::kv_cache::*;
5427/// use fandhe_ai::nn::loss::*;
5428/// use fandhe_ai::interop::*;
5429/// use fandhe_ai::interop::onnx::*;
5430/// use fandhe_ai::interop::safetensors::*;
5431/// use fandhe_ai::interop::npy::*;
5432/// use fandhe_ai::model::*;
5433/// use fandhe_ai::inference::*;
5434/// use fandhe_ai::text::*;
5435/// use fandhe_ai::models::*;
5436/// use fandhe_ai::distributed::*;
5437///
5438/// mod __fandhe_cumulative_hold_probe {
5439///     pub mod cumulative_ops {
5440///         pub fn cummax() {}
5441///         pub fn cummin() {}
5442///         pub fn logcumsumexp() {}
5443///     }
5444///     pub mod cumulative {
5445///         pub fn __mark() {}
5446///     }
5447/// }
5448/// use __fandhe_cumulative_hold_probe::*;
5449///
5450/// struct __FandheCumulativeOpsHoldMarker;
5451///
5452/// trait __FandheCumulativeOpsHoldProbe {
5453///     fn cummax(&self) -> __FandheCumulativeOpsHoldMarker;
5454///     fn cummin(&self) -> __FandheCumulativeOpsHoldMarker;
5455///     fn logcumsumexp(&self) -> __FandheCumulativeOpsHoldMarker;
5456/// }
5457///
5458/// impl __FandheCumulativeOpsHoldProbe for fandhe_ai::Tape {
5459///     fn cummax(&self) -> __FandheCumulativeOpsHoldMarker {
5460///         __FandheCumulativeOpsHoldMarker
5461///     }
5462///     fn cummin(&self) -> __FandheCumulativeOpsHoldMarker {
5463///         __FandheCumulativeOpsHoldMarker
5464///     }
5465///     fn logcumsumexp(&self) -> __FandheCumulativeOpsHoldMarker {
5466///         __FandheCumulativeOpsHoldMarker
5467///     }
5468/// }
5469///
5470/// impl __FandheCumulativeOpsHoldProbe for fandhe_ai::Tensor<f32> {
5471///     fn cummax(&self) -> __FandheCumulativeOpsHoldMarker {
5472///         __FandheCumulativeOpsHoldMarker
5473///     }
5474///     fn cummin(&self) -> __FandheCumulativeOpsHoldMarker {
5475///         __FandheCumulativeOpsHoldMarker
5476///     }
5477///     fn logcumsumexp(&self) -> __FandheCumulativeOpsHoldMarker {
5478///         __FandheCumulativeOpsHoldMarker
5479///     }
5480/// }
5481///
5482/// fn __probe_free_fns() {
5483///     // 修飾なし呼び出し(`use fandhe_ai::*;` が同名を glob 公開して
5484///     // いれば、名前解決自体が曖昧になり E0659 でコンパイル失敗する)。
5485///     cumulative_ops::cummax();
5486///     cumulative_ops::cummin();
5487///     cumulative_ops::logcumsumexp();
5488///     cumulative::__mark();
5489/// }
5490///
5491/// fn __probe_methods(
5492///     _v: &fandhe_ai::Var<'_>,
5493///     tape: &fandhe_ai::Tape,
5494///     tf: &fandhe_ai::Tensor<f32>,
5495/// ) {
5496///     let _: __FandheCumulativeOpsHoldMarker = fandhe_ai::Tape::cummax(tape);
5497///     let _: __FandheCumulativeOpsHoldMarker = fandhe_ai::Tape::cummin(tape);
5498///     let _: __FandheCumulativeOpsHoldMarker = fandhe_ai::Tape::logcumsumexp(tape);
5499///     let _: __FandheCumulativeOpsHoldMarker = fandhe_ai::Tensor::<f32>::cummax(tf);
5500///     let _: __FandheCumulativeOpsHoldMarker = fandhe_ai::Tensor::<f32>::cummin(tf);
5501///     let _: __FandheCumulativeOpsHoldMarker = fandhe_ai::Tensor::<f32>::logcumsumexp(tf);
5502/// }
5503/// ```
5504#[cfg(doctest)]
5505#[allow(dead_code)]
5506struct CumulativeOpsHoldDoctestGuard;
5507
5508/// 順序統計・NaN 無視縮約(`median`・`kthvalue`・`quantile`・`nanmean`・`nansum`。
5509/// イシュー #2637・親 #2625・ルート #2499 Phase 4)のうち未承認の経路を facade 公開面から締め出す保留ガード(`CumulativeOpsHoldDoctestGuard` と同型の正のプローブ 1 ブロック方式)。
5510///
5511/// 下の doctest は全 `pub mod` を glob import したスコープへ、未承認経路に対応するローカル定義(モジュール `stat_reduce_ops`・`stat_reduce`、型 `StatReduceError`)と、
5512/// 同名メソッドを持つプローブ用トレイト(受け手: `Tape`・`Tensor<f32>`)を置き、修飾なしの関数呼び出しと修飾付き(UFCS)のメソッド呼び出しの両方を行う。
5513/// facade が同名のモジュール・関数・型を glob 可能な位置へ公開するか、上の受け手へ同名の inherent メソッドを公開すると、
5514/// 名前解決の曖昧性または呼び出しシグネチャの不一致でエラーコードに依存せずコンパイルが失敗する(`Tensor` は facade から再エクスポートされるため、`tensor-core` 側への同名メソッド追加も検出する)。
5515///
5516/// **#2678 での部分反転**(ルート #2499 の一括承認 `issuecomment-6033824965`・`docs/compat-api-scope.md` §5.1。
5517/// `VarActivationOpsHoldDoctestGuard` の #2516 部分反転と同型): `Var::{median,median_with_indices,kthvalue,quantile,nanmean,nansum}` と `QuantileInterpolation` の再エクスポートは承認形どおり公開済みのため、
5518/// 該当する UFCS 行と、受け手 `Var` の `impl` ブロック、型 `QuantileInterpolation` のローカル定義(ルート再エクスポートと glob 衝突するため)を外した(残すと公開した inherent メソッドや再エクスポート型との衝突でコンパイルが失敗する)。残した受け手の `impl` ブロックは、同じトレイトの別メソッド分のプローブとして維持する。
5519/// 引き続き拒否する未承認経路: モジュール `stat_reduce_ops`・`stat_reduce`、型 `StatReduceError`・残した受け手(`Tape`・`Tensor<f32>`)上の、公開していない名前の同名メソッド。
5520/// **検出範囲の限定**: 列挙した名前・型・受け手に限り、マクロ生成や別名経由の公開までは保証しない。
5521/// 公開済み側の正ガード(薄い委譲・シグネチャ・到達性)は `crates/facade/tests/api_surface.rs` が固定する。
5522///
5523/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
5524/// stat_reduce_ops_hold_doctest_globs_all_pub_modules`・
5525/// `stat_reduce_ops_hold_doctest_probe_body_matches_fixed_contract`・
5526/// `facade_does_not_reexport_or_declare_stat_reduce_ops`・
5527/// `workspace_declares_stat_reduce_ops_fn_names_only_in_allowed_locations`)との
5528/// 多層防御として働く。
5529///
5530/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
5531/// できること
5532///
5533/// ```
5534/// use fandhe_ai::*;
5535/// use fandhe_ai::compat::*;
5536/// use fandhe_ai::optim::*;
5537/// use fandhe_ai::data::*;
5538/// use fandhe_ai::nn::*;
5539/// use fandhe_ai::nn::init::*;
5540/// use fandhe_ai::nn::rnn::*;
5541/// use fandhe_ai::nn::kv_cache::*;
5542/// use fandhe_ai::nn::loss::*;
5543/// use fandhe_ai::interop::*;
5544/// use fandhe_ai::interop::onnx::*;
5545/// use fandhe_ai::interop::safetensors::*;
5546/// use fandhe_ai::interop::npy::*;
5547/// use fandhe_ai::model::*;
5548/// use fandhe_ai::inference::*;
5549/// use fandhe_ai::text::*;
5550/// use fandhe_ai::models::*;
5551/// use fandhe_ai::distributed::*;
5552///
5553/// mod __fandhe_stat_reduce_hold_probe {
5554///     pub struct StatReduceError;
5555///     pub mod stat_reduce_ops {
5556///         pub fn median() {}
5557///         pub fn median_with_indices() {}
5558///         pub fn kthvalue() {}
5559///         pub fn quantile() {}
5560///         pub fn nanmean() {}
5561///         pub fn nansum() {}
5562///     }
5563///     pub mod stat_reduce {
5564///         pub fn __mark() {}
5565///     }
5566/// }
5567/// use __fandhe_stat_reduce_hold_probe::*;
5568///
5569/// struct __FandheStatReduceOpsHoldMarker;
5570///
5571/// trait __FandheStatReduceOpsHoldProbe {
5572///     fn median(&self) -> __FandheStatReduceOpsHoldMarker;
5573///     fn median_with_indices(&self) -> __FandheStatReduceOpsHoldMarker;
5574///     fn kthvalue(&self) -> __FandheStatReduceOpsHoldMarker;
5575///     fn quantile(&self) -> __FandheStatReduceOpsHoldMarker;
5576///     fn nanmean(&self) -> __FandheStatReduceOpsHoldMarker;
5577///     fn nansum(&self) -> __FandheStatReduceOpsHoldMarker;
5578/// }
5579///
5580/// impl __FandheStatReduceOpsHoldProbe for fandhe_ai::Tape {
5581///     fn median(&self) -> __FandheStatReduceOpsHoldMarker {
5582///         __FandheStatReduceOpsHoldMarker
5583///     }
5584///     fn median_with_indices(&self) -> __FandheStatReduceOpsHoldMarker {
5585///         __FandheStatReduceOpsHoldMarker
5586///     }
5587///     fn kthvalue(&self) -> __FandheStatReduceOpsHoldMarker {
5588///         __FandheStatReduceOpsHoldMarker
5589///     }
5590///     fn quantile(&self) -> __FandheStatReduceOpsHoldMarker {
5591///         __FandheStatReduceOpsHoldMarker
5592///     }
5593///     fn nanmean(&self) -> __FandheStatReduceOpsHoldMarker {
5594///         __FandheStatReduceOpsHoldMarker
5595///     }
5596///     fn nansum(&self) -> __FandheStatReduceOpsHoldMarker {
5597///         __FandheStatReduceOpsHoldMarker
5598///     }
5599/// }
5600///
5601/// impl __FandheStatReduceOpsHoldProbe for fandhe_ai::Tensor<f32> {
5602///     fn median(&self) -> __FandheStatReduceOpsHoldMarker {
5603///         __FandheStatReduceOpsHoldMarker
5604///     }
5605///     fn median_with_indices(&self) -> __FandheStatReduceOpsHoldMarker {
5606///         __FandheStatReduceOpsHoldMarker
5607///     }
5608///     fn kthvalue(&self) -> __FandheStatReduceOpsHoldMarker {
5609///         __FandheStatReduceOpsHoldMarker
5610///     }
5611///     fn quantile(&self) -> __FandheStatReduceOpsHoldMarker {
5612///         __FandheStatReduceOpsHoldMarker
5613///     }
5614///     fn nanmean(&self) -> __FandheStatReduceOpsHoldMarker {
5615///         __FandheStatReduceOpsHoldMarker
5616///     }
5617///     fn nansum(&self) -> __FandheStatReduceOpsHoldMarker {
5618///         __FandheStatReduceOpsHoldMarker
5619///     }
5620/// }
5621///
5622/// fn __probe_free_fns(_: StatReduceError) {
5623///     // 修飾なし呼び出し(`use fandhe_ai::*;` が同名を glob 公開して
5624///     // いれば、名前解決自体が曖昧になり E0659 でコンパイル失敗する)。
5625///     stat_reduce_ops::median();
5626///     stat_reduce_ops::median_with_indices();
5627///     stat_reduce_ops::kthvalue();
5628///     stat_reduce_ops::quantile();
5629///     stat_reduce_ops::nanmean();
5630///     stat_reduce_ops::nansum();
5631///     stat_reduce::__mark();
5632/// }
5633///
5634/// fn __probe_methods(
5635///     _v: &fandhe_ai::Var<'_>,
5636///     tape: &fandhe_ai::Tape,
5637///     tf: &fandhe_ai::Tensor<f32>,
5638/// ) {
5639///     let _: __FandheStatReduceOpsHoldMarker = fandhe_ai::Tape::median(tape);
5640///     let _: __FandheStatReduceOpsHoldMarker = fandhe_ai::Tape::median_with_indices(tape);
5641///     let _: __FandheStatReduceOpsHoldMarker = fandhe_ai::Tape::kthvalue(tape);
5642///     let _: __FandheStatReduceOpsHoldMarker = fandhe_ai::Tape::quantile(tape);
5643///     let _: __FandheStatReduceOpsHoldMarker = fandhe_ai::Tape::nanmean(tape);
5644///     let _: __FandheStatReduceOpsHoldMarker = fandhe_ai::Tape::nansum(tape);
5645///     let _: __FandheStatReduceOpsHoldMarker = fandhe_ai::Tensor::<f32>::median(tf);
5646///     let _: __FandheStatReduceOpsHoldMarker = fandhe_ai::Tensor::<f32>::median_with_indices(tf);
5647///     let _: __FandheStatReduceOpsHoldMarker = fandhe_ai::Tensor::<f32>::kthvalue(tf);
5648///     let _: __FandheStatReduceOpsHoldMarker = fandhe_ai::Tensor::<f32>::quantile(tf);
5649///     let _: __FandheStatReduceOpsHoldMarker = fandhe_ai::Tensor::<f32>::nanmean(tf);
5650///     let _: __FandheStatReduceOpsHoldMarker = fandhe_ai::Tensor::<f32>::nansum(tf);
5651/// }
5652/// ```
5653#[cfg(doctest)]
5654#[allow(dead_code)]
5655struct StatReduceOpsHoldDoctestGuard;
5656
5657/// ヒストグラム・二分探索系(`histc`・`bincount`・`searchsorted`・`bucketize`。
5658/// イシュー #2638・親 #2625・ルート #2499 Phase 4)のうち未承認の経路を facade 公開面から締め出す保留ガード(`StatReduceOpsHoldDoctestGuard` と同型の正のプローブ 1 ブロック方式)。
5659///
5660/// 下の doctest は全 `pub mod` を glob import したスコープへ、未承認経路に対応するローカル定義(モジュール `binning_ops`・`binning`、型 `BinningError`)と、
5661/// 同名メソッドを持つプローブ用トレイト(受け手: `Tape`・`Tensor<f32>`・`Tensor<i32>`・`Var`)を置き、修飾なしの関数呼び出しと修飾付き(UFCS)のメソッド呼び出しの両方を行う。
5662/// facade が同名のモジュール・関数・型を glob 可能な位置へ公開するか、上の受け手へ同名の inherent メソッドを公開すると、
5663/// 名前解決の曖昧性または呼び出しシグネチャの不一致でエラーコードに依存せずコンパイルが失敗する(`Tensor` は facade から再エクスポートされるため、`tensor-core` 側への同名メソッド追加も検出する)。
5664///
5665/// **#2678 での部分反転**(ルート #2499 の一括承認 `issuecomment-6033824965`・`docs/compat-api-scope.md` §5.1。
5666/// `VarActivationOpsHoldDoctestGuard` の #2516 部分反転と同型): `Var::{histc,searchsorted,bucketize}` と `Tape::{bincount,bincount_weighted}` は承認形どおり公開済みのため、
5667/// 該当する UFCS 行を外した(残すと公開した inherent メソッドや再エクスポート型との衝突でコンパイルが失敗する)。残した受け手の `impl` ブロックは、同じトレイトの別メソッド分のプローブとして維持する。
5668/// 引き続き拒否する未承認経路: モジュール `binning_ops`・`binning`、型 `BinningError`・残した受け手(`Tape`・`Tensor<f32>`・`Tensor<i32>`・`Var`)上の、公開していない名前の同名メソッド。
5669/// **検出範囲の限定**: 列挙した名前・型・受け手に限り、マクロ生成や別名経由の公開までは保証しない。
5670/// 公開済み側の正ガード(薄い委譲・シグネチャ・到達性)は `crates/facade/tests/api_surface.rs` が固定する。
5671///
5672/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
5673/// binning_ops_hold_doctest_globs_all_pub_modules`・
5674/// `binning_ops_hold_doctest_probe_body_matches_fixed_contract`・
5675/// `facade_does_not_reexport_or_declare_binning_ops`・
5676/// `workspace_declares_binning_ops_fn_names_only_in_allowed_locations`)との
5677/// 多層防御として働く。
5678///
5679/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
5680/// できること
5681///
5682/// ```
5683/// use fandhe_ai::*;
5684/// use fandhe_ai::compat::*;
5685/// use fandhe_ai::optim::*;
5686/// use fandhe_ai::data::*;
5687/// use fandhe_ai::nn::*;
5688/// use fandhe_ai::nn::init::*;
5689/// use fandhe_ai::nn::rnn::*;
5690/// use fandhe_ai::nn::kv_cache::*;
5691/// use fandhe_ai::nn::loss::*;
5692/// use fandhe_ai::interop::*;
5693/// use fandhe_ai::interop::onnx::*;
5694/// use fandhe_ai::interop::safetensors::*;
5695/// use fandhe_ai::interop::npy::*;
5696/// use fandhe_ai::model::*;
5697/// use fandhe_ai::inference::*;
5698/// use fandhe_ai::text::*;
5699/// use fandhe_ai::models::*;
5700/// use fandhe_ai::distributed::*;
5701///
5702/// mod __fandhe_binning_hold_probe {
5703///     pub struct BinningError;
5704///     pub mod binning_ops {
5705///         pub fn histc() {}
5706///         pub fn bincount() {}
5707///         pub fn bincount_weighted() {}
5708///         pub fn searchsorted() {}
5709///         pub fn bucketize() {}
5710///     }
5711///     pub mod binning {
5712///         pub fn __mark() {}
5713///     }
5714/// }
5715/// use __fandhe_binning_hold_probe::*;
5716///
5717/// struct __FandheBinningOpsHoldMarker;
5718///
5719/// trait __FandheBinningOpsHoldProbe {
5720///     fn histc(&self) -> __FandheBinningOpsHoldMarker;
5721///     fn bincount(&self) -> __FandheBinningOpsHoldMarker;
5722///     fn bincount_weighted(&self) -> __FandheBinningOpsHoldMarker;
5723///     fn searchsorted(&self) -> __FandheBinningOpsHoldMarker;
5724///     fn bucketize(&self) -> __FandheBinningOpsHoldMarker;
5725/// }
5726///
5727/// impl<'t> __FandheBinningOpsHoldProbe for fandhe_ai::Var<'t> {
5728///     fn histc(&self) -> __FandheBinningOpsHoldMarker {
5729///         __FandheBinningOpsHoldMarker
5730///     }
5731///     fn bincount(&self) -> __FandheBinningOpsHoldMarker {
5732///         __FandheBinningOpsHoldMarker
5733///     }
5734///     fn bincount_weighted(&self) -> __FandheBinningOpsHoldMarker {
5735///         __FandheBinningOpsHoldMarker
5736///     }
5737///     fn searchsorted(&self) -> __FandheBinningOpsHoldMarker {
5738///         __FandheBinningOpsHoldMarker
5739///     }
5740///     fn bucketize(&self) -> __FandheBinningOpsHoldMarker {
5741///         __FandheBinningOpsHoldMarker
5742///     }
5743/// }
5744///
5745/// impl __FandheBinningOpsHoldProbe for fandhe_ai::Tape {
5746///     fn histc(&self) -> __FandheBinningOpsHoldMarker {
5747///         __FandheBinningOpsHoldMarker
5748///     }
5749///     fn bincount(&self) -> __FandheBinningOpsHoldMarker {
5750///         __FandheBinningOpsHoldMarker
5751///     }
5752///     fn bincount_weighted(&self) -> __FandheBinningOpsHoldMarker {
5753///         __FandheBinningOpsHoldMarker
5754///     }
5755///     fn searchsorted(&self) -> __FandheBinningOpsHoldMarker {
5756///         __FandheBinningOpsHoldMarker
5757///     }
5758///     fn bucketize(&self) -> __FandheBinningOpsHoldMarker {
5759///         __FandheBinningOpsHoldMarker
5760///     }
5761/// }
5762///
5763/// impl __FandheBinningOpsHoldProbe for fandhe_ai::Tensor<f32> {
5764///     fn histc(&self) -> __FandheBinningOpsHoldMarker {
5765///         __FandheBinningOpsHoldMarker
5766///     }
5767///     fn bincount(&self) -> __FandheBinningOpsHoldMarker {
5768///         __FandheBinningOpsHoldMarker
5769///     }
5770///     fn bincount_weighted(&self) -> __FandheBinningOpsHoldMarker {
5771///         __FandheBinningOpsHoldMarker
5772///     }
5773///     fn searchsorted(&self) -> __FandheBinningOpsHoldMarker {
5774///         __FandheBinningOpsHoldMarker
5775///     }
5776///     fn bucketize(&self) -> __FandheBinningOpsHoldMarker {
5777///         __FandheBinningOpsHoldMarker
5778///     }
5779/// }
5780///
5781/// impl __FandheBinningOpsHoldProbe for fandhe_ai::Tensor<i32> {
5782///     fn histc(&self) -> __FandheBinningOpsHoldMarker {
5783///         __FandheBinningOpsHoldMarker
5784///     }
5785///     fn bincount(&self) -> __FandheBinningOpsHoldMarker {
5786///         __FandheBinningOpsHoldMarker
5787///     }
5788///     fn bincount_weighted(&self) -> __FandheBinningOpsHoldMarker {
5789///         __FandheBinningOpsHoldMarker
5790///     }
5791///     fn searchsorted(&self) -> __FandheBinningOpsHoldMarker {
5792///         __FandheBinningOpsHoldMarker
5793///     }
5794///     fn bucketize(&self) -> __FandheBinningOpsHoldMarker {
5795///         __FandheBinningOpsHoldMarker
5796///     }
5797/// }
5798///
5799/// fn __probe_free_fns(_: BinningError) {
5800///     // 修飾なし呼び出し(`use fandhe_ai::*;` が同名を glob 公開して
5801///     // いれば、名前解決自体が曖昧になり E0659 でコンパイル失敗する)。
5802///     binning_ops::histc();
5803///     binning_ops::bincount();
5804///     binning_ops::bincount_weighted();
5805///     binning_ops::searchsorted();
5806///     binning_ops::bucketize();
5807///     binning::__mark();
5808/// }
5809///
5810/// fn __probe_methods(
5811///     v: &fandhe_ai::Var<'_>,
5812///     tape: &fandhe_ai::Tape,
5813///     tf: &fandhe_ai::Tensor<f32>,
5814///     ti: &fandhe_ai::Tensor<i32>,
5815/// ) {
5816///     let _: __FandheBinningOpsHoldMarker = fandhe_ai::Var::bincount(v);
5817///     let _: __FandheBinningOpsHoldMarker = fandhe_ai::Var::bincount_weighted(v);
5818///     let _: __FandheBinningOpsHoldMarker = fandhe_ai::Tape::histc(tape);
5819///     let _: __FandheBinningOpsHoldMarker = fandhe_ai::Tape::searchsorted(tape);
5820///     let _: __FandheBinningOpsHoldMarker = fandhe_ai::Tape::bucketize(tape);
5821///     let _: __FandheBinningOpsHoldMarker = fandhe_ai::Tensor::<f32>::histc(tf);
5822///     let _: __FandheBinningOpsHoldMarker = fandhe_ai::Tensor::<f32>::bincount(tf);
5823///     let _: __FandheBinningOpsHoldMarker = fandhe_ai::Tensor::<f32>::bincount_weighted(tf);
5824///     let _: __FandheBinningOpsHoldMarker = fandhe_ai::Tensor::<f32>::searchsorted(tf);
5825///     let _: __FandheBinningOpsHoldMarker = fandhe_ai::Tensor::<f32>::bucketize(tf);
5826///     let _: __FandheBinningOpsHoldMarker = fandhe_ai::Tensor::<i32>::histc(ti);
5827///     let _: __FandheBinningOpsHoldMarker = fandhe_ai::Tensor::<i32>::bincount(ti);
5828///     let _: __FandheBinningOpsHoldMarker = fandhe_ai::Tensor::<i32>::bincount_weighted(ti);
5829///     let _: __FandheBinningOpsHoldMarker = fandhe_ai::Tensor::<i32>::searchsorted(ti);
5830///     let _: __FandheBinningOpsHoldMarker = fandhe_ai::Tensor::<i32>::bucketize(ti);
5831/// }
5832/// ```
5833#[cfg(doctest)]
5834#[allow(dead_code)]
5835struct BinningOpsHoldDoctestGuard;
5836
5837/// `Var`/`Tape` の低精度 forward 入口(`matmul_low_precision`・
5838/// `add_low_precision`・`mul_low_precision`・`relu_low_precision`・
5839/// `exp_low_precision`・`tanh_low_precision`。イシュー #2628・親 #2626・
5840/// ルート #2499 Phase 4)のうち未承認の経路を facade 公開面から締め出す保留ガード(
5841/// `FftOpsHoldDoctestGuard` と同型の正のプローブ 1 ブロック方式)。
5842///
5843/// 下の doctest は全 `pub mod` を glob import したスコープへ、未承認経路に対応するローカル定義(モジュール `low_precision_ops`、クレートルート直下の裸の自由関数 `matmul_low_precision`・`add_low_precision`・`mul_low_precision`・`relu_low_precision`・`exp_low_precision`・`tanh_low_precision`)と、
5844/// 同名メソッドを持つプローブ用トレイト(受け手: `Tape`)を置き、修飾なしの関数呼び出しと修飾付き(UFCS)のメソッド呼び出しの両方を行う。
5845/// facade が同名のモジュール・関数・型を glob 可能な位置へ公開するか、上の受け手へ同名の inherent メソッドを公開すると、
5846/// 名前解決の曖昧性または呼び出しシグネチャの不一致でエラーコードに依存せずコンパイルが失敗する。
5847///
5848/// **#2678 での部分反転**(ルート #2499 の一括承認 `issuecomment-6033824965`・`docs/compat-api-scope.md` §5.1。
5849/// `VarActivationOpsHoldDoctestGuard` の #2516 部分反転と同型): `Var::{matmul,add,mul,relu,exp,tanh}_low_precision`(`matmul_low_precision` は既存メソッドの `pub` 化)は承認形どおり公開済みのため、
5850/// 該当する UFCS 行と、受け手 `Var` の `impl` ブロックを外した(残すと公開した inherent メソッドや再エクスポート型との衝突でコンパイルが失敗する)。残した受け手の `impl` ブロックは、同じトレイトの別メソッド分のプローブとして維持する。
5851/// 引き続き拒否する未承認経路: モジュール `low_precision_ops`、クレートルート直下の裸の自由関数 `matmul_low_precision`・`add_low_precision`・`mul_low_precision`・`relu_low_precision`・`exp_low_precision`・`tanh_low_precision`・残した受け手(`Tape`)上の、公開していない名前の同名メソッド。
5852/// **検出範囲の限定**: 列挙した名前・型・受け手に限り、マクロ生成や別名経由の公開までは保証しない。
5853/// 公開済み側の正ガード(薄い委譲・シグネチャ・到達性)は `crates/facade/tests/api_surface.rs` が固定する。
5854///
5855/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
5856/// var_low_precision_ops_hold_doctest_globs_all_pub_modules`・
5857/// `var_low_precision_ops_hold_doctest_probe_body_matches_fixed_contract`・
5858/// `facade_does_not_reexport_or_declare_low_precision_ops`・
5859/// `workspace_declares_low_precision_ops_fn_names_only_in_allowed_locations`)
5860/// との多層防御として働く。
5861///
5862/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
5863/// できること
5864///
5865/// ```
5866/// use fandhe_ai::*;
5867/// use fandhe_ai::compat::*;
5868/// use fandhe_ai::optim::*;
5869/// use fandhe_ai::data::*;
5870/// use fandhe_ai::nn::*;
5871/// use fandhe_ai::nn::init::*;
5872/// use fandhe_ai::nn::rnn::*;
5873/// use fandhe_ai::nn::kv_cache::*;
5874/// use fandhe_ai::nn::loss::*;
5875/// use fandhe_ai::interop::*;
5876/// use fandhe_ai::interop::onnx::*;
5877/// use fandhe_ai::interop::safetensors::*;
5878/// use fandhe_ai::interop::npy::*;
5879/// use fandhe_ai::model::*;
5880/// use fandhe_ai::inference::*;
5881/// use fandhe_ai::text::*;
5882/// use fandhe_ai::models::*;
5883/// use fandhe_ai::distributed::*;
5884///
5885/// mod __fandhe_low_precision_ops_hold_probe {
5886///     pub mod low_precision_ops {
5887///         pub fn matmul_low_precision() {}
5888///         pub fn add_low_precision() {}
5889///         pub fn mul_low_precision() {}
5890///         pub fn relu_low_precision() {}
5891///         pub fn exp_low_precision() {}
5892///         pub fn tanh_low_precision() {}
5893///     }
5894///     pub fn matmul_low_precision() {}
5895///     pub fn add_low_precision() {}
5896///     pub fn mul_low_precision() {}
5897///     pub fn relu_low_precision() {}
5898///     pub fn exp_low_precision() {}
5899///     pub fn tanh_low_precision() {}
5900/// }
5901/// use __fandhe_low_precision_ops_hold_probe::*;
5902///
5903/// struct __FandheLowPrecisionHoldMarker;
5904///
5905/// trait __FandheLowPrecisionHoldProbe {
5906///     fn matmul_low_precision(&self) -> __FandheLowPrecisionHoldMarker;
5907///     fn add_low_precision(&self) -> __FandheLowPrecisionHoldMarker;
5908///     fn mul_low_precision(&self) -> __FandheLowPrecisionHoldMarker;
5909///     fn relu_low_precision(&self) -> __FandheLowPrecisionHoldMarker;
5910///     fn exp_low_precision(&self) -> __FandheLowPrecisionHoldMarker;
5911///     fn tanh_low_precision(&self) -> __FandheLowPrecisionHoldMarker;
5912/// }
5913///
5914/// impl __FandheLowPrecisionHoldProbe for fandhe_ai::Tape {
5915///     fn matmul_low_precision(&self) -> __FandheLowPrecisionHoldMarker {
5916///         __FandheLowPrecisionHoldMarker
5917///     }
5918///     fn add_low_precision(&self) -> __FandheLowPrecisionHoldMarker {
5919///         __FandheLowPrecisionHoldMarker
5920///     }
5921///     fn mul_low_precision(&self) -> __FandheLowPrecisionHoldMarker {
5922///         __FandheLowPrecisionHoldMarker
5923///     }
5924///     fn relu_low_precision(&self) -> __FandheLowPrecisionHoldMarker {
5925///         __FandheLowPrecisionHoldMarker
5926///     }
5927///     fn exp_low_precision(&self) -> __FandheLowPrecisionHoldMarker {
5928///         __FandheLowPrecisionHoldMarker
5929///     }
5930///     fn tanh_low_precision(&self) -> __FandheLowPrecisionHoldMarker {
5931///         __FandheLowPrecisionHoldMarker
5932///     }
5933/// }
5934///
5935/// fn __probe_free_fns() {
5936///     // 修飾なし呼び出し(`use fandhe_ai::*;` が同名を glob 公開して
5937///     // いれば、名前解決自体が曖昧になり E0659 でコンパイル失敗する)。
5938///     low_precision_ops::matmul_low_precision();
5939///     low_precision_ops::add_low_precision();
5940///     low_precision_ops::mul_low_precision();
5941///     low_precision_ops::relu_low_precision();
5942///     low_precision_ops::exp_low_precision();
5943///     low_precision_ops::tanh_low_precision();
5944///     matmul_low_precision();
5945///     add_low_precision();
5946///     mul_low_precision();
5947///     relu_low_precision();
5948///     exp_low_precision();
5949///     tanh_low_precision();
5950/// }
5951///
5952/// fn __probe_methods(_v: &fandhe_ai::Var<'_>, tape: &fandhe_ai::Tape) {
5953///     let _: __FandheLowPrecisionHoldMarker = fandhe_ai::Tape::matmul_low_precision(tape);
5954///     let _: __FandheLowPrecisionHoldMarker = fandhe_ai::Tape::add_low_precision(tape);
5955///     let _: __FandheLowPrecisionHoldMarker = fandhe_ai::Tape::mul_low_precision(tape);
5956///     let _: __FandheLowPrecisionHoldMarker = fandhe_ai::Tape::relu_low_precision(tape);
5957///     let _: __FandheLowPrecisionHoldMarker = fandhe_ai::Tape::exp_low_precision(tape);
5958///     let _: __FandheLowPrecisionHoldMarker = fandhe_ai::Tape::tanh_low_precision(tape);
5959/// }
5960/// ```
5961#[cfg(doctest)]
5962#[allow(dead_code)]
5963struct VarLowPrecisionOpsHoldDoctestGuard;
5964
5965/// 形状演算 6 種(`unbind`・`movedim`・`swapaxes`・`tensor_split`・`meshgrid`・`rot90`。
5966/// イシュー #2639・親 #2625・ルート #2499 Phase 4)のうち未承認の経路を facade 公開面から締め出す保留ガード(`StatReduceOpsHoldDoctestGuard` と同型の正のプローブ 1 ブロック方式)。
5967///
5968/// 下の doctest は全 `pub mod` を glob import したスコープへ、未承認経路に対応するローカル定義(モジュール `shape_view_ops`)と、
5969/// 同名メソッドを持つプローブ用トレイト(受け手: `Tape`・`Tensor<f32>`)を置き、修飾なしの関数呼び出しと修飾付き(UFCS)のメソッド呼び出しの両方を行う。
5970/// facade が同名のモジュール・関数・型を glob 可能な位置へ公開するか、上の受け手へ同名の inherent メソッドを公開すると、
5971/// 名前解決の曖昧性または呼び出しシグネチャの不一致でエラーコードに依存せずコンパイルが失敗する(`Tensor` は facade から再エクスポートされるため、`tensor-core` 側への同名メソッド追加も検出する)。
5972///
5973/// **#2678 での部分反転**(ルート #2499 の一括承認 `issuecomment-6033824965`・`docs/compat-api-scope.md` §5.1。
5974/// `VarActivationOpsHoldDoctestGuard` の #2516 部分反転と同型): `Var::{unbind,tensor_split,tensor_split_indices,movedim,swapaxes,rot90,meshgrid}` と `MeshgridIndexing` の再エクスポートは承認形どおり公開済みのため、
5975/// 該当する UFCS 行と、受け手 `Var` の `impl` ブロック、型 `MeshgridIndexing` のローカル定義(ルート再エクスポートと glob 衝突するため)を外した(残すと公開した inherent メソッドや再エクスポート型との衝突でコンパイルが失敗する)。残した受け手の `impl` ブロックは、同じトレイトの別メソッド分のプローブとして維持する。
5976/// 引き続き拒否する未承認経路: モジュール `shape_view_ops`・残した受け手(`Tape`・`Tensor<f32>`)上の、公開していない名前の同名メソッド。
5977/// **検出範囲の限定**: 列挙した名前・型・受け手に限り、マクロ生成や別名経由の公開までは保証しない。
5978/// 公開済み側の正ガード(薄い委譲・シグネチャ・到達性)は `crates/facade/tests/api_surface.rs` が固定する。
5979///
5980/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
5981/// shape_view_ops_hold_doctest_globs_all_pub_modules`・
5982/// `shape_view_ops_hold_doctest_probe_body_matches_fixed_contract`・
5983/// `facade_does_not_reexport_or_declare_shape_view_ops`・
5984/// `workspace_declares_shape_view_ops_fn_names_only_in_allowed_locations`)との
5985/// 多層防御として働く。
5986///
5987/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
5988/// できること
5989///
5990/// ```
5991/// use fandhe_ai::*;
5992/// use fandhe_ai::compat::*;
5993/// use fandhe_ai::optim::*;
5994/// use fandhe_ai::data::*;
5995/// use fandhe_ai::nn::*;
5996/// use fandhe_ai::nn::init::*;
5997/// use fandhe_ai::nn::rnn::*;
5998/// use fandhe_ai::nn::kv_cache::*;
5999/// use fandhe_ai::nn::loss::*;
6000/// use fandhe_ai::interop::*;
6001/// use fandhe_ai::interop::onnx::*;
6002/// use fandhe_ai::interop::safetensors::*;
6003/// use fandhe_ai::interop::npy::*;
6004/// use fandhe_ai::model::*;
6005/// use fandhe_ai::inference::*;
6006/// use fandhe_ai::text::*;
6007/// use fandhe_ai::models::*;
6008/// use fandhe_ai::distributed::*;
6009///
6010/// mod __fandhe_shape_view_hold_probe {
6011///     pub mod shape_view_ops {
6012///         pub fn unbind() {}
6013///         pub fn movedim() {}
6014///         pub fn swapaxes() {}
6015///         pub fn tensor_split() {}
6016///         pub fn tensor_split_indices() {}
6017///         pub fn meshgrid() {}
6018///         pub fn rot90() {}
6019///     }
6020/// }
6021/// use __fandhe_shape_view_hold_probe::*;
6022///
6023/// struct __FandheShapeViewOpsHoldMarker;
6024///
6025/// trait __FandheShapeViewOpsHoldProbe {
6026///     fn unbind(&self) -> __FandheShapeViewOpsHoldMarker;
6027///     fn movedim(&self) -> __FandheShapeViewOpsHoldMarker;
6028///     fn swapaxes(&self) -> __FandheShapeViewOpsHoldMarker;
6029///     fn tensor_split(&self) -> __FandheShapeViewOpsHoldMarker;
6030///     fn tensor_split_indices(&self) -> __FandheShapeViewOpsHoldMarker;
6031///     fn meshgrid(&self) -> __FandheShapeViewOpsHoldMarker;
6032///     fn rot90(&self) -> __FandheShapeViewOpsHoldMarker;
6033/// }
6034///
6035/// impl __FandheShapeViewOpsHoldProbe for fandhe_ai::Tape {
6036///     fn unbind(&self) -> __FandheShapeViewOpsHoldMarker {
6037///         __FandheShapeViewOpsHoldMarker
6038///     }
6039///     fn movedim(&self) -> __FandheShapeViewOpsHoldMarker {
6040///         __FandheShapeViewOpsHoldMarker
6041///     }
6042///     fn swapaxes(&self) -> __FandheShapeViewOpsHoldMarker {
6043///         __FandheShapeViewOpsHoldMarker
6044///     }
6045///     fn tensor_split(&self) -> __FandheShapeViewOpsHoldMarker {
6046///         __FandheShapeViewOpsHoldMarker
6047///     }
6048///     fn tensor_split_indices(&self) -> __FandheShapeViewOpsHoldMarker {
6049///         __FandheShapeViewOpsHoldMarker
6050///     }
6051///     fn meshgrid(&self) -> __FandheShapeViewOpsHoldMarker {
6052///         __FandheShapeViewOpsHoldMarker
6053///     }
6054///     fn rot90(&self) -> __FandheShapeViewOpsHoldMarker {
6055///         __FandheShapeViewOpsHoldMarker
6056///     }
6057/// }
6058///
6059/// impl __FandheShapeViewOpsHoldProbe for fandhe_ai::Tensor<f32> {
6060///     fn unbind(&self) -> __FandheShapeViewOpsHoldMarker {
6061///         __FandheShapeViewOpsHoldMarker
6062///     }
6063///     fn movedim(&self) -> __FandheShapeViewOpsHoldMarker {
6064///         __FandheShapeViewOpsHoldMarker
6065///     }
6066///     fn swapaxes(&self) -> __FandheShapeViewOpsHoldMarker {
6067///         __FandheShapeViewOpsHoldMarker
6068///     }
6069///     fn tensor_split(&self) -> __FandheShapeViewOpsHoldMarker {
6070///         __FandheShapeViewOpsHoldMarker
6071///     }
6072///     fn tensor_split_indices(&self) -> __FandheShapeViewOpsHoldMarker {
6073///         __FandheShapeViewOpsHoldMarker
6074///     }
6075///     fn meshgrid(&self) -> __FandheShapeViewOpsHoldMarker {
6076///         __FandheShapeViewOpsHoldMarker
6077///     }
6078///     fn rot90(&self) -> __FandheShapeViewOpsHoldMarker {
6079///         __FandheShapeViewOpsHoldMarker
6080///     }
6081/// }
6082///
6083/// fn __probe_free_fns() {
6084///     // 修飾なし呼び出し(`use fandhe_ai::*;` が同名を glob 公開して
6085///     // いれば、名前解決自体が曖昧になり E0659 でコンパイル失敗する)。
6086///     shape_view_ops::unbind();
6087///     shape_view_ops::movedim();
6088///     shape_view_ops::swapaxes();
6089///     shape_view_ops::tensor_split();
6090///     shape_view_ops::tensor_split_indices();
6091///     shape_view_ops::meshgrid();
6092///     shape_view_ops::rot90();
6093/// }
6094///
6095/// fn __probe_methods(
6096///     _v: &fandhe_ai::Var<'_>,
6097///     tape: &fandhe_ai::Tape,
6098///     tf: &fandhe_ai::Tensor<f32>,
6099/// ) {
6100///     let _: __FandheShapeViewOpsHoldMarker = fandhe_ai::Tape::unbind(tape);
6101///     let _: __FandheShapeViewOpsHoldMarker = fandhe_ai::Tape::movedim(tape);
6102///     let _: __FandheShapeViewOpsHoldMarker = fandhe_ai::Tape::swapaxes(tape);
6103///     let _: __FandheShapeViewOpsHoldMarker = fandhe_ai::Tape::tensor_split(tape);
6104///     let _: __FandheShapeViewOpsHoldMarker = fandhe_ai::Tape::tensor_split_indices(tape);
6105///     let _: __FandheShapeViewOpsHoldMarker = fandhe_ai::Tape::meshgrid(tape);
6106///     let _: __FandheShapeViewOpsHoldMarker = fandhe_ai::Tape::rot90(tape);
6107///     let _: __FandheShapeViewOpsHoldMarker = fandhe_ai::Tensor::<f32>::unbind(tf);
6108///     let _: __FandheShapeViewOpsHoldMarker = fandhe_ai::Tensor::<f32>::movedim(tf);
6109///     let _: __FandheShapeViewOpsHoldMarker = fandhe_ai::Tensor::<f32>::swapaxes(tf);
6110///     let _: __FandheShapeViewOpsHoldMarker = fandhe_ai::Tensor::<f32>::tensor_split(tf);
6111///     let _: __FandheShapeViewOpsHoldMarker = fandhe_ai::Tensor::<f32>::tensor_split_indices(tf);
6112///     let _: __FandheShapeViewOpsHoldMarker = fandhe_ai::Tensor::<f32>::meshgrid(tf);
6113///     let _: __FandheShapeViewOpsHoldMarker = fandhe_ai::Tensor::<f32>::rot90(tf);
6114/// }
6115/// ```
6116#[cfg(doctest)]
6117#[allow(dead_code)]
6118struct ShapeViewOpsHoldDoctestGuard;
6119
6120/// 索引付き更新 4 種(`scatter_reduce`・`index_add`・`index_copy`・`masked_scatter`。
6121/// イシュー #2641・親 #2625・ルート #2499 Phase 4)のうち未承認の経路を facade 公開面から締め出す保留ガード(`ShapeViewOpsHoldDoctestGuard` と同型の正のプローブ 1 ブロック方式)。
6122///
6123/// 下の doctest は全 `pub mod` を glob import したスコープへ、未承認経路に対応するローカル定義(モジュール `indexed_update_ops`・`indexed_update`)と、
6124/// 同名メソッドを持つプローブ用トレイト(受け手: `Tape`・`Tensor<f32>`)を置き、修飾なしの関数呼び出しと修飾付き(UFCS)のメソッド呼び出しの両方を行う。
6125/// facade が同名のモジュール・関数・型を glob 可能な位置へ公開するか、上の受け手へ同名の inherent メソッドを公開すると、
6126/// 名前解決の曖昧性または呼び出しシグネチャの不一致でエラーコードに依存せずコンパイルが失敗する(`Tensor` は facade から再エクスポートされるため、`tensor-core` 側への同名メソッド追加も検出する)。
6127///
6128/// **#2678 での部分反転**(ルート #2499 の一括承認 `issuecomment-6033824965`・`docs/compat-api-scope.md` §5.1。
6129/// `VarActivationOpsHoldDoctestGuard` の #2516 部分反転と同型): `Var::{scatter_reduce,index_add,index_copy,masked_scatter}` と `ScatterReduceMode` の再エクスポートは承認形どおり公開済みのため、
6130/// 該当する UFCS 行と、受け手 `Var` の `impl` ブロック、型 `ScatterReduceMode` のローカル定義(ルート再エクスポートと glob 衝突するため)を外した(残すと公開した inherent メソッドや再エクスポート型との衝突でコンパイルが失敗する)。残した受け手の `impl` ブロックは、同じトレイトの別メソッド分のプローブとして維持する。
6131/// 引き続き拒否する未承認経路: モジュール `indexed_update_ops`・`indexed_update`・残した受け手(`Tape`・`Tensor<f32>`)上の、公開していない名前の同名メソッド。
6132/// **検出範囲の限定**: 列挙した名前・型・受け手に限り、マクロ生成や別名経由の公開までは保証しない。
6133/// 公開済み側の正ガード(薄い委譲・シグネチャ・到達性)は `crates/facade/tests/api_surface.rs` が固定する。
6134///
6135/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
6136/// indexed_update_ops_hold_doctest_globs_all_pub_modules`・
6137/// `indexed_update_ops_hold_doctest_probe_body_matches_fixed_contract`・
6138/// `facade_does_not_reexport_or_declare_indexed_update_ops`・
6139/// `workspace_declares_indexed_update_ops_fn_names_only_in_allowed_locations`)との
6140/// 多層防御として働く。
6141///
6142/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
6143/// できること
6144///
6145/// ```
6146/// use fandhe_ai::*;
6147/// use fandhe_ai::compat::*;
6148/// use fandhe_ai::optim::*;
6149/// use fandhe_ai::data::*;
6150/// use fandhe_ai::nn::*;
6151/// use fandhe_ai::nn::init::*;
6152/// use fandhe_ai::nn::rnn::*;
6153/// use fandhe_ai::nn::kv_cache::*;
6154/// use fandhe_ai::nn::loss::*;
6155/// use fandhe_ai::interop::*;
6156/// use fandhe_ai::interop::onnx::*;
6157/// use fandhe_ai::interop::safetensors::*;
6158/// use fandhe_ai::interop::npy::*;
6159/// use fandhe_ai::model::*;
6160/// use fandhe_ai::inference::*;
6161/// use fandhe_ai::text::*;
6162/// use fandhe_ai::models::*;
6163/// use fandhe_ai::distributed::*;
6164///
6165/// mod __fandhe_indexed_update_hold_probe {
6166///     pub mod indexed_update_ops {
6167///         pub fn scatter_reduce() {}
6168///         pub fn index_add() {}
6169///         pub fn index_copy() {}
6170///         pub fn masked_scatter() {}
6171///     }
6172///     pub mod indexed_update {
6173///         pub fn __mark() {}
6174///     }
6175/// }
6176/// use __fandhe_indexed_update_hold_probe::*;
6177///
6178/// struct __FandheIndexedUpdateOpsHoldMarker;
6179///
6180/// trait __FandheIndexedUpdateOpsHoldProbe {
6181///     fn scatter_reduce(&self) -> __FandheIndexedUpdateOpsHoldMarker;
6182///     fn index_add(&self) -> __FandheIndexedUpdateOpsHoldMarker;
6183///     fn index_copy(&self) -> __FandheIndexedUpdateOpsHoldMarker;
6184///     fn masked_scatter(&self) -> __FandheIndexedUpdateOpsHoldMarker;
6185/// }
6186///
6187/// impl __FandheIndexedUpdateOpsHoldProbe for fandhe_ai::Tape {
6188///     fn scatter_reduce(&self) -> __FandheIndexedUpdateOpsHoldMarker {
6189///         __FandheIndexedUpdateOpsHoldMarker
6190///     }
6191///     fn index_add(&self) -> __FandheIndexedUpdateOpsHoldMarker {
6192///         __FandheIndexedUpdateOpsHoldMarker
6193///     }
6194///     fn index_copy(&self) -> __FandheIndexedUpdateOpsHoldMarker {
6195///         __FandheIndexedUpdateOpsHoldMarker
6196///     }
6197///     fn masked_scatter(&self) -> __FandheIndexedUpdateOpsHoldMarker {
6198///         __FandheIndexedUpdateOpsHoldMarker
6199///     }
6200/// }
6201///
6202/// impl __FandheIndexedUpdateOpsHoldProbe for fandhe_ai::Tensor<f32> {
6203///     fn scatter_reduce(&self) -> __FandheIndexedUpdateOpsHoldMarker {
6204///         __FandheIndexedUpdateOpsHoldMarker
6205///     }
6206///     fn index_add(&self) -> __FandheIndexedUpdateOpsHoldMarker {
6207///         __FandheIndexedUpdateOpsHoldMarker
6208///     }
6209///     fn index_copy(&self) -> __FandheIndexedUpdateOpsHoldMarker {
6210///         __FandheIndexedUpdateOpsHoldMarker
6211///     }
6212///     fn masked_scatter(&self) -> __FandheIndexedUpdateOpsHoldMarker {
6213///         __FandheIndexedUpdateOpsHoldMarker
6214///     }
6215/// }
6216///
6217/// fn __probe_free_fns() {
6218///     // 修飾なし呼び出し(`use fandhe_ai::*;` が同名を glob 公開して
6219///     // いれば、名前解決自体が曖昧になり E0659 でコンパイル失敗する)。
6220///     indexed_update_ops::scatter_reduce();
6221///     indexed_update_ops::index_add();
6222///     indexed_update_ops::index_copy();
6223///     indexed_update_ops::masked_scatter();
6224///     indexed_update::__mark();
6225/// }
6226///
6227/// fn __probe_methods(
6228///     _v: &fandhe_ai::Var<'_>,
6229///     tape: &fandhe_ai::Tape,
6230///     tf: &fandhe_ai::Tensor<f32>,
6231/// ) {
6232///     let _: __FandheIndexedUpdateOpsHoldMarker = fandhe_ai::Tape::scatter_reduce(tape);
6233///     let _: __FandheIndexedUpdateOpsHoldMarker = fandhe_ai::Tape::index_add(tape);
6234///     let _: __FandheIndexedUpdateOpsHoldMarker = fandhe_ai::Tape::index_copy(tape);
6235///     let _: __FandheIndexedUpdateOpsHoldMarker = fandhe_ai::Tape::masked_scatter(tape);
6236///     let _: __FandheIndexedUpdateOpsHoldMarker = fandhe_ai::Tensor::<f32>::scatter_reduce(tf);
6237///     let _: __FandheIndexedUpdateOpsHoldMarker = fandhe_ai::Tensor::<f32>::index_add(tf);
6238///     let _: __FandheIndexedUpdateOpsHoldMarker = fandhe_ai::Tensor::<f32>::index_copy(tf);
6239///     let _: __FandheIndexedUpdateOpsHoldMarker = fandhe_ai::Tensor::<f32>::masked_scatter(tf);
6240/// }
6241/// ```
6242#[cfg(doctest)]
6243#[allow(dead_code)]
6244struct IndexedUpdateOpsHoldDoctestGuard;
6245
6246/// テンソル積・距離・外積 4 演算(`kron`・`tensordot`〈`tensordot_axes`〉・`cdist`・`cross`。
6247/// イシュー #2640・親 #2625・ルート #2499 Phase 4)のうち未承認の経路を facade 公開面から締め出す保留ガード(`ShapeViewOpsHoldDoctestGuard` と同型の正のプローブ 1 ブロック方式)。
6248///
6249/// 下の doctest は全 `pub mod` を glob import したスコープへ、未承認経路に対応するローカル定義(モジュール `tensor_product_ops`)と、
6250/// 同名メソッドを持つプローブ用トレイト(受け手: `Tape`・`Tensor<f32>`)を置き、修飾なしの関数呼び出しと修飾付き(UFCS)のメソッド呼び出しの両方を行う。
6251/// facade が同名のモジュール・関数・型を glob 可能な位置へ公開するか、上の受け手へ同名の inherent メソッドを公開すると、
6252/// 名前解決の曖昧性または呼び出しシグネチャの不一致でエラーコードに依存せずコンパイルが失敗する(`Tensor` は facade から再エクスポートされるため、`tensor-core` 側への同名メソッド追加も検出する)。
6253///
6254/// **#2678 での部分反転**(ルート #2499 の一括承認 `issuecomment-6033824965`・`docs/compat-api-scope.md` §5.1。
6255/// `VarActivationOpsHoldDoctestGuard` の #2516 部分反転と同型): `Var::{kron,tensordot,tensordot_axes,cdist,cross}` は承認形どおり公開済みのため、
6256/// 該当する UFCS 行と、受け手 `Var` の `impl` ブロックを外した(残すと公開した inherent メソッドや再エクスポート型との衝突でコンパイルが失敗する)。残した受け手の `impl` ブロックは、同じトレイトの別メソッド分のプローブとして維持する。
6257/// 引き続き拒否する未承認経路: モジュール `tensor_product_ops`・残した受け手(`Tape`・`Tensor<f32>`)上の、公開していない名前の同名メソッド。
6258/// **検出範囲の限定**: 列挙した名前・型・受け手に限り、マクロ生成や別名経由の公開までは保証しない。
6259/// 公開済み側の正ガード(薄い委譲・シグネチャ・到達性)は `crates/facade/tests/api_surface.rs` が固定する。
6260///
6261/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
6262/// tensor_product_ops_hold_doctest_globs_all_pub_modules`・
6263/// `tensor_product_ops_hold_doctest_probe_body_matches_fixed_contract`・
6264/// `facade_does_not_reexport_or_declare_tensor_product_ops`・
6265/// `workspace_declares_tensor_product_ops_fn_names_only_in_allowed_locations`)との
6266/// 多層防御として働く。
6267///
6268/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
6269/// できること
6270///
6271/// ```
6272/// use fandhe_ai::*;
6273/// use fandhe_ai::compat::*;
6274/// use fandhe_ai::optim::*;
6275/// use fandhe_ai::data::*;
6276/// use fandhe_ai::nn::*;
6277/// use fandhe_ai::nn::init::*;
6278/// use fandhe_ai::nn::rnn::*;
6279/// use fandhe_ai::nn::kv_cache::*;
6280/// use fandhe_ai::nn::loss::*;
6281/// use fandhe_ai::interop::*;
6282/// use fandhe_ai::interop::onnx::*;
6283/// use fandhe_ai::interop::safetensors::*;
6284/// use fandhe_ai::interop::npy::*;
6285/// use fandhe_ai::model::*;
6286/// use fandhe_ai::inference::*;
6287/// use fandhe_ai::text::*;
6288/// use fandhe_ai::models::*;
6289/// use fandhe_ai::distributed::*;
6290///
6291/// mod __fandhe_tensor_product_hold_probe {
6292///     pub mod tensor_product_ops {
6293///         pub fn kron() {}
6294///         pub fn tensordot() {}
6295///         pub fn tensordot_axes() {}
6296///         pub fn cdist() {}
6297///         pub fn cross() {}
6298///     }
6299/// }
6300/// use __fandhe_tensor_product_hold_probe::*;
6301///
6302/// struct __FandheTensorProductOpsHoldMarker;
6303///
6304/// trait __FandheTensorProductOpsHoldProbe {
6305///     fn kron(&self) -> __FandheTensorProductOpsHoldMarker;
6306///     fn tensordot(&self) -> __FandheTensorProductOpsHoldMarker;
6307///     fn tensordot_axes(&self) -> __FandheTensorProductOpsHoldMarker;
6308///     fn cdist(&self) -> __FandheTensorProductOpsHoldMarker;
6309///     fn cross(&self) -> __FandheTensorProductOpsHoldMarker;
6310/// }
6311///
6312/// impl __FandheTensorProductOpsHoldProbe for fandhe_ai::Tape {
6313///     fn kron(&self) -> __FandheTensorProductOpsHoldMarker {
6314///         __FandheTensorProductOpsHoldMarker
6315///     }
6316///     fn tensordot(&self) -> __FandheTensorProductOpsHoldMarker {
6317///         __FandheTensorProductOpsHoldMarker
6318///     }
6319///     fn tensordot_axes(&self) -> __FandheTensorProductOpsHoldMarker {
6320///         __FandheTensorProductOpsHoldMarker
6321///     }
6322///     fn cdist(&self) -> __FandheTensorProductOpsHoldMarker {
6323///         __FandheTensorProductOpsHoldMarker
6324///     }
6325///     fn cross(&self) -> __FandheTensorProductOpsHoldMarker {
6326///         __FandheTensorProductOpsHoldMarker
6327///     }
6328/// }
6329///
6330/// impl __FandheTensorProductOpsHoldProbe for fandhe_ai::Tensor<f32> {
6331///     fn kron(&self) -> __FandheTensorProductOpsHoldMarker {
6332///         __FandheTensorProductOpsHoldMarker
6333///     }
6334///     fn tensordot(&self) -> __FandheTensorProductOpsHoldMarker {
6335///         __FandheTensorProductOpsHoldMarker
6336///     }
6337///     fn tensordot_axes(&self) -> __FandheTensorProductOpsHoldMarker {
6338///         __FandheTensorProductOpsHoldMarker
6339///     }
6340///     fn cdist(&self) -> __FandheTensorProductOpsHoldMarker {
6341///         __FandheTensorProductOpsHoldMarker
6342///     }
6343///     fn cross(&self) -> __FandheTensorProductOpsHoldMarker {
6344///         __FandheTensorProductOpsHoldMarker
6345///     }
6346/// }
6347///
6348/// fn __probe_free_fns() {
6349///     // 修飾なし呼び出し(`use fandhe_ai::*;` が同名を glob 公開して
6350///     // いれば、名前解決自体が曖昧になり E0659 でコンパイル失敗する)。
6351///     tensor_product_ops::kron();
6352///     tensor_product_ops::tensordot();
6353///     tensor_product_ops::tensordot_axes();
6354///     tensor_product_ops::cdist();
6355///     tensor_product_ops::cross();
6356/// }
6357///
6358/// fn __probe_methods(
6359///     _v: &fandhe_ai::Var<'_>,
6360///     tape: &fandhe_ai::Tape,
6361///     tf: &fandhe_ai::Tensor<f32>,
6362/// ) {
6363///     let _: __FandheTensorProductOpsHoldMarker = fandhe_ai::Tape::kron(tape);
6364///     let _: __FandheTensorProductOpsHoldMarker = fandhe_ai::Tape::tensordot(tape);
6365///     let _: __FandheTensorProductOpsHoldMarker = fandhe_ai::Tape::tensordot_axes(tape);
6366///     let _: __FandheTensorProductOpsHoldMarker = fandhe_ai::Tape::cdist(tape);
6367///     let _: __FandheTensorProductOpsHoldMarker = fandhe_ai::Tape::cross(tape);
6368///     let _: __FandheTensorProductOpsHoldMarker = fandhe_ai::Tensor::<f32>::kron(tf);
6369///     let _: __FandheTensorProductOpsHoldMarker = fandhe_ai::Tensor::<f32>::tensordot(tf);
6370///     let _: __FandheTensorProductOpsHoldMarker = fandhe_ai::Tensor::<f32>::tensordot_axes(tf);
6371///     let _: __FandheTensorProductOpsHoldMarker = fandhe_ai::Tensor::<f32>::cdist(tf);
6372///     let _: __FandheTensorProductOpsHoldMarker = fandhe_ai::Tensor::<f32>::cross(tf);
6373/// }
6374/// ```
6375#[cfg(doctest)]
6376#[allow(dead_code)]
6377struct TensorProductOpsHoldDoctestGuard;
6378
6379/// `pad` の非定数モード(`pad_with_mode`・`PadMode`。reflect/replicate/circular。
6380/// イシュー #2642・親 #2625・ルート #2499 Phase 4)のうち未承認の経路を facade 公開面から締め出す保留ガード(`IndexedUpdateOpsHoldDoctestGuard` と同型の正のプローブ 1 ブロック方式)。
6381///
6382/// 下の doctest は全 `pub mod` を glob import したスコープへ、未承認経路に対応するローカル定義(モジュール `pad_ops`・`pad_modes`、型 `PadModeError`)と、
6383/// 同名メソッドを持つプローブ用トレイト(受け手: `Tape`・`Tensor<f32>`)を置き、修飾なしの関数呼び出しと修飾付き(UFCS)のメソッド呼び出しの両方を行う。
6384/// facade が同名のモジュール・関数・型を glob 可能な位置へ公開するか、上の受け手へ同名の inherent メソッドを公開すると、
6385/// 名前解決の曖昧性または呼び出しシグネチャの不一致でエラーコードに依存せずコンパイルが失敗する(`Tensor` は facade から再エクスポートされるため、`tensor-core` 側への同名メソッド追加も検出する)。
6386///
6387/// **#2678 での部分反転**(ルート #2499 の一括承認 `issuecomment-6033824965`・`docs/compat-api-scope.md` §5.1。
6388/// `VarActivationOpsHoldDoctestGuard` の #2516 部分反転と同型): `Var::pad_with_mode` と `PadMode` の再エクスポートは承認形どおり公開済みのため、
6389/// 該当する UFCS 行と、受け手 `Var` の `impl` ブロック、型 `PadMode` のローカル定義(ルート再エクスポートと glob 衝突するため)を外した(残すと公開した inherent メソッドや再エクスポート型との衝突でコンパイルが失敗する)。残した受け手の `impl` ブロックは、同じトレイトの別メソッド分のプローブとして維持する。
6390/// 引き続き拒否する未承認経路: モジュール `pad_ops`・`pad_modes`、型 `PadModeError`・残した受け手(`Tape`・`Tensor<f32>`)上の、公開していない名前の同名メソッド。
6391/// **検出範囲の限定**: 列挙した名前・型・受け手に限り、マクロ生成や別名経由の公開までは保証しない。
6392/// 公開済み側の正ガード(薄い委譲・シグネチャ・到達性)は `crates/facade/tests/api_surface.rs` が固定する。
6393///
6394/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
6395/// pad_modes_hold_doctest_globs_all_pub_modules`・
6396/// `pad_modes_hold_doctest_probe_body_matches_fixed_contract`・
6397/// `facade_does_not_reexport_or_declare_pad_modes`・
6398/// `workspace_declares_pad_modes_fn_names_only_in_allowed_locations`)との
6399/// 多層防御として働く。
6400///
6401/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
6402/// できること
6403///
6404/// ```
6405/// use fandhe_ai::*;
6406/// use fandhe_ai::compat::*;
6407/// use fandhe_ai::optim::*;
6408/// use fandhe_ai::data::*;
6409/// use fandhe_ai::nn::*;
6410/// use fandhe_ai::nn::init::*;
6411/// use fandhe_ai::nn::rnn::*;
6412/// use fandhe_ai::nn::kv_cache::*;
6413/// use fandhe_ai::nn::loss::*;
6414/// use fandhe_ai::interop::*;
6415/// use fandhe_ai::interop::onnx::*;
6416/// use fandhe_ai::interop::safetensors::*;
6417/// use fandhe_ai::interop::npy::*;
6418/// use fandhe_ai::model::*;
6419/// use fandhe_ai::inference::*;
6420/// use fandhe_ai::text::*;
6421/// use fandhe_ai::models::*;
6422/// use fandhe_ai::distributed::*;
6423///
6424/// mod __fandhe_pad_modes_hold_probe {
6425///     pub struct PadModeError;
6426///     pub mod pad_ops {
6427///         pub fn pad_with_mode() {}
6428///     }
6429///     pub mod pad_modes {
6430///         pub fn __mark() {}
6431///     }
6432/// }
6433/// use __fandhe_pad_modes_hold_probe::*;
6434///
6435/// struct __FandhePadModesHoldMarker;
6436///
6437/// trait __FandhePadModesHoldProbe {
6438///     fn pad_with_mode(&self) -> __FandhePadModesHoldMarker;
6439/// }
6440///
6441/// impl __FandhePadModesHoldProbe for fandhe_ai::Tape {
6442///     fn pad_with_mode(&self) -> __FandhePadModesHoldMarker {
6443///         __FandhePadModesHoldMarker
6444///     }
6445/// }
6446///
6447/// impl __FandhePadModesHoldProbe for fandhe_ai::Tensor<f32> {
6448///     fn pad_with_mode(&self) -> __FandhePadModesHoldMarker {
6449///         __FandhePadModesHoldMarker
6450///     }
6451/// }
6452///
6453/// fn __probe_free_fns(_: PadModeError) {
6454///     // 修飾なし呼び出し(`use fandhe_ai::*;` が同名を glob 公開して
6455///     // いれば、名前解決自体が曖昧になり E0659 でコンパイル失敗する)。
6456///     pad_ops::pad_with_mode();
6457///     pad_modes::__mark();
6458/// }
6459///
6460/// fn __probe_methods(
6461///     _v: &fandhe_ai::Var<'_>,
6462///     tape: &fandhe_ai::Tape,
6463///     tf: &fandhe_ai::Tensor<f32>,
6464/// ) {
6465///     let _: __FandhePadModesHoldMarker = fandhe_ai::Tape::pad_with_mode(tape);
6466///     let _: __FandhePadModesHoldMarker = fandhe_ai::Tensor::<f32>::pad_with_mode(tf);
6467/// }
6468/// ```
6469#[cfg(doctest)]
6470#[allow(dead_code)]
6471struct PadModesHoldDoctestGuard;
6472
6473/// 3D プーリング(`max_pool3d`・`avg_pool3d`。イシュー #2643・親 #2625・ルート #2499
6474/// Phase 4)のうち未承認の経路を facade 公開面から締め出す保留ガード(`PadModesHoldDoctestGuard` と同型の
6475/// 正のプローブ 1 ブロック方式)。
6476///
6477/// 下の doctest は全 `pub mod` を glob import したスコープへ、ローカル
6478/// モジュール `pool3d_ops`/`pool3d`・型 `Pool3dParams`/`MaxPool3d`/`AvgPool3d`・メソッド
6479/// `max_pool3d`/`avg_pool3d`(`Tape`/`Tensor<f32>`。`Var` は #2850 で、`compat::Sequential::add_*` は #3028 で外した)を持つプローブ用トレイトを
6480/// 置き、修飾なしの関数呼び出しと修飾付きメソッド呼び出しの両方を行う。facade が同名の
6481/// モジュール・型・関数を glob 可能な位置へ公開するか、これらの型へ同名の inherent
6482/// メソッドを公開すると、名前解決の曖昧性または呼び出しシグネチャの不一致で
6483/// エラーコードに依存せずコンパイルが失敗する(`Tensor` は facade から再エクスポート
6484/// されるため、`tensor-core` 側への同名メソッド追加も検出する)。
6485///
6486/// **#2850 での部分反転**(承認根拠 `https://github.com/Fandhe-AI/fandhe-ai/issues/2499#issuecomment-6052732061`・
6487/// 公開形は `docs/autodiff-pool3d-ops-decision.md` §12.1・`docs/compat-api-scope.md` §5.1。`PadModesHoldDoctestGuard` の #2678 部分反転と同型):
6488/// `Var::max_pool3d`/`Var::avg_pool3d` は記録 §12.1 の形で公開済みのため、受け手 `Var` の `impl` ブロックと該当する UFCS 行を外した
6489/// (残すと公開した inherent メソッドとの衝突でコンパイルが失敗する)。残した受け手の `impl` ブロックは `Tape`・`Tensor<f32>` 上の同名メソッド分のプローブとして維持する。
6490/// 引き続き拒否する未承認経路: モジュール `pool3d_ops`・`pool3d`、型 `Pool3dParams`/`MaxPool3d`/`AvgPool3d`、
6491/// `Tape`・`Tensor<f32>` 上の `max_pool3d`/`avg_pool3d`。
6492/// **#3028 での部分反転**: `compat::Sequential::add_max_pool3d`/`add_avg_pool3d` は決定記録 `docs/compat-sequential-3d-fold-lrn-layers-decision.md` §3 の形で公開済みのため、受け手 `Sequential` の `impl` ブロックと UFCS 行を外した(残すと inherent メソッドとの衝突でコンパイルが失敗する)。
6493/// **検出範囲の限定**: 列挙した名前・型・受け手に限り、マクロ生成や別名経由の公開までは保証しない。
6494/// 公開済み側の正ガード(薄い委譲・シグネチャ・到達性)は `crates/facade/tests/api_surface.rs` が固定する。
6495///
6496/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
6497/// pool3d_ops_hold_doctest_globs_all_pub_modules`・
6498/// `pool3d_ops_hold_doctest_probe_body_matches_fixed_contract`・
6499/// `facade_does_not_reexport_or_declare_pool3d_ops`・
6500/// `workspace_declares_pool3d_ops_fn_names_only_in_allowed_locations`)との
6501/// 多層防御として働く。
6502///
6503/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
6504/// できること
6505///
6506/// ```
6507/// use fandhe_ai::*;
6508/// use fandhe_ai::compat::*;
6509/// use fandhe_ai::optim::*;
6510/// use fandhe_ai::data::*;
6511/// use fandhe_ai::nn::*;
6512/// use fandhe_ai::nn::init::*;
6513/// use fandhe_ai::nn::rnn::*;
6514/// use fandhe_ai::nn::kv_cache::*;
6515/// use fandhe_ai::nn::loss::*;
6516/// use fandhe_ai::interop::*;
6517/// use fandhe_ai::interop::onnx::*;
6518/// use fandhe_ai::interop::safetensors::*;
6519/// use fandhe_ai::interop::npy::*;
6520/// use fandhe_ai::model::*;
6521/// use fandhe_ai::inference::*;
6522/// use fandhe_ai::text::*;
6523/// use fandhe_ai::models::*;
6524/// use fandhe_ai::distributed::*;
6525///
6526/// mod __fandhe_pool3d_hold_probe {
6527///     pub struct Pool3dParams;
6528///     pub struct MaxPool3d;
6529///     pub struct AvgPool3d;
6530///     pub mod pool3d_ops {
6531///         pub fn max_pool3d() {}
6532///         pub fn avg_pool3d() {}
6533///     }
6534///     pub mod pool3d {
6535///         pub fn __mark() {}
6536///     }
6537/// }
6538/// use __fandhe_pool3d_hold_probe::*;
6539///
6540/// struct __FandhePool3dHoldMarker;
6541///
6542/// trait __FandhePool3dHoldProbe {
6543///     fn max_pool3d(&self) -> __FandhePool3dHoldMarker;
6544///     fn avg_pool3d(&self) -> __FandhePool3dHoldMarker;
6545/// }
6546///
6547/// impl __FandhePool3dHoldProbe for fandhe_ai::Tape {
6548///     fn max_pool3d(&self) -> __FandhePool3dHoldMarker {
6549///         __FandhePool3dHoldMarker
6550///     }
6551///     fn avg_pool3d(&self) -> __FandhePool3dHoldMarker {
6552///         __FandhePool3dHoldMarker
6553///     }
6554/// }
6555///
6556/// impl __FandhePool3dHoldProbe for fandhe_ai::Tensor<f32> {
6557///     fn max_pool3d(&self) -> __FandhePool3dHoldMarker {
6558///         __FandhePool3dHoldMarker
6559///     }
6560///     fn avg_pool3d(&self) -> __FandhePool3dHoldMarker {
6561///         __FandhePool3dHoldMarker
6562///     }
6563/// }
6564///
6565/// fn __probe_free_fns(_: Pool3dParams, _: MaxPool3d, _: AvgPool3d) {
6566///     // 修飾なし呼び出し(`use fandhe_ai::*;` が同名を glob 公開して
6567///     // いれば、名前解決自体が曖昧になり E0659 でコンパイル失敗する)。
6568///     pool3d_ops::max_pool3d();
6569///     pool3d_ops::avg_pool3d();
6570///     pool3d::__mark();
6571/// }
6572///
6573/// fn __probe_methods(
6574///     _v: &fandhe_ai::Var<'_>,
6575///     tape: &fandhe_ai::Tape,
6576///     tf: &fandhe_ai::Tensor<f32>,
6577/// ) {
6578///     let _: __FandhePool3dHoldMarker = fandhe_ai::Tape::max_pool3d(tape);
6579///     let _: __FandhePool3dHoldMarker = fandhe_ai::Tape::avg_pool3d(tape);
6580///     let _: __FandhePool3dHoldMarker = fandhe_ai::Tensor::<f32>::max_pool3d(tf);
6581///     let _: __FandhePool3dHoldMarker = fandhe_ai::Tensor::<f32>::avg_pool3d(tf);
6582/// }
6583/// ```
6584#[cfg(doctest)]
6585#[allow(dead_code)]
6586struct Pool3dOpsHoldDoctestGuard;
6587
6588/// 3D 転置畳み込みと MaxUnpool(`conv_transpose3d`・`max_unpool1d`・`max_unpool2d`・`max_unpool3d`。
6589/// イシュー #2644・親 #2625・ルート #2499 Phase 4)を facade 公開面から締め出す保留ガード
6590/// (`Pool3dOpsHoldDoctestGuard` と同型の正のプローブ 1 ブロック方式)。
6591///
6592/// 下の doctest は全 `pub mod` を glob import したスコープへ、ローカルモジュール
6593/// `conv_transpose3d_ops`/`max_unpool_ops`/`conv_transpose3d`/`max_unpool`・型
6594/// `ConvTranspose3d`/`MaxUnpool1d`/`MaxUnpool2d`/`MaxUnpool3d`/`MaxUnpoolLayout`・メソッド
6595/// `conv_transpose3d`/`max_unpool1d`/`max_unpool2d`/`max_unpool3d`(`Tape`/
6596/// `Tensor<f32>`。`Var` は #2850 で、`compat::Sequential::add_conv_transpose3d` は #3032 で外した)と `add_max_unpool1d`/`add_max_unpool2d`/
6597/// `add_max_unpool3d`(`compat::Sequential`)を持つプローブ用トレイトを置き、修飾なしの関数
6598/// 呼び出しと修飾付きメソッド呼び出しの両方を行う。facade が同名のモジュール・型・関数を glob
6599/// 可能な位置へ公開するか、これらの型へ同名の inherent メソッドを公開すると、名前解決の曖昧性
6600/// または呼び出しシグネチャの不一致でエラーコードに依存せずコンパイルが失敗する(`Tensor` は
6601/// facade から再エクスポートされるため、`tensor-core` 側への同名メソッド追加も検出する)。
6602///
6603/// **#2850 での部分反転**(承認根拠 `https://github.com/Fandhe-AI/fandhe-ai/issues/2499#issuecomment-6052732061`・
6604/// 公開形は `docs/autodiff-conv-transpose3d-max-unpool-decision.md` §12.1・`docs/compat-api-scope.md` §5.1。`PadModesHoldDoctestGuard` の #2678 部分反転と同型):
6605/// `Var::conv_transpose3d`/`Var::max_unpool1d/2d/3d` は記録 §12.1 の形で公開済みのため、受け手 `Var` の `impl` ブロックと該当する UFCS 行を外した
6606/// (残すと公開した inherent メソッドとの衝突でコンパイルが失敗する)。§12.2 の設計判断 3 件(`MaxUnpool` の索引受け渡し・`output_padding < stride` 拒否・`C = 0` 受理)は現行挙動のまま公開した。
6607/// 残した受け手の `impl` ブロックは `Tape`・`Tensor<f32>` 上の同名メソッド分のプローブとして維持する。
6608/// 引き続き拒否する未承認経路: モジュール `conv_transpose3d_ops`/`max_unpool_ops`/`conv_transpose3d`/`max_unpool`、
6609/// 型 `ConvTranspose3d`/`MaxUnpool1d/2d/3d`/`MaxUnpoolLayout`、`Tape`・`Tensor<f32>` 上の同名メソッド、
6610/// `compat::Sequential::add_max_unpool1d/2d/3d`(#3036 で「公開しない経路」として確定。MaxUnpool は入力が値と索引の 2 つで
6611/// `Module::forward` の単入力に載らないため `Sequential` へ層化しない。決定記録 §6 案 A)。
6612/// **#3036 の整理**: MaxUnpool の公開は `compat::FunctionalBuilder::{max_pool{1,2,3}d_with_indices, max_unpool{1,2,3}d}` で行った。
6613/// これらは本ガードのプローブの受け手(`Sequential`/`Tape`/`Tensor<f32>`・型名・モジュール名)に含まれないためコンパイル衝突せず、
6614/// 反転すべきプローブは無い(プローブ本文は不変)。保存・復元は #3037 で対応済み(Functional manifest の op 追加。`format_version` 1 据え置き)。
6615/// **#3032 での部分反転**: `compat::Sequential::add_conv_transpose3d` は決定記録 `docs/compat-sequential-3d-fold-lrn-layers-decision.md` §3 の形で公開済みのため、受け手 `Sequential` の `impl` ブロック内の同名メソッドと UFCS 行を外した(残すと inherent メソッドとの衝突でコンパイルが失敗する)。`add_max_unpool*`・`Tape`/`Tensor<f32>` 上の同名メソッド・モジュール・型名の否定は維持する。
6616/// **検出範囲の限定**: 列挙した名前・型・受け手に限り、マクロ生成や別名経由の公開までは保証しない。
6617/// 公開済み側の正ガード(薄い委譲・シグネチャ・到達性)は `crates/facade/tests/api_surface.rs` が固定する。
6618///
6619/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
6620/// conv_transpose3d_max_unpool_hold_doctest_globs_all_pub_modules`・
6621/// `conv_transpose3d_max_unpool_hold_doctest_probe_body_matches_fixed_contract`・
6622/// `facade_does_not_reexport_or_declare_conv_transpose3d_max_unpool`・
6623/// `workspace_declares_conv_transpose3d_max_unpool_fn_names_only_in_allowed_locations`)との
6624/// 多層防御として働く。
6625///
6626/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
6627/// できること
6628///
6629/// ```
6630/// use fandhe_ai::*;
6631/// use fandhe_ai::compat::*;
6632/// use fandhe_ai::optim::*;
6633/// use fandhe_ai::data::*;
6634/// use fandhe_ai::nn::*;
6635/// use fandhe_ai::nn::init::*;
6636/// use fandhe_ai::nn::rnn::*;
6637/// use fandhe_ai::nn::kv_cache::*;
6638/// use fandhe_ai::nn::loss::*;
6639/// use fandhe_ai::interop::*;
6640/// use fandhe_ai::interop::onnx::*;
6641/// use fandhe_ai::interop::safetensors::*;
6642/// use fandhe_ai::interop::npy::*;
6643/// use fandhe_ai::model::*;
6644/// use fandhe_ai::inference::*;
6645/// use fandhe_ai::text::*;
6646/// use fandhe_ai::models::*;
6647/// use fandhe_ai::distributed::*;
6648///
6649/// mod __fandhe_conv_transpose3d_max_unpool_hold_probe {
6650///     pub struct ConvTranspose3d;
6651///     pub struct MaxUnpool1d;
6652///     pub struct MaxUnpool2d;
6653///     pub struct MaxUnpool3d;
6654///     pub struct MaxUnpoolLayout;
6655///     pub mod conv_transpose3d_ops {
6656///         pub fn conv_transpose3d() {}
6657///     }
6658///     pub mod max_unpool_ops {
6659///         pub fn max_unpool1d() {}
6660///         pub fn max_unpool2d() {}
6661///         pub fn max_unpool3d() {}
6662///     }
6663///     pub mod conv_transpose3d {
6664///         pub fn __mark() {}
6665///     }
6666///     pub mod max_unpool {
6667///         pub fn __mark() {}
6668///     }
6669/// }
6670/// use __fandhe_conv_transpose3d_max_unpool_hold_probe::*;
6671///
6672/// struct __FandheConvTranspose3dMaxUnpoolHoldMarker;
6673///
6674/// trait __FandheConvTranspose3dMaxUnpoolHoldProbe {
6675///     fn conv_transpose3d(&self) -> __FandheConvTranspose3dMaxUnpoolHoldMarker;
6676///     fn max_unpool1d(&self) -> __FandheConvTranspose3dMaxUnpoolHoldMarker;
6677///     fn max_unpool2d(&self) -> __FandheConvTranspose3dMaxUnpoolHoldMarker;
6678///     fn max_unpool3d(&self) -> __FandheConvTranspose3dMaxUnpoolHoldMarker;
6679/// }
6680///
6681/// impl __FandheConvTranspose3dMaxUnpoolHoldProbe for fandhe_ai::Tape {
6682///     fn conv_transpose3d(&self) -> __FandheConvTranspose3dMaxUnpoolHoldMarker {
6683///         __FandheConvTranspose3dMaxUnpoolHoldMarker
6684///     }
6685///     fn max_unpool1d(&self) -> __FandheConvTranspose3dMaxUnpoolHoldMarker {
6686///         __FandheConvTranspose3dMaxUnpoolHoldMarker
6687///     }
6688///     fn max_unpool2d(&self) -> __FandheConvTranspose3dMaxUnpoolHoldMarker {
6689///         __FandheConvTranspose3dMaxUnpoolHoldMarker
6690///     }
6691///     fn max_unpool3d(&self) -> __FandheConvTranspose3dMaxUnpoolHoldMarker {
6692///         __FandheConvTranspose3dMaxUnpoolHoldMarker
6693///     }
6694/// }
6695///
6696/// impl __FandheConvTranspose3dMaxUnpoolHoldProbe for fandhe_ai::Tensor<f32> {
6697///     fn conv_transpose3d(&self) -> __FandheConvTranspose3dMaxUnpoolHoldMarker {
6698///         __FandheConvTranspose3dMaxUnpoolHoldMarker
6699///     }
6700///     fn max_unpool1d(&self) -> __FandheConvTranspose3dMaxUnpoolHoldMarker {
6701///         __FandheConvTranspose3dMaxUnpoolHoldMarker
6702///     }
6703///     fn max_unpool2d(&self) -> __FandheConvTranspose3dMaxUnpoolHoldMarker {
6704///         __FandheConvTranspose3dMaxUnpoolHoldMarker
6705///     }
6706///     fn max_unpool3d(&self) -> __FandheConvTranspose3dMaxUnpoolHoldMarker {
6707///         __FandheConvTranspose3dMaxUnpoolHoldMarker
6708///     }
6709/// }
6710///
6711/// trait __FandheConvTranspose3dMaxUnpoolHoldSequentialProbe {
6712///     fn add_max_unpool1d(&self) -> __FandheConvTranspose3dMaxUnpoolHoldMarker;
6713///     fn add_max_unpool2d(&self) -> __FandheConvTranspose3dMaxUnpoolHoldMarker;
6714///     fn add_max_unpool3d(&self) -> __FandheConvTranspose3dMaxUnpoolHoldMarker;
6715/// }
6716///
6717/// impl __FandheConvTranspose3dMaxUnpoolHoldSequentialProbe for fandhe_ai::compat::Sequential {
6718///     fn add_max_unpool1d(&self) -> __FandheConvTranspose3dMaxUnpoolHoldMarker {
6719///         __FandheConvTranspose3dMaxUnpoolHoldMarker
6720///     }
6721///     fn add_max_unpool2d(&self) -> __FandheConvTranspose3dMaxUnpoolHoldMarker {
6722///         __FandheConvTranspose3dMaxUnpoolHoldMarker
6723///     }
6724///     fn add_max_unpool3d(&self) -> __FandheConvTranspose3dMaxUnpoolHoldMarker {
6725///         __FandheConvTranspose3dMaxUnpoolHoldMarker
6726///     }
6727/// }
6728///
6729/// fn __probe_free_fns(_: ConvTranspose3d, _: MaxUnpool1d, _: MaxUnpool2d, _: MaxUnpool3d, _: MaxUnpoolLayout) {
6730///     // 修飾なし呼び出し(`use fandhe_ai::*;` が同名を glob 公開して
6731///     // いれば、名前解決自体が曖昧になり E0659 でコンパイル失敗する)。
6732///     conv_transpose3d_ops::conv_transpose3d();
6733///     max_unpool_ops::max_unpool1d();
6734///     max_unpool_ops::max_unpool2d();
6735///     max_unpool_ops::max_unpool3d();
6736///     conv_transpose3d::__mark();
6737///     max_unpool::__mark();
6738/// }
6739///
6740/// fn __probe_methods(
6741///     _v: &fandhe_ai::Var<'_>,
6742///     tape: &fandhe_ai::Tape,
6743///     tf: &fandhe_ai::Tensor<f32>,
6744///     seq: &fandhe_ai::compat::Sequential,
6745/// ) {
6746///     let _: __FandheConvTranspose3dMaxUnpoolHoldMarker = fandhe_ai::Tape::conv_transpose3d(tape);
6747///     let _: __FandheConvTranspose3dMaxUnpoolHoldMarker = fandhe_ai::Tape::max_unpool1d(tape);
6748///     let _: __FandheConvTranspose3dMaxUnpoolHoldMarker = fandhe_ai::Tape::max_unpool2d(tape);
6749///     let _: __FandheConvTranspose3dMaxUnpoolHoldMarker = fandhe_ai::Tape::max_unpool3d(tape);
6750///     let _: __FandheConvTranspose3dMaxUnpoolHoldMarker = fandhe_ai::Tensor::<f32>::conv_transpose3d(tf);
6751///     let _: __FandheConvTranspose3dMaxUnpoolHoldMarker = fandhe_ai::Tensor::<f32>::max_unpool1d(tf);
6752///     let _: __FandheConvTranspose3dMaxUnpoolHoldMarker = fandhe_ai::Tensor::<f32>::max_unpool2d(tf);
6753///     let _: __FandheConvTranspose3dMaxUnpoolHoldMarker = fandhe_ai::Tensor::<f32>::max_unpool3d(tf);
6754///     let _: __FandheConvTranspose3dMaxUnpoolHoldMarker = fandhe_ai::compat::Sequential::add_max_unpool1d(seq);
6755///     let _: __FandheConvTranspose3dMaxUnpoolHoldMarker = fandhe_ai::compat::Sequential::add_max_unpool2d(seq);
6756///     let _: __FandheConvTranspose3dMaxUnpoolHoldMarker = fandhe_ai::compat::Sequential::add_max_unpool3d(seq);
6757/// }
6758/// ```
6759#[cfg(doctest)]
6760#[allow(dead_code)]
6761struct ConvTranspose3dMaxUnpoolHoldDoctestGuard;
6762
6763/// Fold と Unfold(`fold`・`unfold`。`F.fold`/`F.unfold`・`nn.Fold`/`nn.Unfold` 相当。イシュー #2645・
6764/// 親 #2625・ルート #2499 Phase 4)のうち、未承認の経路を facade 公開面から締め出す保留ガード
6765/// (`ConvTranspose3dMaxUnpoolHoldDoctestGuard` と同型の正のプローブ 1 ブロック方式)。
6766///
6767/// **#2851 での部分反転**: `Var::fold`/`Var::unfold` の委譲メソッドは、ルート #2499 の
6768/// <https://github.com/Fandhe-AI/fandhe-ai/issues/2499#issuecomment-6052732061> の承認に基づき
6769/// `docs/autodiff-fold-unfold-decision.md` §12.1 の形で公開した(`docs/compat-api-scope.md` §5.1)。
6770/// そのため `Var` へのトレイト impl と UFCS 呼び出しは本プローブから外した(inherent メソッドと
6771/// シグネチャが衝突するため)。公開済み側の正ガードは
6772/// `crates/facade/tests/api_surface.rs`(`workspace_declares_fold_unfold_fn_names_only_in_allowed_locations`・
6773/// `PHASE4_VAR_EXPECTED_BODIES`)が担う。
6774///
6775/// 引き続き拒否する未承認経路は、ローカルモジュール `fold_ops`/`fold`・型 `Fold`/`Unfold`・
6776/// `Tape`/`Tensor<f32>` 上の同名メソッドである。
6777/// **#3040 での部分反転**: `compat::Sequential::add_fold`/`add_unfold` は `docs/compat-sequential-3d-fold-lrn-layers-decision.md` §3 の
6778/// 承認形で公開したため、`Sequential` 向けのトレイト impl と UFCS 呼び出しは本プローブから外した(inherent メソッドと衝突するため)。
6779/// 公開済み側の正ガードは `crates/facade/tests/api_surface.rs::add_fold_unfold_signatures_match_approved_contract` 等が担う。
6780///
6781/// 下の doctest は全 `pub mod` を glob import したスコープへこれらのプローブを置き、facade が同名のモジュール・型・関数を
6782/// glob 可能な位置へ公開するか、これらの型へ同名の inherent メソッドを公開すると、名前解決の曖昧性または
6783/// 呼び出しシグネチャの不一致でエラーコードに依存せずコンパイルが失敗する(`Tensor` は facade から再エクスポートされるため、
6784/// `tensor-core` 側への同名メソッド追加も検出する)。検出範囲はこれらの名前・型に限り、マクロ生成や別名経由の
6785/// メソッドまでは保証しない。
6786///
6787/// ソース走査ガード(`crates/facade/tests/api_surface.rs::fold_unfold_hold_doctest_globs_all_pub_modules`・
6788/// `fold_unfold_hold_doctest_probe_body_matches_fixed_contract`・
6789/// `facade_does_not_reexport_or_declare_fold_unfold`・
6790/// `workspace_declares_fold_unfold_fn_names_only_in_allowed_locations`)との多層防御として働く。
6791///
6792/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
6793/// できること
6794///
6795/// ```
6796/// use fandhe_ai::*;
6797/// use fandhe_ai::compat::*;
6798/// use fandhe_ai::optim::*;
6799/// use fandhe_ai::data::*;
6800/// use fandhe_ai::nn::*;
6801/// use fandhe_ai::nn::init::*;
6802/// use fandhe_ai::nn::rnn::*;
6803/// use fandhe_ai::nn::kv_cache::*;
6804/// use fandhe_ai::nn::loss::*;
6805/// use fandhe_ai::interop::*;
6806/// use fandhe_ai::interop::onnx::*;
6807/// use fandhe_ai::interop::safetensors::*;
6808/// use fandhe_ai::interop::npy::*;
6809/// use fandhe_ai::model::*;
6810/// use fandhe_ai::inference::*;
6811/// use fandhe_ai::text::*;
6812/// use fandhe_ai::models::*;
6813/// use fandhe_ai::distributed::*;
6814///
6815/// mod __fandhe_fold_unfold_hold_probe {
6816///     pub struct Fold;
6817///     pub struct Unfold;
6818///     pub mod fold_ops {
6819///         pub fn fold() {}
6820///         pub fn unfold() {}
6821///     }
6822///     pub mod fold {
6823///         pub fn __mark() {}
6824///     }
6825/// }
6826/// use __fandhe_fold_unfold_hold_probe::*;
6827///
6828/// struct __FandheFoldUnfoldHoldMarker;
6829///
6830/// trait __FandheFoldUnfoldHoldProbe {
6831///     fn fold(&self) -> __FandheFoldUnfoldHoldMarker;
6832///     fn unfold(&self) -> __FandheFoldUnfoldHoldMarker;
6833/// }
6834///
6835/// impl __FandheFoldUnfoldHoldProbe for fandhe_ai::Tape {
6836///     fn fold(&self) -> __FandheFoldUnfoldHoldMarker {
6837///         __FandheFoldUnfoldHoldMarker
6838///     }
6839///     fn unfold(&self) -> __FandheFoldUnfoldHoldMarker {
6840///         __FandheFoldUnfoldHoldMarker
6841///     }
6842/// }
6843///
6844/// impl __FandheFoldUnfoldHoldProbe for fandhe_ai::Tensor<f32> {
6845///     fn fold(&self) -> __FandheFoldUnfoldHoldMarker {
6846///         __FandheFoldUnfoldHoldMarker
6847///     }
6848///     fn unfold(&self) -> __FandheFoldUnfoldHoldMarker {
6849///         __FandheFoldUnfoldHoldMarker
6850///     }
6851/// }
6852///
6853/// fn __probe_free_fns(_: Fold, _: Unfold) {
6854///     // 修飾なし呼び出し(`use fandhe_ai::*;` が同名を glob 公開していれば、名前解決自体が曖昧になり
6855///     // E0659 でコンパイル失敗する)。
6856///     fold_ops::fold();
6857///     fold_ops::unfold();
6858///     fold::__mark();
6859/// }
6860///
6861/// fn __probe_methods(
6862///     _v: &fandhe_ai::Var<'_>,
6863///     tape: &fandhe_ai::Tape,
6864///     tf: &fandhe_ai::Tensor<f32>,
6865/// ) {
6866///     let _: __FandheFoldUnfoldHoldMarker = fandhe_ai::Tape::fold(tape);
6867///     let _: __FandheFoldUnfoldHoldMarker = fandhe_ai::Tape::unfold(tape);
6868///     let _: __FandheFoldUnfoldHoldMarker = fandhe_ai::Tensor::<f32>::fold(tf);
6869///     let _: __FandheFoldUnfoldHoldMarker = fandhe_ai::Tensor::<f32>::unfold(tf);
6870/// }
6871/// ```
6872#[cfg(doctest)]
6873#[allow(dead_code)]
6874struct FoldUnfoldHoldDoctestGuard;
6875
6876/// LocalResponseNorm と重み再パラメータ化(`local_response_norm`・`weight_norm`・`norm_except_dim`・
6877/// `spectral_norm`。`F.local_response_norm`・`torch._weight_norm`・`parametrizations.spectral_norm` 相当。
6878/// イシュー #2646・親 #2625・ルート #2499 Phase 4)のうち、未承認の経路を facade 公開面から締め出す保留ガード
6879/// (`FoldUnfoldHoldDoctestGuard` と同型の正のプローブ 1 ブロック方式)。
6880///
6881/// **#2851 での部分反転**: `Var::local_response_norm`/`Var::weight_norm`/`Var::spectral_norm` の委譲メソッドと
6882/// `SpectralNormState` のクレートルート再エクスポートは、ルート #2499 の
6883/// <https://github.com/Fandhe-AI/fandhe-ai/issues/2499#issuecomment-6052732061> の承認に基づき
6884/// `docs/autodiff-lrn-weight-reparam-decision.md` §12.1・§12.2 の形で公開した(`docs/compat-api-scope.md` §5.1)。
6885/// そのため下の `Var` 向け UFCS 呼び出し 3 行と、プローブモジュール内のローカル型 `SpectralNormState`
6886/// (ルート再エクスポートと glob 衝突して E0659 になるため)を外した。`Var` へのトレイト impl は
6887/// `norm_except_dim`(非公開のまま保留)のプローブのため残す。公開済み側の正ガードは
6888/// `crates/facade/tests/api_surface.rs`(`facade_reexports_spectral_norm_state_only_in_approved_shape`・
6889/// `workspace_declares_lrn_weight_reparam_fn_names_only_in_allowed_locations`・`PHASE4_VAR_EXPECTED_BODIES`)が担う。
6890///
6891/// 引き続き拒否する未承認経路は、ローカルモジュール `lrn_ops`/`weight_reparam_ops`/`lrn`/`weight_reparam`・
6892/// 型 `LocalResponseNorm`/`WeightNorm`/`SpectralNorm`・`Var::norm_except_dim` と `Tape`/`Tensor<f32>` 上の
6893/// 同名メソッドである(層化・結線は #3050 までに `compat::Sequential::parametrize_weight_norm`/
6894/// `parametrize_spectral_norm` として公開済みのため、未採用名 `add_weight_norm`/`add_spectral_norm` の
6895/// プローブは外した。復活は `api_surface.rs` の workspace インベントリが検出する)。
6896/// **#3044 での部分反転**: `compat::Sequential::add_local_response_norm` は
6897/// `docs/compat-sequential-3d-fold-lrn-layers-decision.md` §3 の承認形で公開したため、`Sequential` 向けのトレイト impl と
6898/// UFCS 呼び出しから同名だけを外した(inherent メソッドと衝突するため)。
6899/// **#3050 での反転**: `Sequential` 向けのトレイト・impl・UFCS 呼び出し(`add_weight_norm`/`add_spectral_norm`)を
6900/// 外した(公開名は `parametrize_*` に確定し、`add_*` 名は採用されなかったため。`save_model`/`load_model` 対応も同時に追加)。
6901/// 残る保留は決定記録 `docs/autodiff-lrn-weight-reparam-decision.md` で非公開と確定した名前
6902/// (`norm_except_dim`・`Tape`/`Tensor<f32>` 上の同名メソッド・モジュール・型)である。
6903/// 公開済み側の正ガードは `crates/facade/tests/api_surface.rs::add_local_response_norm_signature_matches_approved_contract`
6904/// 等が担う。
6905///
6906/// 下の doctest は全 `pub mod` を glob import したスコープへこれらのプローブを置き、
6907/// facade が同名のモジュール・型・関数を glob 可能な位置へ公開するか、これらの型へ同名の inherent メソッドを公開すると、
6908/// 名前解決の曖昧性または呼び出しシグネチャの不一致でエラーコードに依存せずコンパイルが失敗する
6909/// (`Tensor` は facade から再エクスポートされるため、`tensor-core` 側への同名メソッド追加も検出する)。
6910/// 検出範囲はこれらの名前・型に限り、マクロ生成や別名経由のメソッドまでは保証しない。
6911///
6912/// ソース走査ガード(`crates/facade/tests/api_surface.rs::lrn_weight_reparam_hold_doctest_globs_all_pub_modules`・
6913/// `lrn_weight_reparam_hold_doctest_probe_body_matches_fixed_contract`・
6914/// `facade_does_not_reexport_or_declare_lrn_weight_reparam`・
6915/// `workspace_declares_lrn_weight_reparam_fn_names_only_in_allowed_locations`)との多層防御として働く。
6916///
6917/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
6918/// できること
6919///
6920/// ```
6921/// use fandhe_ai::*;
6922/// use fandhe_ai::compat::*;
6923/// use fandhe_ai::optim::*;
6924/// use fandhe_ai::data::*;
6925/// use fandhe_ai::nn::*;
6926/// use fandhe_ai::nn::init::*;
6927/// use fandhe_ai::nn::rnn::*;
6928/// use fandhe_ai::nn::kv_cache::*;
6929/// use fandhe_ai::nn::loss::*;
6930/// use fandhe_ai::interop::*;
6931/// use fandhe_ai::interop::onnx::*;
6932/// use fandhe_ai::interop::safetensors::*;
6933/// use fandhe_ai::interop::npy::*;
6934/// use fandhe_ai::model::*;
6935/// use fandhe_ai::inference::*;
6936/// use fandhe_ai::text::*;
6937/// use fandhe_ai::models::*;
6938/// use fandhe_ai::distributed::*;
6939///
6940/// mod __fandhe_lrn_weight_reparam_hold_probe {
6941///     pub struct LocalResponseNorm;
6942///     pub struct WeightNorm;
6943///     pub struct SpectralNorm;
6944///     pub mod lrn_ops {
6945///         pub fn local_response_norm() {}
6946///     }
6947///     pub mod weight_reparam_ops {
6948///         pub fn weight_norm() {}
6949///         pub fn norm_except_dim() {}
6950///         pub fn spectral_norm() {}
6951///     }
6952///     pub mod lrn {
6953///         pub fn __mark() {}
6954///     }
6955///     pub mod weight_reparam {
6956///         pub fn __mark() {}
6957///     }
6958/// }
6959/// use __fandhe_lrn_weight_reparam_hold_probe::*;
6960///
6961/// struct __FandheLrnWeightReparamHoldMarker;
6962///
6963/// trait __FandheLrnWeightReparamHoldProbe {
6964///     fn local_response_norm(&self) -> __FandheLrnWeightReparamHoldMarker;
6965///     fn weight_norm(&self) -> __FandheLrnWeightReparamHoldMarker;
6966///     fn spectral_norm(&self) -> __FandheLrnWeightReparamHoldMarker;
6967///     fn norm_except_dim(&self) -> __FandheLrnWeightReparamHoldMarker;
6968/// }
6969///
6970/// impl<'t> __FandheLrnWeightReparamHoldProbe for fandhe_ai::Var<'t> {
6971///     fn local_response_norm(&self) -> __FandheLrnWeightReparamHoldMarker {
6972///         __FandheLrnWeightReparamHoldMarker
6973///     }
6974///     fn weight_norm(&self) -> __FandheLrnWeightReparamHoldMarker {
6975///         __FandheLrnWeightReparamHoldMarker
6976///     }
6977///     fn spectral_norm(&self) -> __FandheLrnWeightReparamHoldMarker {
6978///         __FandheLrnWeightReparamHoldMarker
6979///     }
6980///     fn norm_except_dim(&self) -> __FandheLrnWeightReparamHoldMarker {
6981///         __FandheLrnWeightReparamHoldMarker
6982///     }
6983/// }
6984///
6985/// impl __FandheLrnWeightReparamHoldProbe for fandhe_ai::Tape {
6986///     fn local_response_norm(&self) -> __FandheLrnWeightReparamHoldMarker {
6987///         __FandheLrnWeightReparamHoldMarker
6988///     }
6989///     fn weight_norm(&self) -> __FandheLrnWeightReparamHoldMarker {
6990///         __FandheLrnWeightReparamHoldMarker
6991///     }
6992///     fn spectral_norm(&self) -> __FandheLrnWeightReparamHoldMarker {
6993///         __FandheLrnWeightReparamHoldMarker
6994///     }
6995///     fn norm_except_dim(&self) -> __FandheLrnWeightReparamHoldMarker {
6996///         __FandheLrnWeightReparamHoldMarker
6997///     }
6998/// }
6999///
7000/// impl __FandheLrnWeightReparamHoldProbe for fandhe_ai::Tensor<f32> {
7001///     fn local_response_norm(&self) -> __FandheLrnWeightReparamHoldMarker {
7002///         __FandheLrnWeightReparamHoldMarker
7003///     }
7004///     fn weight_norm(&self) -> __FandheLrnWeightReparamHoldMarker {
7005///         __FandheLrnWeightReparamHoldMarker
7006///     }
7007///     fn spectral_norm(&self) -> __FandheLrnWeightReparamHoldMarker {
7008///         __FandheLrnWeightReparamHoldMarker
7009///     }
7010///     fn norm_except_dim(&self) -> __FandheLrnWeightReparamHoldMarker {
7011///         __FandheLrnWeightReparamHoldMarker
7012///     }
7013/// }
7014///
7015/// fn __probe_free_fns(_: LocalResponseNorm, _: WeightNorm, _: SpectralNorm) {
7016///     // 修飾なし呼び出し(`use fandhe_ai::*;` が同名を glob 公開していれば、名前解決自体が曖昧になり
7017///     // E0659 でコンパイル失敗する)。
7018///     lrn_ops::local_response_norm();
7019///     weight_reparam_ops::weight_norm();
7020///     weight_reparam_ops::norm_except_dim();
7021///     weight_reparam_ops::spectral_norm();
7022///     lrn::__mark();
7023///     weight_reparam::__mark();
7024/// }
7025///
7026/// fn __probe_methods(
7027///     v: &fandhe_ai::Var<'_>,
7028///     tape: &fandhe_ai::Tape,
7029///     tf: &fandhe_ai::Tensor<f32>,
7030/// ) {
7031///     let _: __FandheLrnWeightReparamHoldMarker = fandhe_ai::Var::norm_except_dim(v);
7032///     let _: __FandheLrnWeightReparamHoldMarker = fandhe_ai::Tape::local_response_norm(tape);
7033///     let _: __FandheLrnWeightReparamHoldMarker = fandhe_ai::Tape::weight_norm(tape);
7034///     let _: __FandheLrnWeightReparamHoldMarker = fandhe_ai::Tape::spectral_norm(tape);
7035///     let _: __FandheLrnWeightReparamHoldMarker = fandhe_ai::Tape::norm_except_dim(tape);
7036///     let _: __FandheLrnWeightReparamHoldMarker = fandhe_ai::Tensor::<f32>::local_response_norm(tf);
7037///     let _: __FandheLrnWeightReparamHoldMarker = fandhe_ai::Tensor::<f32>::weight_norm(tf);
7038///     let _: __FandheLrnWeightReparamHoldMarker = fandhe_ai::Tensor::<f32>::spectral_norm(tf);
7039///     let _: __FandheLrnWeightReparamHoldMarker = fandhe_ai::Tensor::<f32>::norm_except_dim(tf);
7040/// }
7041/// ```
7042#[cfg(doctest)]
7043#[allow(dead_code)]
7044struct LrnWeightReparamHoldDoctestGuard;
7045
7046/// 可変長系列の pack/unpack(`pack_padded_sequence`・`pad_packed_sequence`・`PackedSequence`)と RNN 系の
7047/// packed 実行(`rnn_forward_packed`・`gru_forward_packed`・`lstm_forward_packed`・`stacked_*_forward_packed`。
7048/// `torch.nn.utils.rnn` 相当。イシュー #2647・親 #2625・ルート #2499 Phase 4)の保留ガード。イシュー #2679 で
7049/// 承認形(`fandhe_ai::nn::rnn` への型 5・自由関数 8 の純再エクスポート。`docs/autodiff-packed-sequence-decision.md`
7050/// §7)を公開したため、型名・自由関数名の衝突プローブは削除した(`LrnWeightReparamHoldDoctestGuard` と同型の
7051/// 正のプローブ 1 ブロック方式)。
7052///
7053/// 残すのは**未承認の経路**だけである。下の doctest は全 `pub mod` を glob import したスコープへ、ローカルモジュール
7054/// `packed_sequence`(facade が同名の公開モジュールを持たないこと)と、プローブ用トレイトのメソッド
7055/// (`Var`/`Tape`/`Tensor<f32>` の `pack_padded_sequence`/`pad_packed_sequence`、`Tape` の `*_forward_packed` 6 名、
7056/// `nn::rnn::{Rnn, Lstm, Gru, StackedRnn, StackedLstm, StackedGru}` の `forward_packed`)を置き、修飾なしのモジュール
7057/// 参照と修飾付きメソッド呼び出しの両方を行う。facade が同名のモジュールを glob 可能な位置へ公開するか、これらの型へ
7058/// 同名の inherent メソッド(`Var` 委譲・`Tape` 委譲・`Rnn::forward_packed`)を公開すると、名前解決の曖昧性または
7059/// 呼び出しシグネチャの不一致でエラーコードに依存せずコンパイルが失敗する。検出範囲は列挙したこれらの名前・型に限り、
7060/// マクロ生成や別名経由のメソッドまでは保証しない。
7061///
7062/// ソース走査ガード(`crates/facade/tests/api_surface.rs::packed_sequence_hold_doctest_globs_all_pub_modules`・
7063/// `packed_sequence_hold_doctest_probe_body_matches_fixed_contract`・
7064/// `facade_does_not_reexport_or_declare_packed_sequence`・
7065/// `facade_exposes_packed_sequence_only_in_approved_shape`・
7066/// `workspace_declares_packed_sequence_fn_names_only_in_allowed_locations`)との多層防御として働く。
7067///
7068/// 未承認経路(`Var`/`Tape` 委譲メソッド等)が承認される日が来たら、本構造体・本 doctest 自体を削除する。
7069///
7070/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
7071/// できること
7072///
7073/// ```
7074/// use fandhe_ai::*;
7075/// use fandhe_ai::compat::*;
7076/// use fandhe_ai::optim::*;
7077/// use fandhe_ai::data::*;
7078/// use fandhe_ai::nn::*;
7079/// use fandhe_ai::nn::init::*;
7080/// use fandhe_ai::nn::rnn::*;
7081/// use fandhe_ai::nn::kv_cache::*;
7082/// use fandhe_ai::nn::loss::*;
7083/// use fandhe_ai::interop::*;
7084/// use fandhe_ai::interop::onnx::*;
7085/// use fandhe_ai::interop::safetensors::*;
7086/// use fandhe_ai::interop::npy::*;
7087/// use fandhe_ai::model::*;
7088/// use fandhe_ai::inference::*;
7089/// use fandhe_ai::text::*;
7090/// use fandhe_ai::models::*;
7091/// use fandhe_ai::distributed::*;
7092///
7093/// mod __fandhe_packed_sequence_hold_probe {
7094///     pub mod packed_sequence {
7095///         pub fn __mark() {}
7096///     }
7097/// }
7098/// use __fandhe_packed_sequence_hold_probe::*;
7099///
7100/// struct __FandhePackedSequenceHoldMarker;
7101///
7102/// trait __FandhePackedSequenceHoldProbe {
7103///     fn pack_padded_sequence(&self) -> __FandhePackedSequenceHoldMarker;
7104///     fn pad_packed_sequence(&self) -> __FandhePackedSequenceHoldMarker;
7105/// }
7106///
7107/// trait __FandhePackedSequenceHoldTapeProbe {
7108///     fn rnn_forward_packed(&self) -> __FandhePackedSequenceHoldMarker;
7109///     fn gru_forward_packed(&self) -> __FandhePackedSequenceHoldMarker;
7110///     fn lstm_forward_packed(&self) -> __FandhePackedSequenceHoldMarker;
7111///     fn stacked_rnn_forward_packed(&self) -> __FandhePackedSequenceHoldMarker;
7112///     fn stacked_gru_forward_packed(&self) -> __FandhePackedSequenceHoldMarker;
7113///     fn stacked_lstm_forward_packed(&self) -> __FandhePackedSequenceHoldMarker;
7114/// }
7115///
7116/// trait __FandhePackedSequenceHoldRnnProbe {
7117///     fn forward_packed(&self) -> __FandhePackedSequenceHoldMarker;
7118/// }
7119///
7120/// impl<'t> __FandhePackedSequenceHoldProbe for fandhe_ai::Var<'t> {
7121///     fn pack_padded_sequence(&self) -> __FandhePackedSequenceHoldMarker {
7122///         __FandhePackedSequenceHoldMarker
7123///     }
7124///     fn pad_packed_sequence(&self) -> __FandhePackedSequenceHoldMarker {
7125///         __FandhePackedSequenceHoldMarker
7126///     }
7127/// }
7128///
7129/// impl __FandhePackedSequenceHoldProbe for fandhe_ai::Tape {
7130///     fn pack_padded_sequence(&self) -> __FandhePackedSequenceHoldMarker {
7131///         __FandhePackedSequenceHoldMarker
7132///     }
7133///     fn pad_packed_sequence(&self) -> __FandhePackedSequenceHoldMarker {
7134///         __FandhePackedSequenceHoldMarker
7135///     }
7136/// }
7137///
7138/// impl __FandhePackedSequenceHoldProbe for fandhe_ai::Tensor<f32> {
7139///     fn pack_padded_sequence(&self) -> __FandhePackedSequenceHoldMarker {
7140///         __FandhePackedSequenceHoldMarker
7141///     }
7142///     fn pad_packed_sequence(&self) -> __FandhePackedSequenceHoldMarker {
7143///         __FandhePackedSequenceHoldMarker
7144///     }
7145/// }
7146///
7147/// impl __FandhePackedSequenceHoldTapeProbe for fandhe_ai::Tape {
7148///     fn rnn_forward_packed(&self) -> __FandhePackedSequenceHoldMarker {
7149///         __FandhePackedSequenceHoldMarker
7150///     }
7151///     fn gru_forward_packed(&self) -> __FandhePackedSequenceHoldMarker {
7152///         __FandhePackedSequenceHoldMarker
7153///     }
7154///     fn lstm_forward_packed(&self) -> __FandhePackedSequenceHoldMarker {
7155///         __FandhePackedSequenceHoldMarker
7156///     }
7157///     fn stacked_rnn_forward_packed(&self) -> __FandhePackedSequenceHoldMarker {
7158///         __FandhePackedSequenceHoldMarker
7159///     }
7160///     fn stacked_gru_forward_packed(&self) -> __FandhePackedSequenceHoldMarker {
7161///         __FandhePackedSequenceHoldMarker
7162///     }
7163///     fn stacked_lstm_forward_packed(&self) -> __FandhePackedSequenceHoldMarker {
7164///         __FandhePackedSequenceHoldMarker
7165///     }
7166/// }
7167///
7168/// impl __FandhePackedSequenceHoldRnnProbe for fandhe_ai::nn::rnn::Rnn {
7169///     fn forward_packed(&self) -> __FandhePackedSequenceHoldMarker {
7170///         __FandhePackedSequenceHoldMarker
7171///     }
7172/// }
7173///
7174/// impl __FandhePackedSequenceHoldRnnProbe for fandhe_ai::nn::rnn::Lstm {
7175///     fn forward_packed(&self) -> __FandhePackedSequenceHoldMarker {
7176///         __FandhePackedSequenceHoldMarker
7177///     }
7178/// }
7179///
7180/// impl __FandhePackedSequenceHoldRnnProbe for fandhe_ai::nn::rnn::Gru {
7181///     fn forward_packed(&self) -> __FandhePackedSequenceHoldMarker {
7182///         __FandhePackedSequenceHoldMarker
7183///     }
7184/// }
7185///
7186/// impl __FandhePackedSequenceHoldRnnProbe for fandhe_ai::nn::rnn::StackedRnn {
7187///     fn forward_packed(&self) -> __FandhePackedSequenceHoldMarker {
7188///         __FandhePackedSequenceHoldMarker
7189///     }
7190/// }
7191///
7192/// impl __FandhePackedSequenceHoldRnnProbe for fandhe_ai::nn::rnn::StackedLstm {
7193///     fn forward_packed(&self) -> __FandhePackedSequenceHoldMarker {
7194///         __FandhePackedSequenceHoldMarker
7195///     }
7196/// }
7197///
7198/// impl __FandhePackedSequenceHoldRnnProbe for fandhe_ai::nn::rnn::StackedGru {
7199///     fn forward_packed(&self) -> __FandhePackedSequenceHoldMarker {
7200///         __FandhePackedSequenceHoldMarker
7201///     }
7202/// }
7203///
7204/// fn __probe_module() {
7205///     // 修飾なし参照(`use fandhe_ai::*;` が同名モジュールを glob 公開していれば、名前解決自体が曖昧になり
7206///     // E0659 でコンパイル失敗する)。
7207///     packed_sequence::__mark();
7208/// }
7209///
7210/// fn __probe_methods(
7211///     v: &fandhe_ai::Var<'_>,
7212///     tape: &fandhe_ai::Tape,
7213///     tf: &fandhe_ai::Tensor<f32>,
7214///     rnn: &fandhe_ai::nn::rnn::Rnn,
7215///     lstm: &fandhe_ai::nn::rnn::Lstm,
7216///     gru: &fandhe_ai::nn::rnn::Gru,
7217///     stackedrnn: &fandhe_ai::nn::rnn::StackedRnn,
7218///     stackedlstm: &fandhe_ai::nn::rnn::StackedLstm,
7219///     stackedgru: &fandhe_ai::nn::rnn::StackedGru,
7220/// ) {
7221///     let _: __FandhePackedSequenceHoldMarker = fandhe_ai::Var::pack_padded_sequence(v);
7222///     let _: __FandhePackedSequenceHoldMarker = fandhe_ai::Tape::pack_padded_sequence(tape);
7223///     let _: __FandhePackedSequenceHoldMarker = fandhe_ai::Tensor::<f32>::pack_padded_sequence(tf);
7224///     let _: __FandhePackedSequenceHoldMarker = fandhe_ai::Var::pad_packed_sequence(v);
7225///     let _: __FandhePackedSequenceHoldMarker = fandhe_ai::Tape::pad_packed_sequence(tape);
7226///     let _: __FandhePackedSequenceHoldMarker = fandhe_ai::Tensor::<f32>::pad_packed_sequence(tf);
7227///     let _: __FandhePackedSequenceHoldMarker = fandhe_ai::Tape::rnn_forward_packed(tape);
7228///     let _: __FandhePackedSequenceHoldMarker = fandhe_ai::Tape::gru_forward_packed(tape);
7229///     let _: __FandhePackedSequenceHoldMarker = fandhe_ai::Tape::lstm_forward_packed(tape);
7230///     let _: __FandhePackedSequenceHoldMarker = fandhe_ai::Tape::stacked_rnn_forward_packed(tape);
7231///     let _: __FandhePackedSequenceHoldMarker = fandhe_ai::Tape::stacked_gru_forward_packed(tape);
7232///     let _: __FandhePackedSequenceHoldMarker = fandhe_ai::Tape::stacked_lstm_forward_packed(tape);
7233///     let _: __FandhePackedSequenceHoldMarker = fandhe_ai::nn::rnn::Rnn::forward_packed(rnn);
7234///     let _: __FandhePackedSequenceHoldMarker = fandhe_ai::nn::rnn::Lstm::forward_packed(lstm);
7235///     let _: __FandhePackedSequenceHoldMarker = fandhe_ai::nn::rnn::Gru::forward_packed(gru);
7236///     let _: __FandhePackedSequenceHoldMarker = fandhe_ai::nn::rnn::StackedRnn::forward_packed(stackedrnn);
7237///     let _: __FandhePackedSequenceHoldMarker = fandhe_ai::nn::rnn::StackedLstm::forward_packed(stackedlstm);
7238///     let _: __FandhePackedSequenceHoldMarker = fandhe_ai::nn::rnn::StackedGru::forward_packed(stackedgru);
7239/// }
7240/// ```
7241#[cfg(doctest)]
7242#[allow(dead_code)]
7243struct PackedSequenceHoldDoctestGuard;
7244
7245/// SELU・CELU・Softsign・Hardsigmoid・LogSigmoid(`selu`・`celu`・`softsign`・
7246/// `hardsigmoid`・`log_sigmoid`。イシュー #2649・親 #2648)の未承認経路の facade 公開保留ガード
7247/// (`PackedSequenceHoldDoctestGuard` と同型の正のプローブ 1 ブロック方式)。
7248///
7249/// 下の doctest は全 `pub mod` を glob import したスコープへ、未承認経路に対応するローカル定義(モジュール `activation_scalar_ops`、型 `Selu`・`Celu`・`Softsign`・`Hardsigmoid`・`LogSigmoid`、クレートルート直下の裸の自由関数 `selu`・`celu`・`softsign`・`hardsigmoid`・`log_sigmoid`)と、
7250/// 同名メソッドを持つプローブ用トレイト(受け手: `Tape`・`Tensor<f32>`)を置き、修飾なしの関数呼び出しと修飾付き(UFCS)のメソッド呼び出しの両方を行う。
7251/// facade が同名のモジュール・関数・型を glob 可能な位置へ公開するか、上の受け手へ同名の inherent メソッドを公開すると、
7252/// 名前解決の曖昧性または呼び出しシグネチャの不一致でエラーコードに依存せずコンパイルが失敗する(`Tensor` は facade から再エクスポートされるため、`tensor-core` 側への同名メソッド追加も検出する)。
7253///
7254/// **#2678 での部分反転**(ルート #2499 の一括承認 `issuecomment-6033824965`・`docs/compat-api-scope.md` §5.1。
7255/// `VarActivationOpsHoldDoctestGuard` の #2516 部分反転と同型): `Var::{selu,celu,softsign,hardsigmoid,log_sigmoid}` は承認形どおり公開済みのため、
7256/// 該当する UFCS 行と、受け手 `Var` の `impl` ブロックを外した(残すと公開した inherent メソッドや再エクスポート型との衝突でコンパイルが失敗する)。残した受け手の `impl` ブロックは、同じトレイトの別メソッド分のプローブとして維持する。
7257/// 引き続き拒否する未承認経路: モジュール `activation_scalar_ops`、型 `Selu`・`Celu`・`Softsign`・`Hardsigmoid`・`LogSigmoid`、クレートルート直下の裸の自由関数 `selu`・`celu`・`softsign`・`hardsigmoid`・`log_sigmoid`・残した受け手(`Tape`・`Tensor<f32>`)上の、公開していない名前の同名メソッド。
7258/// **検出範囲の限定**: 列挙した名前・型・受け手に限り、マクロ生成や別名経由の公開までは保証しない。
7259/// 公開済み側の正ガード(薄い委譲・シグネチャ・到達性)は `crates/facade/tests/api_surface.rs` が固定する。
7260///
7261/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
7262/// activation_scalar_ops_hold_doctest_globs_all_pub_modules`・
7263/// `activation_scalar_ops_hold_doctest_probe_body_matches_fixed_contract`・
7264/// `facade_does_not_reexport_or_declare_activation_scalar_ops`・
7265/// `workspace_declares_activation_scalar_ops_fn_names_only_in_allowed_locations`)との多層防御として働く。
7266///
7267/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
7268/// できること
7269///
7270/// ```
7271/// use fandhe_ai::*;
7272/// use fandhe_ai::compat::*;
7273/// use fandhe_ai::optim::*;
7274/// use fandhe_ai::data::*;
7275/// use fandhe_ai::nn::*;
7276/// use fandhe_ai::nn::init::*;
7277/// use fandhe_ai::nn::rnn::*;
7278/// use fandhe_ai::nn::kv_cache::*;
7279/// use fandhe_ai::nn::loss::*;
7280/// use fandhe_ai::interop::*;
7281/// use fandhe_ai::interop::onnx::*;
7282/// use fandhe_ai::interop::safetensors::*;
7283/// use fandhe_ai::interop::npy::*;
7284/// use fandhe_ai::model::*;
7285/// use fandhe_ai::inference::*;
7286/// use fandhe_ai::text::*;
7287/// use fandhe_ai::models::*;
7288/// use fandhe_ai::distributed::*;
7289///
7290/// mod __fandhe_activation_scalar_ops_hold_probe {
7291///     pub struct Selu;
7292///     pub struct Celu;
7293///     pub struct Softsign;
7294///     pub struct Hardsigmoid;
7295///     pub struct LogSigmoid;
7296///     pub fn selu() {}
7297///     pub fn celu() {}
7298///     pub fn softsign() {}
7299///     pub fn hardsigmoid() {}
7300///     pub fn log_sigmoid() {}
7301///     pub mod activation_scalar_ops {
7302///         pub fn __mark() {}
7303///     }
7304/// }
7305/// use __fandhe_activation_scalar_ops_hold_probe::*;
7306///
7307/// struct __FandheActivationScalarOpsHoldMarker;
7308///
7309/// trait __FandheActivationScalarOpsHoldProbe {
7310///     fn selu(&self) -> __FandheActivationScalarOpsHoldMarker;
7311///     fn celu(&self) -> __FandheActivationScalarOpsHoldMarker;
7312///     fn softsign(&self) -> __FandheActivationScalarOpsHoldMarker;
7313///     fn hardsigmoid(&self) -> __FandheActivationScalarOpsHoldMarker;
7314///     fn log_sigmoid(&self) -> __FandheActivationScalarOpsHoldMarker;
7315/// }
7316///
7317/// impl __FandheActivationScalarOpsHoldProbe for fandhe_ai::Tape {
7318///     fn selu(&self) -> __FandheActivationScalarOpsHoldMarker {
7319///         __FandheActivationScalarOpsHoldMarker
7320///     }
7321///     fn celu(&self) -> __FandheActivationScalarOpsHoldMarker {
7322///         __FandheActivationScalarOpsHoldMarker
7323///     }
7324///     fn softsign(&self) -> __FandheActivationScalarOpsHoldMarker {
7325///         __FandheActivationScalarOpsHoldMarker
7326///     }
7327///     fn hardsigmoid(&self) -> __FandheActivationScalarOpsHoldMarker {
7328///         __FandheActivationScalarOpsHoldMarker
7329///     }
7330///     fn log_sigmoid(&self) -> __FandheActivationScalarOpsHoldMarker {
7331///         __FandheActivationScalarOpsHoldMarker
7332///     }
7333/// }
7334///
7335/// impl __FandheActivationScalarOpsHoldProbe for fandhe_ai::Tensor<f32> {
7336///     fn selu(&self) -> __FandheActivationScalarOpsHoldMarker {
7337///         __FandheActivationScalarOpsHoldMarker
7338///     }
7339///     fn celu(&self) -> __FandheActivationScalarOpsHoldMarker {
7340///         __FandheActivationScalarOpsHoldMarker
7341///     }
7342///     fn softsign(&self) -> __FandheActivationScalarOpsHoldMarker {
7343///         __FandheActivationScalarOpsHoldMarker
7344///     }
7345///     fn hardsigmoid(&self) -> __FandheActivationScalarOpsHoldMarker {
7346///         __FandheActivationScalarOpsHoldMarker
7347///     }
7348///     fn log_sigmoid(&self) -> __FandheActivationScalarOpsHoldMarker {
7349///         __FandheActivationScalarOpsHoldMarker
7350///     }
7351/// }
7352///
7353/// fn __probe_free_fns(
7354///     _0: Selu,
7355///     _1: Celu,
7356///     _2: Softsign,
7357///     _3: Hardsigmoid,
7358///     _4: LogSigmoid,
7359/// ) {
7360///     // 修飾なし呼び出し(`use fandhe_ai::*;` が同名を glob 公開していれば、名前解決自体が曖昧になり
7361///     // E0659 でコンパイル失敗する)。
7362///     selu();
7363///     celu();
7364///     softsign();
7365///     hardsigmoid();
7366///     log_sigmoid();
7367///     activation_scalar_ops::__mark();
7368/// }
7369///
7370/// fn __probe_methods(
7371///     _v: &fandhe_ai::Var<'_>,
7372///     tape: &fandhe_ai::Tape,
7373///     tf: &fandhe_ai::Tensor<f32>,
7374/// ) {
7375///     let _: __FandheActivationScalarOpsHoldMarker = fandhe_ai::Tape::selu(tape);
7376///     let _: __FandheActivationScalarOpsHoldMarker = fandhe_ai::Tensor::<f32>::selu(tf);
7377///     let _: __FandheActivationScalarOpsHoldMarker = fandhe_ai::Tape::celu(tape);
7378///     let _: __FandheActivationScalarOpsHoldMarker = fandhe_ai::Tensor::<f32>::celu(tf);
7379///     let _: __FandheActivationScalarOpsHoldMarker = fandhe_ai::Tape::softsign(tape);
7380///     let _: __FandheActivationScalarOpsHoldMarker = fandhe_ai::Tensor::<f32>::softsign(tf);
7381///     let _: __FandheActivationScalarOpsHoldMarker = fandhe_ai::Tape::hardsigmoid(tape);
7382///     let _: __FandheActivationScalarOpsHoldMarker = fandhe_ai::Tensor::<f32>::hardsigmoid(tf);
7383///     let _: __FandheActivationScalarOpsHoldMarker = fandhe_ai::Tape::log_sigmoid(tape);
7384///     let _: __FandheActivationScalarOpsHoldMarker = fandhe_ai::Tensor::<f32>::log_sigmoid(tf);
7385/// }
7386/// ```
7387#[cfg(doctest)]
7388#[allow(dead_code)]
7389struct ActivationScalarOpsHoldDoctestGuard;
7390
7391/// 活性化 4 種(`softmin`・`tanhshrink`・`threshold`・`rrelu`/`rrelu_with_noise` と層 `Softmin`・`Tanhshrink`・
7392/// `Threshold`・`RRelu`。`F.softmin`/`F.tanhshrink`/`F.threshold`/`F.rrelu` 相当。イシュー #2650・親 #2648・
7393/// Phase 親 #2625)の未承認経路の facade 公開保留ガード(`PackedSequenceHoldDoctestGuard` と同型の正のプローブ 1
7394/// ブロック方式)。
7395///
7396/// 下の doctest は全 `pub mod` を glob import したスコープへ、未承認経路に対応するローカル定義(モジュール `softmin_threshold_ops`・`softmin_threshold`、型 `Softmin`・`Tanhshrink`・`RRelu`・`Threshold`)と、
7397/// 同名メソッドを持つプローブ用トレイト(受け手: `Tape`・`Tensor<f32>`・`Var`)を置き、修飾なしの関数呼び出しと修飾付き(UFCS)のメソッド呼び出しの両方を行う。
7398/// facade が同名のモジュール・関数・型を glob 可能な位置へ公開するか、上の受け手へ同名の inherent メソッドを公開すると、
7399/// 名前解決の曖昧性または呼び出しシグネチャの不一致でエラーコードに依存せずコンパイルが失敗する(`Tensor` は facade から再エクスポートされるため、`tensor-core` 側への同名メソッド追加も検出する)。
7400///
7401/// **#2678 での部分反転**(ルート #2499 の一括承認 `issuecomment-6033824965`・`docs/compat-api-scope.md` §5.1。
7402/// `VarActivationOpsHoldDoctestGuard` の #2516 部分反転と同型): `Var::{softmin,tanhshrink,threshold,rrelu}` は承認形どおり公開済みのため、
7403/// 該当する UFCS 行を外した(残すと公開した inherent メソッドや再エクスポート型との衝突でコンパイルが失敗する)。残した受け手の `impl` ブロックは、同じトレイトの別メソッド分のプローブとして維持する。
7404/// 引き続き拒否する未承認経路: モジュール `softmin_threshold_ops`・`softmin_threshold`、型 `Softmin`・`Tanhshrink`・`RRelu`・`Threshold`・`Var` 上の `rrelu_with_noise`(公開しない)・残した受け手(`Tape`・`Tensor<f32>`・`Var`)上の、公開していない名前の同名メソッド。
7405/// **検出範囲の限定**: 列挙した名前・型・受け手に限り、マクロ生成や別名経由の公開までは保証しない。
7406/// 公開済み側の正ガード(薄い委譲・シグネチャ・到達性)は `crates/facade/tests/api_surface.rs` が固定する。
7407///
7408/// ソース走査ガード(`crates/facade/tests/api_surface.rs::softmin_threshold_ops_hold_doctest_globs_all_pub_modules`・
7409/// `softmin_threshold_ops_hold_doctest_probe_body_matches_fixed_contract`・
7410/// `facade_does_not_reexport_or_declare_softmin_threshold_ops`・
7411/// `workspace_declares_softmin_threshold_ops_fn_names_only_in_allowed_locations`)との多層防御として働く。
7412///
7413/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
7414/// できること
7415///
7416/// ```
7417/// use fandhe_ai::*;
7418/// use fandhe_ai::compat::*;
7419/// use fandhe_ai::optim::*;
7420/// use fandhe_ai::data::*;
7421/// use fandhe_ai::nn::*;
7422/// use fandhe_ai::nn::init::*;
7423/// use fandhe_ai::nn::rnn::*;
7424/// use fandhe_ai::nn::kv_cache::*;
7425/// use fandhe_ai::nn::loss::*;
7426/// use fandhe_ai::interop::*;
7427/// use fandhe_ai::interop::onnx::*;
7428/// use fandhe_ai::interop::safetensors::*;
7429/// use fandhe_ai::interop::npy::*;
7430/// use fandhe_ai::model::*;
7431/// use fandhe_ai::inference::*;
7432/// use fandhe_ai::text::*;
7433/// use fandhe_ai::models::*;
7434/// use fandhe_ai::distributed::*;
7435///
7436/// mod __fandhe_softmin_threshold_ops_hold_probe {
7437///     pub struct Softmin;
7438///     pub struct Tanhshrink;
7439///     pub struct RRelu;
7440///     pub struct Threshold;
7441///     pub mod softmin_threshold_ops {
7442///         pub fn softmin() {}
7443///         pub fn tanhshrink() {}
7444///         pub fn threshold() {}
7445///         pub fn rrelu() {}
7446///         pub fn rrelu_with_noise() {}
7447///     }
7448///     pub mod softmin_threshold {
7449///         pub fn __mark() {}
7450///     }
7451/// }
7452/// use __fandhe_softmin_threshold_ops_hold_probe::*;
7453///
7454/// struct __FandheSoftminThresholdOpsHoldMarker;
7455///
7456/// trait __FandheSoftminThresholdOpsHoldProbe {
7457///     fn softmin(&self) -> __FandheSoftminThresholdOpsHoldMarker;
7458///     fn tanhshrink(&self) -> __FandheSoftminThresholdOpsHoldMarker;
7459///     fn threshold(&self) -> __FandheSoftminThresholdOpsHoldMarker;
7460///     fn rrelu(&self) -> __FandheSoftminThresholdOpsHoldMarker;
7461///     fn rrelu_with_noise(&self) -> __FandheSoftminThresholdOpsHoldMarker;
7462/// }
7463///
7464/// impl<'t> __FandheSoftminThresholdOpsHoldProbe for fandhe_ai::Var<'t> {
7465///     fn softmin(&self) -> __FandheSoftminThresholdOpsHoldMarker {
7466///         __FandheSoftminThresholdOpsHoldMarker
7467///     }
7468///     fn tanhshrink(&self) -> __FandheSoftminThresholdOpsHoldMarker {
7469///         __FandheSoftminThresholdOpsHoldMarker
7470///     }
7471///     fn threshold(&self) -> __FandheSoftminThresholdOpsHoldMarker {
7472///         __FandheSoftminThresholdOpsHoldMarker
7473///     }
7474///     fn rrelu(&self) -> __FandheSoftminThresholdOpsHoldMarker {
7475///         __FandheSoftminThresholdOpsHoldMarker
7476///     }
7477///     fn rrelu_with_noise(&self) -> __FandheSoftminThresholdOpsHoldMarker {
7478///         __FandheSoftminThresholdOpsHoldMarker
7479///     }
7480/// }
7481///
7482/// impl __FandheSoftminThresholdOpsHoldProbe for fandhe_ai::Tape {
7483///     fn softmin(&self) -> __FandheSoftminThresholdOpsHoldMarker {
7484///         __FandheSoftminThresholdOpsHoldMarker
7485///     }
7486///     fn tanhshrink(&self) -> __FandheSoftminThresholdOpsHoldMarker {
7487///         __FandheSoftminThresholdOpsHoldMarker
7488///     }
7489///     fn threshold(&self) -> __FandheSoftminThresholdOpsHoldMarker {
7490///         __FandheSoftminThresholdOpsHoldMarker
7491///     }
7492///     fn rrelu(&self) -> __FandheSoftminThresholdOpsHoldMarker {
7493///         __FandheSoftminThresholdOpsHoldMarker
7494///     }
7495///     fn rrelu_with_noise(&self) -> __FandheSoftminThresholdOpsHoldMarker {
7496///         __FandheSoftminThresholdOpsHoldMarker
7497///     }
7498/// }
7499///
7500/// impl __FandheSoftminThresholdOpsHoldProbe for fandhe_ai::Tensor<f32> {
7501///     fn softmin(&self) -> __FandheSoftminThresholdOpsHoldMarker {
7502///         __FandheSoftminThresholdOpsHoldMarker
7503///     }
7504///     fn tanhshrink(&self) -> __FandheSoftminThresholdOpsHoldMarker {
7505///         __FandheSoftminThresholdOpsHoldMarker
7506///     }
7507///     fn threshold(&self) -> __FandheSoftminThresholdOpsHoldMarker {
7508///         __FandheSoftminThresholdOpsHoldMarker
7509///     }
7510///     fn rrelu(&self) -> __FandheSoftminThresholdOpsHoldMarker {
7511///         __FandheSoftminThresholdOpsHoldMarker
7512///     }
7513///     fn rrelu_with_noise(&self) -> __FandheSoftminThresholdOpsHoldMarker {
7514///         __FandheSoftminThresholdOpsHoldMarker
7515///     }
7516/// }
7517///
7518/// fn __probe_free_fns(
7519///     _0: Softmin,
7520///     _1: Tanhshrink,
7521///     _2: RRelu,
7522///     _3: Threshold,
7523/// ) {
7524///     // モジュール経由の呼び出し(`use fandhe_ai::*;` が同名モジュールを glob 公開していれば、
7525///     // 名前解決自体が曖昧になり E0659 でコンパイル失敗する)。
7526///     softmin_threshold_ops::softmin();
7527///     softmin_threshold_ops::tanhshrink();
7528///     softmin_threshold_ops::threshold();
7529///     softmin_threshold_ops::rrelu();
7530///     softmin_threshold_ops::rrelu_with_noise();
7531///     softmin_threshold::__mark();
7532/// }
7533///
7534/// fn __probe_methods(
7535///     v: &fandhe_ai::Var<'_>,
7536///     tape: &fandhe_ai::Tape,
7537///     tf: &fandhe_ai::Tensor<f32>,
7538/// ) {
7539///     let _: __FandheSoftminThresholdOpsHoldMarker = fandhe_ai::Var::rrelu_with_noise(v);
7540///     let _: __FandheSoftminThresholdOpsHoldMarker = fandhe_ai::Tape::softmin(tape);
7541///     let _: __FandheSoftminThresholdOpsHoldMarker = fandhe_ai::Tape::tanhshrink(tape);
7542///     let _: __FandheSoftminThresholdOpsHoldMarker = fandhe_ai::Tape::threshold(tape);
7543///     let _: __FandheSoftminThresholdOpsHoldMarker = fandhe_ai::Tape::rrelu(tape);
7544///     let _: __FandheSoftminThresholdOpsHoldMarker = fandhe_ai::Tape::rrelu_with_noise(tape);
7545///     let _: __FandheSoftminThresholdOpsHoldMarker = fandhe_ai::Tensor::<f32>::softmin(tf);
7546///     let _: __FandheSoftminThresholdOpsHoldMarker = fandhe_ai::Tensor::<f32>::tanhshrink(tf);
7547///     let _: __FandheSoftminThresholdOpsHoldMarker = fandhe_ai::Tensor::<f32>::threshold(tf);
7548///     let _: __FandheSoftminThresholdOpsHoldMarker = fandhe_ai::Tensor::<f32>::rrelu(tf);
7549///     let _: __FandheSoftminThresholdOpsHoldMarker = fandhe_ai::Tensor::<f32>::rrelu_with_noise(tf);
7550/// }
7551/// ```
7552#[cfg(doctest)]
7553#[allow(dead_code)]
7554struct SoftminThresholdOpsHoldDoctestGuard;
7555
7556/// pos_weight 付き BCEWithLogits・HingeEmbedding・SoftMargin・GaussianNLL(イシュー #2652・親 #2651)を
7557/// facade 公開面から締め出す保留ガード(`SoftminThresholdOpsHoldDoctestGuard` と同型の正のプローブ 1 ブロック方式)。
7558///
7559/// 下の doctest は全 `pub mod` を glob import したスコープへ、ローカルモジュール `elementwise_loss_ops` と、
7560/// プローブ用トレイトのメソッド(`Tape`/`Tensor<f32>` 向けに 4 名 `bce_with_logits_loss_with`・
7561/// `hinge_embedding_loss`・`soft_margin_loss`・`gaussian_nll_loss`)を置き、モジュール経由の関数呼び出しと
7562/// 修飾付きメソッド呼び出しの両方を行う。facade が同名のモジュールを glob 可能な位置へ公開するか、`Tape`/
7563/// `Tensor<f32>` へ同名の inherent メソッドを公開すると、名前解決の曖昧性または呼び出しシグネチャの不一致で
7564/// エラーコードに依存せずコンパイルが失敗する。検出範囲は列挙したこれらの名前・型に限り、マクロ生成や
7565/// 別名経由のメソッドまでは保証しない。
7566///
7567/// 実装は内部クレートに閉じている(`fandhe_ai_autodiff::elementwise_loss_ops`)。
7568///
7569/// **#2677・#2854 での反転**(ルート #2499 の承認。#2677 は `issuecomment-6033824965`、#2854 は
7570/// `https://github.com/Fandhe-AI/fandhe-ai/issues/2499#issuecomment-6052732061`。形の正は
7571/// `docs/facade-nn-loss-structs-exposure-decision.md` §11・`docs/compat-api-scope.md` §5.1):
7572/// `Var::hinge_embedding_loss`・`Var::soft_margin_loss`(#2677)と `Var::bce_with_logits_loss_with`・
7573/// `Var::gaussian_nll_loss`、オプション型 `BceWithLogitsOptions`・`GaussianNllOptions`(#2854。型は
7574/// `fandhe_ai::nn::loss` 経由のみ)は承認形どおり公開済みのため、`Var` 側のプローブと型のプローブを外した
7575/// (公開済みの型・メソッドと同名のローカル宣言を残すと glob の曖昧性やシグネチャ不一致で本 doctest が
7576/// 壊れるため)。残す保留対象は、モジュール `elementwise_loss_ops` の再エクスポート拒否と、承認していない受け手
7577/// (`Tape`/`Tensor<f32>`)への同名メソッドの配置拒否の 2 点だけである。公開済み側の正ガード(薄い委譲・
7578/// 到達性・オプション型の経路)は `crates/facade/tests/api_surface.rs` が固定する。
7579///
7580/// ソース走査ガード(`crates/facade/tests/api_surface.rs::elementwise_loss_ops_hold_doctest_globs_all_pub_modules`・
7581/// `elementwise_loss_ops_hold_doctest_probe_body_matches_fixed_contract`・
7582/// `facade_does_not_reexport_or_declare_elementwise_loss_ops`・
7583/// `workspace_declares_elementwise_loss_ops_fn_names_only_in_allowed_locations`)との多層防御として働く。
7584///
7585/// モジュール再エクスポートと `Tape`/`Tensor` 上の同名メソッドの承認を得た日が来たら、本構造体・本 doctest
7586/// 自体を削除する(ソース走査側の対応する否定ガードも同時に正ガードへ置き換える)。
7587///
7588/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
7589/// できること
7590///
7591/// ```
7592/// use fandhe_ai::*;
7593/// use fandhe_ai::compat::*;
7594/// use fandhe_ai::optim::*;
7595/// use fandhe_ai::data::*;
7596/// use fandhe_ai::nn::*;
7597/// use fandhe_ai::nn::init::*;
7598/// use fandhe_ai::nn::rnn::*;
7599/// use fandhe_ai::nn::kv_cache::*;
7600/// use fandhe_ai::nn::loss::*;
7601/// use fandhe_ai::interop::*;
7602/// use fandhe_ai::interop::onnx::*;
7603/// use fandhe_ai::interop::safetensors::*;
7604/// use fandhe_ai::interop::npy::*;
7605/// use fandhe_ai::model::*;
7606/// use fandhe_ai::inference::*;
7607/// use fandhe_ai::text::*;
7608/// use fandhe_ai::models::*;
7609/// use fandhe_ai::distributed::*;
7610///
7611/// mod __fandhe_elementwise_loss_ops_hold_probe {
7612///     pub mod elementwise_loss_ops {
7613///         pub fn bce_with_logits_loss_with() {}
7614///         pub fn hinge_embedding_loss() {}
7615///         pub fn soft_margin_loss() {}
7616///         pub fn gaussian_nll_loss() {}
7617///     }
7618/// }
7619/// use __fandhe_elementwise_loss_ops_hold_probe::*;
7620///
7621/// struct __FandheElementwiseLossOpsHoldMarker;
7622///
7623/// trait __FandheElementwiseLossOpsHoldProbe {
7624///     fn bce_with_logits_loss_with(&self) -> __FandheElementwiseLossOpsHoldMarker;
7625///     fn hinge_embedding_loss(&self) -> __FandheElementwiseLossOpsHoldMarker;
7626///     fn soft_margin_loss(&self) -> __FandheElementwiseLossOpsHoldMarker;
7627///     fn gaussian_nll_loss(&self) -> __FandheElementwiseLossOpsHoldMarker;
7628/// }
7629///
7630/// impl __FandheElementwiseLossOpsHoldProbe for fandhe_ai::Tape {
7631///     fn bce_with_logits_loss_with(&self) -> __FandheElementwiseLossOpsHoldMarker {
7632///         __FandheElementwiseLossOpsHoldMarker
7633///     }
7634///     fn hinge_embedding_loss(&self) -> __FandheElementwiseLossOpsHoldMarker {
7635///         __FandheElementwiseLossOpsHoldMarker
7636///     }
7637///     fn soft_margin_loss(&self) -> __FandheElementwiseLossOpsHoldMarker {
7638///         __FandheElementwiseLossOpsHoldMarker
7639///     }
7640///     fn gaussian_nll_loss(&self) -> __FandheElementwiseLossOpsHoldMarker {
7641///         __FandheElementwiseLossOpsHoldMarker
7642///     }
7643/// }
7644///
7645/// impl __FandheElementwiseLossOpsHoldProbe for fandhe_ai::Tensor<f32> {
7646///     fn bce_with_logits_loss_with(&self) -> __FandheElementwiseLossOpsHoldMarker {
7647///         __FandheElementwiseLossOpsHoldMarker
7648///     }
7649///     fn hinge_embedding_loss(&self) -> __FandheElementwiseLossOpsHoldMarker {
7650///         __FandheElementwiseLossOpsHoldMarker
7651///     }
7652///     fn soft_margin_loss(&self) -> __FandheElementwiseLossOpsHoldMarker {
7653///         __FandheElementwiseLossOpsHoldMarker
7654///     }
7655///     fn gaussian_nll_loss(&self) -> __FandheElementwiseLossOpsHoldMarker {
7656///         __FandheElementwiseLossOpsHoldMarker
7657///     }
7658/// }
7659///
7660/// fn __probe_free_fns() {
7661///     // モジュール経由の呼び出し(`use fandhe_ai::*;` が同名モジュールを glob 公開していれば、
7662///     // 名前解決自体が曖昧になり E0659 でコンパイル失敗する)。
7663///     elementwise_loss_ops::bce_with_logits_loss_with();
7664///     elementwise_loss_ops::hinge_embedding_loss();
7665///     elementwise_loss_ops::soft_margin_loss();
7666///     elementwise_loss_ops::gaussian_nll_loss();
7667/// }
7668///
7669/// fn __probe_methods(
7670///     tape: &fandhe_ai::Tape,
7671///     tf: &fandhe_ai::Tensor<f32>,
7672/// ) {
7673///     let _: __FandheElementwiseLossOpsHoldMarker = fandhe_ai::Tape::bce_with_logits_loss_with(tape);
7674///     let _: __FandheElementwiseLossOpsHoldMarker = fandhe_ai::Tape::hinge_embedding_loss(tape);
7675///     let _: __FandheElementwiseLossOpsHoldMarker = fandhe_ai::Tape::soft_margin_loss(tape);
7676///     let _: __FandheElementwiseLossOpsHoldMarker = fandhe_ai::Tape::gaussian_nll_loss(tape);
7677///     let _: __FandheElementwiseLossOpsHoldMarker = fandhe_ai::Tensor::<f32>::bce_with_logits_loss_with(tf);
7678///     let _: __FandheElementwiseLossOpsHoldMarker = fandhe_ai::Tensor::<f32>::hinge_embedding_loss(tf);
7679///     let _: __FandheElementwiseLossOpsHoldMarker = fandhe_ai::Tensor::<f32>::soft_margin_loss(tf);
7680///     let _: __FandheElementwiseLossOpsHoldMarker = fandhe_ai::Tensor::<f32>::gaussian_nll_loss(tf);
7681/// }
7682/// ```
7683#[cfg(doctest)]
7684#[allow(dead_code)]
7685struct ElementwiseLossOpsHoldDoctestGuard;
7686
7687/// MultiMargin・MultiLabelMargin・MultiLabelSoftMargin・sigmoid focal loss(イシュー #2653・親 #2651)を
7688/// facade 公開面から締め出す保留ガード(`SoftminThresholdOpsHoldDoctestGuard` と同型の正のプローブ 1 ブロック方式)。
7689///
7690/// 下の doctest は全 `pub mod` を glob import したスコープへ、ローカルモジュール `margin_focal_loss_ops` と、
7691/// プローブ用トレイトのメソッド(`Tape`/`Tensor<f32>` 向けに 4 名 `multi_margin_loss`・
7692/// `multilabel_margin_loss`・`multilabel_soft_margin_loss`・`sigmoid_focal_loss`)を置き、モジュール経由の
7693/// 関数呼び出しと修飾付きメソッド呼び出しの両方を行う。facade が同名のモジュールを glob 可能な位置へ公開するか、
7694/// `Tape`/`Tensor<f32>` へ同名の inherent メソッドを公開すると、名前解決の曖昧性または呼び出しシグネチャの
7695/// 不一致でエラーコードに依存せずコンパイルが失敗する。検出範囲は列挙したこれらの名前・型に限り、マクロ生成や
7696/// 別名経由のメソッドまでは保証しない。
7697///
7698/// 実装は内部クレートに閉じている(`fandhe_ai_autodiff::margin_focal_loss_ops`)。
7699///
7700/// **#2677・#2854 での反転**(ルート #2499 の承認。#2677 は `issuecomment-6033824965`、#2854 は
7701/// `https://github.com/Fandhe-AI/fandhe-ai/issues/2499#issuecomment-6052732061`。形の正は
7702/// `docs/facade-nn-loss-structs-exposure-decision.md` §11・`docs/compat-api-scope.md` §5.1):
7703/// `Var::multilabel_margin_loss`(#2677)と `Var::multi_margin_loss`・`Var::multilabel_soft_margin_loss`・
7704/// `Var::sigmoid_focal_loss`、オプション型 `MultiMarginOptions`・`MultiLabelSoftMarginOptions`・
7705/// `SigmoidFocalLossOptions`(#2854。型は `fandhe_ai::nn::loss` 経由のみ)は承認形どおり公開済みのため、
7706/// `Var` 側のプローブと型のプローブを外した(公開済みの型・メソッドと同名のローカル宣言を残すと glob の
7707/// 曖昧性やシグネチャ不一致で本 doctest が壊れるため)。残す保留対象は、モジュール `margin_focal_loss_ops` の
7708/// 再エクスポート拒否と、承認していない受け手(`Tape`/`Tensor<f32>`)への同名メソッドの配置拒否の 2 点だけである。
7709/// 公開済み側の正ガード(薄い委譲・到達性・オプション型の経路)は `crates/facade/tests/api_surface.rs` が固定する。
7710///
7711/// ソース走査ガード(`crates/facade/tests/api_surface.rs::margin_focal_loss_ops_hold_doctest_globs_all_pub_modules`・
7712/// `margin_focal_loss_ops_hold_doctest_probe_body_matches_fixed_contract`・
7713/// `facade_does_not_reexport_or_declare_margin_focal_loss_ops`・
7714/// `workspace_declares_margin_focal_loss_ops_fn_names_only_in_allowed_locations`)との多層防御として働く。
7715///
7716/// モジュール再エクスポートと `Tape`/`Tensor` 上の同名メソッドの承認を得た日が来たら、本構造体・本 doctest
7717/// 自体を削除する(ソース走査側の対応する否定ガードも同時に正ガードへ置き換える)。
7718///
7719/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
7720/// できること
7721///
7722/// ```
7723/// use fandhe_ai::*;
7724/// use fandhe_ai::compat::*;
7725/// use fandhe_ai::optim::*;
7726/// use fandhe_ai::data::*;
7727/// use fandhe_ai::nn::*;
7728/// use fandhe_ai::nn::init::*;
7729/// use fandhe_ai::nn::rnn::*;
7730/// use fandhe_ai::nn::kv_cache::*;
7731/// use fandhe_ai::nn::loss::*;
7732/// use fandhe_ai::interop::*;
7733/// use fandhe_ai::interop::onnx::*;
7734/// use fandhe_ai::interop::safetensors::*;
7735/// use fandhe_ai::interop::npy::*;
7736/// use fandhe_ai::model::*;
7737/// use fandhe_ai::inference::*;
7738/// use fandhe_ai::text::*;
7739/// use fandhe_ai::models::*;
7740/// use fandhe_ai::distributed::*;
7741///
7742/// mod __fandhe_margin_focal_loss_ops_hold_probe {
7743///     pub mod margin_focal_loss_ops {
7744///         pub fn multi_margin_loss() {}
7745///         pub fn multilabel_margin_loss() {}
7746///         pub fn multilabel_soft_margin_loss() {}
7747///         pub fn sigmoid_focal_loss() {}
7748///     }
7749/// }
7750/// use __fandhe_margin_focal_loss_ops_hold_probe::*;
7751///
7752/// struct __FandheMarginFocalLossOpsHoldMarker;
7753///
7754/// trait __FandheMarginFocalLossOpsHoldProbe {
7755///     fn multi_margin_loss(&self) -> __FandheMarginFocalLossOpsHoldMarker;
7756///     fn multilabel_margin_loss(&self) -> __FandheMarginFocalLossOpsHoldMarker;
7757///     fn multilabel_soft_margin_loss(&self) -> __FandheMarginFocalLossOpsHoldMarker;
7758///     fn sigmoid_focal_loss(&self) -> __FandheMarginFocalLossOpsHoldMarker;
7759/// }
7760///
7761/// impl __FandheMarginFocalLossOpsHoldProbe for fandhe_ai::Tape {
7762///     fn multi_margin_loss(&self) -> __FandheMarginFocalLossOpsHoldMarker {
7763///         __FandheMarginFocalLossOpsHoldMarker
7764///     }
7765///     fn multilabel_margin_loss(&self) -> __FandheMarginFocalLossOpsHoldMarker {
7766///         __FandheMarginFocalLossOpsHoldMarker
7767///     }
7768///     fn multilabel_soft_margin_loss(&self) -> __FandheMarginFocalLossOpsHoldMarker {
7769///         __FandheMarginFocalLossOpsHoldMarker
7770///     }
7771///     fn sigmoid_focal_loss(&self) -> __FandheMarginFocalLossOpsHoldMarker {
7772///         __FandheMarginFocalLossOpsHoldMarker
7773///     }
7774/// }
7775///
7776/// impl __FandheMarginFocalLossOpsHoldProbe for fandhe_ai::Tensor<f32> {
7777///     fn multi_margin_loss(&self) -> __FandheMarginFocalLossOpsHoldMarker {
7778///         __FandheMarginFocalLossOpsHoldMarker
7779///     }
7780///     fn multilabel_margin_loss(&self) -> __FandheMarginFocalLossOpsHoldMarker {
7781///         __FandheMarginFocalLossOpsHoldMarker
7782///     }
7783///     fn multilabel_soft_margin_loss(&self) -> __FandheMarginFocalLossOpsHoldMarker {
7784///         __FandheMarginFocalLossOpsHoldMarker
7785///     }
7786///     fn sigmoid_focal_loss(&self) -> __FandheMarginFocalLossOpsHoldMarker {
7787///         __FandheMarginFocalLossOpsHoldMarker
7788///     }
7789/// }
7790///
7791/// fn __probe_free_fns() {
7792///     // モジュール経由の呼び出し(`use fandhe_ai::*;` が同名モジュールを glob 公開していれば、
7793///     // 名前解決自体が曖昧になり E0659 でコンパイル失敗する)。
7794///     margin_focal_loss_ops::multi_margin_loss();
7795///     margin_focal_loss_ops::multilabel_margin_loss();
7796///     margin_focal_loss_ops::multilabel_soft_margin_loss();
7797///     margin_focal_loss_ops::sigmoid_focal_loss();
7798/// }
7799///
7800/// fn __probe_methods(
7801///     tape: &fandhe_ai::Tape,
7802///     tf: &fandhe_ai::Tensor<f32>,
7803/// ) {
7804///     let _: __FandheMarginFocalLossOpsHoldMarker = fandhe_ai::Tape::multi_margin_loss(tape);
7805///     let _: __FandheMarginFocalLossOpsHoldMarker = fandhe_ai::Tape::multilabel_margin_loss(tape);
7806///     let _: __FandheMarginFocalLossOpsHoldMarker = fandhe_ai::Tape::multilabel_soft_margin_loss(tape);
7807///     let _: __FandheMarginFocalLossOpsHoldMarker = fandhe_ai::Tape::sigmoid_focal_loss(tape);
7808///     let _: __FandheMarginFocalLossOpsHoldMarker = fandhe_ai::Tensor::<f32>::multi_margin_loss(tf);
7809///     let _: __FandheMarginFocalLossOpsHoldMarker = fandhe_ai::Tensor::<f32>::multilabel_margin_loss(tf);
7810///     let _: __FandheMarginFocalLossOpsHoldMarker = fandhe_ai::Tensor::<f32>::multilabel_soft_margin_loss(tf);
7811///     let _: __FandheMarginFocalLossOpsHoldMarker = fandhe_ai::Tensor::<f32>::sigmoid_focal_loss(tf);
7812/// }
7813/// ```
7814#[cfg(doctest)]
7815#[allow(dead_code)]
7816struct MarginFocalLossOpsHoldDoctestGuard;
7817
7818/// Functional API(多入力・多出力グラフ。`FunctionalBuilder`・`FunctionalModel`・`Node`・
7819/// `FunctionalVars`(学習用の `bind` 結果。#2667)・`save_functional_model`・`load_functional_model`。
7820/// イシュー #2665・#2667・親 #2663・ルート #2499 Phase 4)の保留ガード
7821/// (`PackedSequenceHoldDoctestGuard` と同型の正のプローブ 1 ブロック方式)。
7822///
7823/// イシュー #2679 で承認形(`fandhe_ai::compat` への `FunctionalBuilder`・`FunctionalModel`・`Node`・
7824/// `save_functional_model`・`load_functional_model` の公開。`docs/facade-functional-api-decision.md` §10・§13・
7825/// §16〜§18。承認はルート #2499 のコメント)を公開したため、これら 5 名の衝突プローブは削除した。残すのは
7826/// **未承認の経路**だけである: 学習用の束縛結果型 `FunctionalVars`(§13 項 11 で非公開と承認)・モジュール
7827/// `functional` の公開・`compat::Sequential` 上のメソッド `apply`/`call`(`Sequential` を Functional ノードとして
7828/// 呼ぶ形は承認されていない)。
7829///
7830/// 下の doctest は全 `pub mod` を glob import したスコープへ、ローカルの型 `FunctionalVars`・モジュール
7831/// `functional` と、`compat::Sequential` 上のメソッド `apply`/`call` を持つプローブ用トレイトを置き、
7832/// 修飾なしのモジュール参照と修飾付きメソッド呼び出し(UFCS)の両方を行う。facade が同名のモジュール・型を
7833/// glob 可能な位置へ公開するか、`compat::Sequential` に同名の inherent メソッドを公開すると、名前解決の
7834/// 曖昧性または呼び出しシグネチャの不一致でエラーコードに依存せずコンパイルが失敗する。
7835///
7836/// 検出範囲は本プローブが名前解決で触れる名前と、ソース走査が見るトークン列に限る(マクロ生成や
7837/// 別名経由の公開までは保証しない)。`Sequential` の inherent メソッド名は `apply`/`call` の 2 つに
7838/// 限った契約で、将来の正当な追加(PyTorch `Module.apply` 相当等)と衝突した場合は本ガードを意識的に
7839/// 更新すること。
7840///
7841/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
7842/// functional_api_hold_doctest_globs_all_pub_modules`・
7843/// `functional_api_hold_doctest_probe_body_matches_fixed_contract`・
7844/// `facade_exposes_functional_api_only_in_approved_shape`・
7845/// `workspace_declares_functional_model_io_fn_names_only_in_allowed_location`)との多層防御として働く。
7846///
7847/// 未承認経路が承認される日が来たら、本構造体・本 doctest 自体を削除する。
7848///
7849/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
7850/// できること
7851///
7852/// ```
7853/// use fandhe_ai::*;
7854/// use fandhe_ai::compat::*;
7855/// use fandhe_ai::optim::*;
7856/// use fandhe_ai::data::*;
7857/// use fandhe_ai::nn::*;
7858/// use fandhe_ai::nn::init::*;
7859/// use fandhe_ai::nn::rnn::*;
7860/// use fandhe_ai::nn::kv_cache::*;
7861/// use fandhe_ai::nn::loss::*;
7862/// use fandhe_ai::interop::*;
7863/// use fandhe_ai::interop::onnx::*;
7864/// use fandhe_ai::interop::safetensors::*;
7865/// use fandhe_ai::interop::npy::*;
7866/// use fandhe_ai::model::*;
7867/// use fandhe_ai::inference::*;
7868/// use fandhe_ai::text::*;
7869/// use fandhe_ai::models::*;
7870/// use fandhe_ai::distributed::*;
7871///
7872/// mod __fandhe_functional_api_hold_probe {
7873///     pub struct FunctionalVars;
7874///     pub mod functional {
7875///         pub fn __mark() {}
7876///     }
7877/// }
7878/// use __fandhe_functional_api_hold_probe::*;
7879///
7880/// struct __FandheFunctionalApiHoldMarker;
7881///
7882/// trait __FandheFunctionalApiHoldProbe {
7883///     fn apply(&self) -> __FandheFunctionalApiHoldMarker;
7884///     fn call(&self) -> __FandheFunctionalApiHoldMarker;
7885/// }
7886///
7887/// impl __FandheFunctionalApiHoldProbe for fandhe_ai::compat::Sequential {
7888///     fn apply(&self) -> __FandheFunctionalApiHoldMarker {
7889///         __FandheFunctionalApiHoldMarker
7890///     }
7891///     fn call(&self) -> __FandheFunctionalApiHoldMarker {
7892///         __FandheFunctionalApiHoldMarker
7893///     }
7894/// }
7895///
7896/// fn __probe_types(_0: FunctionalVars) {}
7897///
7898/// fn __probe_module() {
7899///     functional::__mark();
7900/// }
7901///
7902/// fn __probe_methods(seq: &fandhe_ai::compat::Sequential) {
7903///     let _: __FandheFunctionalApiHoldMarker = fandhe_ai::compat::Sequential::apply(seq);
7904///     let _: __FandheFunctionalApiHoldMarker = fandhe_ai::compat::Sequential::call(seq);
7905/// }
7906/// ```
7907#[cfg(doctest)]
7908#[allow(dead_code)]
7909struct FunctionalApiHoldDoctestGuard;
7910
7911/// Functional API の結合 4 演算(`merge_concatenate`・`merge_add`・`merge_multiply`・
7912/// `merge_average`。イシュー #2666・親 #2663・ルート #2499 Phase 4)を facade 公開面から
7913/// 締め出す保留ガード(`TensorProductOpsHoldDoctestGuard` と同型の正のプローブ 1 ブロック方式)。
7914///
7915/// 下の doctest は全 `pub mod` を glob import したスコープへ、ローカルモジュール `merge_ops`・
7916/// 裸の自由関数 4 名・`Var`/`Tape`/`Tensor<f32>` 向けの 7 メソッド(`merge_*` 4 名と
7917/// `concatenate`/`multiply`/`average`)を持つプローブ用トレイト・`compat::Sequential` 向けの
7918/// 4 メソッド(`add_concatenate`/`add_add`/`add_multiply`/`add_average`)を持つプローブ用
7919/// トレイトを置き、モジュール経由と修飾なしの関数呼び出し、および修飾付きメソッド呼び出しの
7920/// 両方を行う。facade が同名のモジュール・関数を glob 可能な位置へ公開するか、これらの型へ
7921/// 同名の inherent メソッドを公開すると、名前解決の曖昧性または呼び出しシグネチャの不一致で
7922/// エラーコードに依存せずコンパイルが失敗する。
7923///
7924/// **検出範囲の限定**: 列挙した名前と型に限る。`add` は既存の承認済み公開 API(`Var::add`)と
7925/// 同名のため対象外(結合の公開形は `FunctionalBuilder::add` として #2679 で型と同時に公開した)。
7926/// マクロ生成・別名経由の公開までは保証しない。
7927///
7928/// 実装は内部クレートと facade 内部に閉じている(`fandhe_ai_autodiff::merge_ops`・
7929/// `compat/functional.rs`。新規 `Op`・`BackendOps` メソッドはない)。**#2679 で承認形
7930/// (`FunctionalBuilder::{concatenate, add, multiply, average}` を型と同時に公開。`docs/facade-functional-api-decision.md`
7931/// §17。承認はルート #2499 のコメント)を公開した。本ガードが固定するのは、承認形に含まれない経路**
7932/// (`merge_ops` モジュール・自由関数の公開、`Var`/`Tape`/`Tensor<f32>` への結合メソッド、
7933/// `Sequential::add_concatenate` 等)の締め出しである。
7934///
7935/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
7936/// merge_ops_hold_doctest_globs_all_pub_modules`・
7937/// `merge_ops_hold_doctest_probe_body_matches_fixed_contract`・
7938/// `facade_does_not_reexport_or_declare_merge_ops`・
7939/// `workspace_declares_merge_ops_fn_names_only_in_allowed_locations`)との多層防御として働く。
7940///
7941/// 承認を得た日が来たら、本構造体・本 doctest 自体を削除する(ソース走査側の対応する否定ガードも
7942/// 同時に正ガードへ置き換える)。
7943///
7944/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
7945/// できること
7946///
7947/// ```
7948/// use fandhe_ai::*;
7949/// use fandhe_ai::compat::*;
7950/// use fandhe_ai::optim::*;
7951/// use fandhe_ai::data::*;
7952/// use fandhe_ai::nn::*;
7953/// use fandhe_ai::nn::init::*;
7954/// use fandhe_ai::nn::rnn::*;
7955/// use fandhe_ai::nn::kv_cache::*;
7956/// use fandhe_ai::nn::loss::*;
7957/// use fandhe_ai::interop::*;
7958/// use fandhe_ai::interop::onnx::*;
7959/// use fandhe_ai::interop::safetensors::*;
7960/// use fandhe_ai::interop::npy::*;
7961/// use fandhe_ai::model::*;
7962/// use fandhe_ai::inference::*;
7963/// use fandhe_ai::text::*;
7964/// use fandhe_ai::models::*;
7965/// use fandhe_ai::distributed::*;
7966///
7967/// mod __fandhe_merge_ops_hold_probe {
7968///     pub mod merge_ops {
7969///         pub fn merge_concatenate() {}
7970///         pub fn merge_add() {}
7971///         pub fn merge_multiply() {}
7972///         pub fn merge_average() {}
7973///     }
7974///     pub fn merge_concatenate() {}
7975///     pub fn merge_add() {}
7976///     pub fn merge_multiply() {}
7977///     pub fn merge_average() {}
7978/// }
7979/// use __fandhe_merge_ops_hold_probe::*;
7980///
7981/// struct __FandheMergeOpsHoldMarker;
7982///
7983/// trait __FandheMergeOpsHoldProbe {
7984///     fn merge_concatenate(&self) -> __FandheMergeOpsHoldMarker;
7985///     fn merge_add(&self) -> __FandheMergeOpsHoldMarker;
7986///     fn merge_multiply(&self) -> __FandheMergeOpsHoldMarker;
7987///     fn merge_average(&self) -> __FandheMergeOpsHoldMarker;
7988///     fn concatenate(&self) -> __FandheMergeOpsHoldMarker;
7989///     fn multiply(&self) -> __FandheMergeOpsHoldMarker;
7990///     fn average(&self) -> __FandheMergeOpsHoldMarker;
7991/// }
7992///
7993/// impl<'t> __FandheMergeOpsHoldProbe for fandhe_ai::Var<'t> {
7994///     fn merge_concatenate(&self) -> __FandheMergeOpsHoldMarker {
7995///         __FandheMergeOpsHoldMarker
7996///     }
7997///     fn merge_add(&self) -> __FandheMergeOpsHoldMarker {
7998///         __FandheMergeOpsHoldMarker
7999///     }
8000///     fn merge_multiply(&self) -> __FandheMergeOpsHoldMarker {
8001///         __FandheMergeOpsHoldMarker
8002///     }
8003///     fn merge_average(&self) -> __FandheMergeOpsHoldMarker {
8004///         __FandheMergeOpsHoldMarker
8005///     }
8006///     fn concatenate(&self) -> __FandheMergeOpsHoldMarker {
8007///         __FandheMergeOpsHoldMarker
8008///     }
8009///     fn multiply(&self) -> __FandheMergeOpsHoldMarker {
8010///         __FandheMergeOpsHoldMarker
8011///     }
8012///     fn average(&self) -> __FandheMergeOpsHoldMarker {
8013///         __FandheMergeOpsHoldMarker
8014///     }
8015/// }
8016///
8017/// impl __FandheMergeOpsHoldProbe for fandhe_ai::Tape {
8018///     fn merge_concatenate(&self) -> __FandheMergeOpsHoldMarker {
8019///         __FandheMergeOpsHoldMarker
8020///     }
8021///     fn merge_add(&self) -> __FandheMergeOpsHoldMarker {
8022///         __FandheMergeOpsHoldMarker
8023///     }
8024///     fn merge_multiply(&self) -> __FandheMergeOpsHoldMarker {
8025///         __FandheMergeOpsHoldMarker
8026///     }
8027///     fn merge_average(&self) -> __FandheMergeOpsHoldMarker {
8028///         __FandheMergeOpsHoldMarker
8029///     }
8030///     fn concatenate(&self) -> __FandheMergeOpsHoldMarker {
8031///         __FandheMergeOpsHoldMarker
8032///     }
8033///     fn multiply(&self) -> __FandheMergeOpsHoldMarker {
8034///         __FandheMergeOpsHoldMarker
8035///     }
8036///     fn average(&self) -> __FandheMergeOpsHoldMarker {
8037///         __FandheMergeOpsHoldMarker
8038///     }
8039/// }
8040///
8041/// impl __FandheMergeOpsHoldProbe for fandhe_ai::Tensor<f32> {
8042///     fn merge_concatenate(&self) -> __FandheMergeOpsHoldMarker {
8043///         __FandheMergeOpsHoldMarker
8044///     }
8045///     fn merge_add(&self) -> __FandheMergeOpsHoldMarker {
8046///         __FandheMergeOpsHoldMarker
8047///     }
8048///     fn merge_multiply(&self) -> __FandheMergeOpsHoldMarker {
8049///         __FandheMergeOpsHoldMarker
8050///     }
8051///     fn merge_average(&self) -> __FandheMergeOpsHoldMarker {
8052///         __FandheMergeOpsHoldMarker
8053///     }
8054///     fn concatenate(&self) -> __FandheMergeOpsHoldMarker {
8055///         __FandheMergeOpsHoldMarker
8056///     }
8057///     fn multiply(&self) -> __FandheMergeOpsHoldMarker {
8058///         __FandheMergeOpsHoldMarker
8059///     }
8060///     fn average(&self) -> __FandheMergeOpsHoldMarker {
8061///         __FandheMergeOpsHoldMarker
8062///     }
8063/// }
8064///
8065/// trait __FandheMergeOpsSequentialHoldProbe {
8066///     fn add_concatenate(&self) -> __FandheMergeOpsHoldMarker;
8067///     fn add_add(&self) -> __FandheMergeOpsHoldMarker;
8068///     fn add_multiply(&self) -> __FandheMergeOpsHoldMarker;
8069///     fn add_average(&self) -> __FandheMergeOpsHoldMarker;
8070/// }
8071///
8072/// impl __FandheMergeOpsSequentialHoldProbe for fandhe_ai::compat::Sequential {
8073///     fn add_concatenate(&self) -> __FandheMergeOpsHoldMarker {
8074///         __FandheMergeOpsHoldMarker
8075///     }
8076///     fn add_add(&self) -> __FandheMergeOpsHoldMarker {
8077///         __FandheMergeOpsHoldMarker
8078///     }
8079///     fn add_multiply(&self) -> __FandheMergeOpsHoldMarker {
8080///         __FandheMergeOpsHoldMarker
8081///     }
8082///     fn add_average(&self) -> __FandheMergeOpsHoldMarker {
8083///         __FandheMergeOpsHoldMarker
8084///     }
8085/// }
8086///
8087/// fn __probe_free_fns() {
8088///     // モジュール経由の呼び出し(`use fandhe_ai::*;` が同名モジュールを glob 公開して
8089///     // いれば、名前解決自体が曖昧になり E0659 でコンパイル失敗する)。
8090///     merge_ops::merge_concatenate();
8091///     merge_ops::merge_add();
8092///     merge_ops::merge_multiply();
8093///     merge_ops::merge_average();
8094///     // 修飾なしの自由関数呼び出し(同名の関数を facade が glob 公開していれば同様に曖昧になる)。
8095///     merge_concatenate();
8096///     merge_add();
8097///     merge_multiply();
8098///     merge_average();
8099/// }
8100///
8101/// fn __probe_methods(
8102///     v: &fandhe_ai::Var<'_>,
8103///     tape: &fandhe_ai::Tape,
8104///     tf: &fandhe_ai::Tensor<f32>,
8105///     seq: &fandhe_ai::compat::Sequential,
8106/// ) {
8107///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Var::merge_concatenate(v);
8108///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Var::merge_add(v);
8109///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Var::merge_multiply(v);
8110///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Var::merge_average(v);
8111///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Var::concatenate(v);
8112///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Var::multiply(v);
8113///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Var::average(v);
8114///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Tape::merge_concatenate(tape);
8115///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Tape::merge_add(tape);
8116///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Tape::merge_multiply(tape);
8117///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Tape::merge_average(tape);
8118///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Tape::concatenate(tape);
8119///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Tape::multiply(tape);
8120///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Tape::average(tape);
8121///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Tensor::<f32>::merge_concatenate(tf);
8122///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Tensor::<f32>::merge_add(tf);
8123///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Tensor::<f32>::merge_multiply(tf);
8124///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Tensor::<f32>::merge_average(tf);
8125///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Tensor::<f32>::concatenate(tf);
8126///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Tensor::<f32>::multiply(tf);
8127///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::Tensor::<f32>::average(tf);
8128///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::compat::Sequential::add_concatenate(seq);
8129///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::compat::Sequential::add_add(seq);
8130///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::compat::Sequential::add_multiply(seq);
8131///     let _: __FandheMergeOpsHoldMarker = fandhe_ai::compat::Sequential::add_average(seq);
8132/// }
8133/// ```
8134#[cfg(doctest)]
8135#[allow(dead_code)]
8136struct MergeOpsHoldDoctestGuard;
8137
8138/// `jacobian`・`hessian`(イシュー #2670・親 #2668。`fandhe_ai_autodiff::jacobian_ops`)のうち未承認の経路を facade 公開面から締め出す保留ガード(`MergeOpsHoldDoctestGuard` と同型の正のプローブ 1 ブロック方式)。
8139///
8140/// 下の doctest は全 `pub mod` を glob import したスコープへ、未承認経路に対応するローカル定義(モジュール `jacobian_ops`、クレートルート直下の裸の自由関数 `jacobian`・`hessian`)と、
8141/// 同名メソッドを持つプローブ用トレイト(受け手: `Tensor<f32>`・`Var`)を置き、修飾なしの関数呼び出しと修飾付き(UFCS)のメソッド呼び出しの両方を行う。
8142/// facade が同名のモジュール・関数・型を glob 可能な位置へ公開するか、上の受け手へ同名の inherent メソッドを公開すると、
8143/// 名前解決の曖昧性または呼び出しシグネチャの不一致でエラーコードに依存せずコンパイルが失敗する(`Tensor` は facade から再エクスポートされるため、`tensor-core` 側への同名メソッド追加も検出する)。
8144///
8145/// **#2678 での部分反転**(ルート #2499 の一括承認 `issuecomment-6033824965`・`docs/compat-api-scope.md` §5.1。
8146/// `VarActivationOpsHoldDoctestGuard` の #2516 部分反転と同型): `Tape::{jacobian,hessian}` は承認形どおり公開済みのため、
8147/// 該当する UFCS 行と、受け手 `Tape` の `impl` ブロックを外した(残すと公開した inherent メソッドや再エクスポート型との衝突でコンパイルが失敗する)。残した受け手の `impl` ブロックは、同じトレイトの別メソッド分のプローブとして維持する。
8148/// 引き続き拒否する未承認経路: モジュール `jacobian_ops`、クレートルート直下の裸の自由関数 `jacobian`・`hessian`・残した受け手(`Tensor<f32>`・`Var`)上の、公開していない名前の同名メソッド。
8149/// **検出範囲の限定**: 列挙した名前・型・受け手に限り、マクロ生成や別名経由の公開までは保証しない。
8150/// 公開済み側の正ガード(薄い委譲・シグネチャ・到達性)は `crates/facade/tests/api_surface.rs` が固定する。
8151///
8152/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
8153/// jacobian_hessian_hold_doctest_globs_all_pub_modules`・
8154/// `jacobian_hessian_hold_doctest_probe_body_matches_fixed_contract`・
8155/// `facade_does_not_reexport_or_declare_jacobian_hessian`・
8156/// `workspace_declares_jacobian_hessian_fn_names_only_in_allowed_locations`)との多層防御として働く。
8157///
8158/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
8159/// できること
8160///
8161/// ```
8162/// use fandhe_ai::*;
8163/// use fandhe_ai::compat::*;
8164/// use fandhe_ai::optim::*;
8165/// use fandhe_ai::data::*;
8166/// use fandhe_ai::nn::*;
8167/// use fandhe_ai::nn::init::*;
8168/// use fandhe_ai::nn::rnn::*;
8169/// use fandhe_ai::nn::kv_cache::*;
8170/// use fandhe_ai::nn::loss::*;
8171/// use fandhe_ai::interop::*;
8172/// use fandhe_ai::interop::onnx::*;
8173/// use fandhe_ai::interop::safetensors::*;
8174/// use fandhe_ai::interop::npy::*;
8175/// use fandhe_ai::model::*;
8176/// use fandhe_ai::inference::*;
8177/// use fandhe_ai::text::*;
8178/// use fandhe_ai::models::*;
8179/// use fandhe_ai::distributed::*;
8180///
8181/// mod __fandhe_jacobian_hessian_hold_probe {
8182///     pub mod jacobian_ops {
8183///         pub fn __mark() {}
8184///     }
8185///     pub fn jacobian() {}
8186///     pub fn hessian() {}
8187/// }
8188/// use __fandhe_jacobian_hessian_hold_probe::*;
8189///
8190/// struct __FandheJacobianHessianHoldMarker;
8191///
8192/// trait __FandheJacobianHessianHoldProbe {
8193///     fn jacobian(&self) -> __FandheJacobianHessianHoldMarker;
8194///     fn hessian(&self) -> __FandheJacobianHessianHoldMarker;
8195/// }
8196///
8197/// impl<'t> __FandheJacobianHessianHoldProbe for fandhe_ai::Var<'t> {
8198///     fn jacobian(&self) -> __FandheJacobianHessianHoldMarker {
8199///         __FandheJacobianHessianHoldMarker
8200///     }
8201///     fn hessian(&self) -> __FandheJacobianHessianHoldMarker {
8202///         __FandheJacobianHessianHoldMarker
8203///     }
8204/// }
8205///
8206/// impl __FandheJacobianHessianHoldProbe for fandhe_ai::Tensor<f32> {
8207///     fn jacobian(&self) -> __FandheJacobianHessianHoldMarker {
8208///         __FandheJacobianHessianHoldMarker
8209///     }
8210///     fn hessian(&self) -> __FandheJacobianHessianHoldMarker {
8211///         __FandheJacobianHessianHoldMarker
8212///     }
8213/// }
8214///
8215/// fn __probe_free_fns() {
8216///     // モジュール経由の呼び出し(`use fandhe_ai::*;` が同名モジュールを glob 公開して
8217///     // いれば、名前解決自体が曖昧になり E0659 でコンパイル失敗する)。
8218///     jacobian_ops::__mark();
8219///     // 修飾なしの自由関数呼び出し(同名の関数を facade が glob 公開していれば同様に曖昧になる)。
8220///     jacobian();
8221///     hessian();
8222/// }
8223///
8224/// fn __probe_methods(
8225///     v: &fandhe_ai::Var<'_>,
8226///     _tape: &fandhe_ai::Tape,
8227///     tf: &fandhe_ai::Tensor<f32>,
8228/// ) {
8229///     let _: __FandheJacobianHessianHoldMarker = fandhe_ai::Var::jacobian(v);
8230///     let _: __FandheJacobianHessianHoldMarker = fandhe_ai::Var::hessian(v);
8231///     let _: __FandheJacobianHessianHoldMarker = fandhe_ai::Tensor::<f32>::jacobian(tf);
8232///     let _: __FandheJacobianHessianHoldMarker = fandhe_ai::Tensor::<f32>::hessian(tf);
8233/// }
8234/// ```
8235#[cfg(doctest)]
8236#[allow(dead_code)]
8237struct JacobianHessianHoldDoctestGuard;
8238
8239/// `gradcheck`・`backward_detect_anomaly`(イシュー #2671・親 #2668。`fandhe_ai_autodiff::gradcheck`/
8240/// `fandhe_ai_autodiff::anomaly`)のうち未承認の経路を facade 公開面から締め出す保留ガード
8241/// (`JacobianHessianHoldDoctestGuard` と同型の正のプローブ 1 ブロック方式)。
8242///
8243/// 下の doctest は全 `pub mod` を glob import したスコープへ、未承認経路に対応するローカル定義(モジュール `gradcheck`・`anomaly`、クレートルート直下の裸の自由関数 `gradcheck`・`backward_detect_anomaly`)と、
8244/// 同名メソッドを持つプローブ用トレイト(受け手: `Tape`・`Tensor<f32>`・`Var`)を置き、修飾なしの関数呼び出しと修飾付き(UFCS)のメソッド呼び出しの両方を行う。
8245/// facade が同名のモジュール・関数・型を glob 可能な位置へ公開するか、上の受け手へ同名の inherent メソッドを公開すると、
8246/// 名前解決の曖昧性または呼び出しシグネチャの不一致でエラーコードに依存せずコンパイルが失敗する(`Tensor` は facade から再エクスポートされるため、`tensor-core` 側への同名メソッド追加も検出する)。
8247///
8248/// **#2678 での部分反転**(ルート #2499 の一括承認 `issuecomment-6033824965`・`docs/compat-api-scope.md` §5.1。
8249/// `VarActivationOpsHoldDoctestGuard` の #2516 部分反転と同型): `Tape::backward_detect_anomaly` は承認形どおり公開済みのため、
8250/// 該当する UFCS 行を外した(残すと公開した inherent メソッドや再エクスポート型との衝突でコンパイルが失敗する)。残した受け手の `impl` ブロックは、同じトレイトの別メソッド分のプローブとして維持する。
8251/// 引き続き拒否する未承認経路: モジュール `gradcheck`・`anomaly`、クレートルート直下の裸の自由関数 `gradcheck`・`backward_detect_anomaly`(公開しない)・`Var`/`Tensor<f32>` 上の同名メソッド・残した受け手(`Tape`・`Tensor<f32>`・`Var`)上の、公開していない名前の同名メソッド。
8252/// **検出範囲の限定**: 列挙した名前・型・受け手に限り、マクロ生成や別名経由の公開までは保証しない。
8253/// 公開済み側の正ガード(薄い委譲・シグネチャ・到達性)は `crates/facade/tests/api_surface.rs` が固定する。
8254///
8255/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
8256/// gradcheck_anomaly_hold_doctest_globs_all_pub_modules`・
8257/// `gradcheck_anomaly_hold_doctest_probe_body_matches_fixed_contract`・
8258/// `facade_does_not_reexport_or_declare_gradcheck_anomaly`・
8259/// `workspace_declares_gradcheck_anomaly_fn_names_only_in_allowed_locations`)との多層防御として働く。
8260///
8261/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
8262/// できること
8263///
8264/// ```
8265/// use fandhe_ai::*;
8266/// use fandhe_ai::compat::*;
8267/// use fandhe_ai::optim::*;
8268/// use fandhe_ai::data::*;
8269/// use fandhe_ai::nn::*;
8270/// use fandhe_ai::nn::init::*;
8271/// use fandhe_ai::nn::rnn::*;
8272/// use fandhe_ai::nn::kv_cache::*;
8273/// use fandhe_ai::nn::loss::*;
8274/// use fandhe_ai::interop::*;
8275/// use fandhe_ai::interop::onnx::*;
8276/// use fandhe_ai::interop::safetensors::*;
8277/// use fandhe_ai::interop::npy::*;
8278/// use fandhe_ai::model::*;
8279/// use fandhe_ai::inference::*;
8280/// use fandhe_ai::text::*;
8281/// use fandhe_ai::models::*;
8282/// use fandhe_ai::distributed::*;
8283///
8284/// mod __fandhe_gradcheck_anomaly_hold_probe {
8285///     pub mod gradcheck {
8286///         pub fn __mark() {}
8287///     }
8288///     pub mod anomaly {
8289///         pub fn __mark() {}
8290///     }
8291///     pub fn gradcheck() {}
8292///     pub fn backward_detect_anomaly() {}
8293/// }
8294/// use __fandhe_gradcheck_anomaly_hold_probe::*;
8295///
8296/// struct __FandheGradcheckAnomalyHoldMarker;
8297///
8298/// trait __FandheGradcheckAnomalyHoldProbe {
8299///     fn gradcheck(&self) -> __FandheGradcheckAnomalyHoldMarker;
8300///     fn backward_detect_anomaly(&self) -> __FandheGradcheckAnomalyHoldMarker;
8301/// }
8302///
8303/// impl<'t> __FandheGradcheckAnomalyHoldProbe for fandhe_ai::Var<'t> {
8304///     fn gradcheck(&self) -> __FandheGradcheckAnomalyHoldMarker {
8305///         __FandheGradcheckAnomalyHoldMarker
8306///     }
8307///     fn backward_detect_anomaly(&self) -> __FandheGradcheckAnomalyHoldMarker {
8308///         __FandheGradcheckAnomalyHoldMarker
8309///     }
8310/// }
8311///
8312/// impl __FandheGradcheckAnomalyHoldProbe for fandhe_ai::Tape {
8313///     fn gradcheck(&self) -> __FandheGradcheckAnomalyHoldMarker {
8314///         __FandheGradcheckAnomalyHoldMarker
8315///     }
8316///     fn backward_detect_anomaly(&self) -> __FandheGradcheckAnomalyHoldMarker {
8317///         __FandheGradcheckAnomalyHoldMarker
8318///     }
8319/// }
8320///
8321/// impl __FandheGradcheckAnomalyHoldProbe for fandhe_ai::Tensor<f32> {
8322///     fn gradcheck(&self) -> __FandheGradcheckAnomalyHoldMarker {
8323///         __FandheGradcheckAnomalyHoldMarker
8324///     }
8325///     fn backward_detect_anomaly(&self) -> __FandheGradcheckAnomalyHoldMarker {
8326///         __FandheGradcheckAnomalyHoldMarker
8327///     }
8328/// }
8329///
8330/// fn __probe_free_fns() {
8331///     // モジュール経由の呼び出し(`use fandhe_ai::*;` が同名モジュールを glob 公開して
8332///     // いれば、名前解決自体が曖昧になり E0659 でコンパイル失敗する)。
8333///     gradcheck::__mark();
8334///     anomaly::__mark();
8335///     // 修飾なしの自由関数呼び出し(同名の関数を facade が glob 公開していれば同様に曖昧になる)。
8336///     gradcheck();
8337///     backward_detect_anomaly();
8338/// }
8339///
8340/// fn __probe_methods(
8341///     v: &fandhe_ai::Var<'_>,
8342///     _tape: &fandhe_ai::Tape,
8343///     tf: &fandhe_ai::Tensor<f32>,
8344/// ) {
8345///     let _: __FandheGradcheckAnomalyHoldMarker = fandhe_ai::Var::gradcheck(v);
8346///     let _: __FandheGradcheckAnomalyHoldMarker = fandhe_ai::Var::backward_detect_anomaly(v);
8347///     let _: __FandheGradcheckAnomalyHoldMarker = fandhe_ai::Tensor::<f32>::gradcheck(tf);
8348///     let _: __FandheGradcheckAnomalyHoldMarker = fandhe_ai::Tensor::<f32>::backward_detect_anomaly(tf);
8349/// }
8350/// ```
8351#[cfg(doctest)]
8352#[allow(dead_code)]
8353struct GradcheckAnomalyHoldDoctestGuard;
8354
8355/// `vjp`・`hvp`・`vmap`(イシュー #2874・親 #2841。内部実装 `fandhe_ai_autodiff::functional_ops`)の
8356/// 未承認経路を facade 公開面から締め出す保留ガード(`GradcheckAnomalyHoldDoctestGuard` と同型の
8357/// 正のプローブ 1 ブロック方式。#2678/#2847 と同じ部分反転の文体)。
8358///
8359/// **部分反転(イシュー #2931)**: 公開形はルート #2499 のリポジトリ所有者コメント
8360/// (`https://github.com/Fandhe-AI/fandhe-ai/issues/2499#issuecomment-6067263650`)の項 1 で承認され、
8361/// `Tape` の inherent メソッド `vjp`・`hvp`・`vmap` の 3 名だけを公開した(決定記録
8362/// `docs/autodiff-functional-transforms-design.md` §23.4)。このため `Tape` 受け手のプローブ
8363/// (`impl ... for fandhe_ai::Tape` と `fandhe_ai::Tape::vjp/hvp/vmap(tape)` の UFCS 3 行)は外した
8364/// (inherent メソッドと名前が衝突して UFCS の解決が変わるため、impl ブロックごと外している)。
8365/// 公開した 3 名の正ガードは `crates/facade/tests/api_surface.rs::
8366/// facade_tape_functional_transforms_are_approved_thin_delegations` が担う。
8367///
8368/// **部分反転(イシュー #2956)**: 同コメントの項 1(`issuecomment-6079384681`)に基づき `Tape` の
8369/// inherent メソッド `jvp`・`jacfwd` の 2 名を追加で公開した(設計記録 §27.1・§28)。このため `Tape`
8370/// 受け手のプローブ用トレイトと impl・UFCS 2 行を外した(#2931 と同じ理由)。正ガードは上と同じ
8371/// `facade_tape_functional_transforms_are_approved_thin_delegations`(承認形 5 名)が担う。
8372///
8373/// **追加の承認公開(イシュー #3063)**: 所有者判断 D-A(2026-10-11)に基づき `Tape` の inherent メソッド
8374/// `jvp_multi` を追加で公開した(設計記録 §30。承認形は計 6 名)。`Tape` 受け手のプローブは足さない
8375/// (承認形と衝突するため)。一方、裸の自由関数・`Var<'t>`・`Tensor<f32>` 上の `jvp_multi` は未承認の
8376/// 受け手として本 doctest のプローブに新規に加えた。
8377///
8378/// **追加の承認公開(イシュー #3068)**: 同じ所有者判断 D-A に基づき `Tape` の inherent メソッド
8379/// `jvp_create_graph`(微分可能な jvp。設計記録 §31。承認形は計 7 名)を追加で公開した。保留ガードに
8380/// 反転対象はなく、`Tape` 受け手のプローブは足さない(承認形と衝突するため)。一方、裸の自由関数・
8381/// `Var<'t>`・`Tensor<f32>` 上の `jvp_create_graph` は未承認の受け手として本 doctest のプローブに新規に加えた。
8382///
8383/// **追加の承認公開(イシュー #3072)**: 同じ所有者判断 D-A に基づき `Tape` の関連関数 `vmap_grad`
8384/// (サンプルごとの勾配。設計記録 §32。承認形は計 8 名)を追加で公開した。保留ガードに反転対象はなく、
8385/// `Tape` 受け手のプローブは足さない(承認形と衝突するため。`&self` を持たない関連関数である点も同じ)。
8386/// 一方、裸の自由関数・`Var<'t>`・`Tensor<f32>` 上の `vmap_grad` は未承認の受け手として本 doctest の
8387/// プローブに新規に加えた。
8388///
8389/// 引き続き拒否する未承認経路: モジュール `functional_ops` の公開、クレートルート直下の裸の自由関数
8390/// `vjp`・`hvp`・`vmap`・`jvp`・`jacfwd`・`jvp_multi`・`jvp_create_graph`・`vmap_grad`、および `Var<'t>`・`Tensor<f32>` 上の同名メソッド。下の doctest は全 `pub mod` を glob import
8391/// したスコープへ、これらに対応するローカル定義とプローブ用トレイトを置き、修飾なしの関数呼び出しと
8392/// 修飾付き(UFCS)のメソッド呼び出しの両方を行う。facade が同名のモジュール・関数を glob 可能な位置へ
8393/// 公開するか、上の受け手へ同名の inherent メソッドを公開すると、名前解決の曖昧性または呼び出しシグネチャの
8394/// 不一致でエラーコードに依存せずコンパイルが失敗する。
8395/// **検出範囲の限定**: 列挙した名前・型・受け手に限り、マクロ生成や別名経由の公開までは保証しない。
8396///
8397/// ソース走査ガード(`crates/facade/tests/api_surface.rs::
8398/// functional_transforms_hold_doctest_globs_all_pub_modules`・
8399/// `functional_transforms_hold_doctest_probe_body_matches_fixed_contract`・
8400/// `facade_does_not_reexport_or_declare_functional_transforms`・
8401/// `workspace_declares_functional_transforms_fn_names_only_in_allowed_locations`)との多層防御として働く。
8402///
8403/// # 正のプローブ: 全 `pub mod` glob import 済みのスコープでコンパイル
8404/// できること
8405///
8406/// ```
8407/// use fandhe_ai::*;
8408/// use fandhe_ai::compat::*;
8409/// use fandhe_ai::optim::*;
8410/// use fandhe_ai::data::*;
8411/// use fandhe_ai::nn::*;
8412/// use fandhe_ai::nn::init::*;
8413/// use fandhe_ai::nn::rnn::*;
8414/// use fandhe_ai::nn::kv_cache::*;
8415/// use fandhe_ai::nn::loss::*;
8416/// use fandhe_ai::interop::*;
8417/// use fandhe_ai::interop::onnx::*;
8418/// use fandhe_ai::interop::safetensors::*;
8419/// use fandhe_ai::interop::npy::*;
8420/// use fandhe_ai::model::*;
8421/// use fandhe_ai::inference::*;
8422/// use fandhe_ai::text::*;
8423/// use fandhe_ai::models::*;
8424/// use fandhe_ai::distributed::*;
8425///
8426/// mod __fandhe_functional_transforms_hold_probe {
8427///     pub mod functional_ops {
8428///         pub fn __mark() {}
8429///     }
8430///     pub fn vjp() {}
8431///     pub fn hvp() {}
8432///     pub fn vmap() {}
8433///     pub fn jvp() {}
8434///     pub fn jacfwd() {}
8435///     pub fn jvp_multi() {}
8436///     pub fn jvp_create_graph() {}
8437///     pub fn vmap_grad() {}
8438/// }
8439/// use __fandhe_functional_transforms_hold_probe::*;
8440///
8441/// struct __FandheFunctionalTransformsHoldMarker;
8442///
8443/// trait __FandheFunctionalTransformsHoldProbe {
8444///     fn vjp(&self) -> __FandheFunctionalTransformsHoldMarker;
8445///     fn hvp(&self) -> __FandheFunctionalTransformsHoldMarker;
8446///     fn vmap(&self) -> __FandheFunctionalTransformsHoldMarker;
8447///     fn jvp(&self) -> __FandheFunctionalTransformsHoldMarker;
8448///     fn jacfwd(&self) -> __FandheFunctionalTransformsHoldMarker;
8449///     fn jvp_multi(&self) -> __FandheFunctionalTransformsHoldMarker;
8450///     fn jvp_create_graph(&self) -> __FandheFunctionalTransformsHoldMarker;
8451///     fn vmap_grad(&self) -> __FandheFunctionalTransformsHoldMarker;
8452/// }
8453///
8454/// impl<'t> __FandheFunctionalTransformsHoldProbe for fandhe_ai::Var<'t> {
8455///     fn vjp(&self) -> __FandheFunctionalTransformsHoldMarker {
8456///         __FandheFunctionalTransformsHoldMarker
8457///     }
8458///     fn hvp(&self) -> __FandheFunctionalTransformsHoldMarker {
8459///         __FandheFunctionalTransformsHoldMarker
8460///     }
8461///     fn vmap(&self) -> __FandheFunctionalTransformsHoldMarker {
8462///         __FandheFunctionalTransformsHoldMarker
8463///     }
8464///     fn jvp(&self) -> __FandheFunctionalTransformsHoldMarker {
8465///         __FandheFunctionalTransformsHoldMarker
8466///     }
8467///     fn jacfwd(&self) -> __FandheFunctionalTransformsHoldMarker {
8468///         __FandheFunctionalTransformsHoldMarker
8469///     }
8470///     fn jvp_multi(&self) -> __FandheFunctionalTransformsHoldMarker {
8471///         __FandheFunctionalTransformsHoldMarker
8472///     }
8473///     fn jvp_create_graph(&self) -> __FandheFunctionalTransformsHoldMarker {
8474///         __FandheFunctionalTransformsHoldMarker
8475///     }
8476///     fn vmap_grad(&self) -> __FandheFunctionalTransformsHoldMarker {
8477///         __FandheFunctionalTransformsHoldMarker
8478///     }
8479/// }
8480///
8481/// impl __FandheFunctionalTransformsHoldProbe for fandhe_ai::Tensor<f32> {
8482///     fn vjp(&self) -> __FandheFunctionalTransformsHoldMarker {
8483///         __FandheFunctionalTransformsHoldMarker
8484///     }
8485///     fn hvp(&self) -> __FandheFunctionalTransformsHoldMarker {
8486///         __FandheFunctionalTransformsHoldMarker
8487///     }
8488///     fn vmap(&self) -> __FandheFunctionalTransformsHoldMarker {
8489///         __FandheFunctionalTransformsHoldMarker
8490///     }
8491///     fn jvp(&self) -> __FandheFunctionalTransformsHoldMarker {
8492///         __FandheFunctionalTransformsHoldMarker
8493///     }
8494///     fn jacfwd(&self) -> __FandheFunctionalTransformsHoldMarker {
8495///         __FandheFunctionalTransformsHoldMarker
8496///     }
8497///     fn jvp_multi(&self) -> __FandheFunctionalTransformsHoldMarker {
8498///         __FandheFunctionalTransformsHoldMarker
8499///     }
8500///     fn jvp_create_graph(&self) -> __FandheFunctionalTransformsHoldMarker {
8501///         __FandheFunctionalTransformsHoldMarker
8502///     }
8503///     fn vmap_grad(&self) -> __FandheFunctionalTransformsHoldMarker {
8504///         __FandheFunctionalTransformsHoldMarker
8505///     }
8506/// }
8507///
8508/// fn __probe_free_fns() {
8509///     // モジュール経由の呼び出し(`use fandhe_ai::*;` が同名モジュールを glob 公開して
8510///     // いれば、名前解決自体が曖昧になり E0659 でコンパイル失敗する)。
8511///     functional_ops::__mark();
8512///     // 修飾なしの自由関数呼び出し(同名の関数を facade が glob 公開していれば同様に曖昧になる)。
8513///     vjp();
8514///     hvp();
8515///     vmap();
8516///     jvp();
8517///     jacfwd();
8518///     jvp_multi();
8519///     jvp_create_graph();
8520///     vmap_grad();
8521/// }
8522///
8523/// fn __probe_methods(
8524///     v: &fandhe_ai::Var<'_>,
8525///     _tape: &fandhe_ai::Tape,
8526///     tf: &fandhe_ai::Tensor<f32>,
8527/// ) {
8528///     let _: __FandheFunctionalTransformsHoldMarker = fandhe_ai::Var::vjp(v);
8529///     let _: __FandheFunctionalTransformsHoldMarker = fandhe_ai::Var::hvp(v);
8530///     let _: __FandheFunctionalTransformsHoldMarker = fandhe_ai::Var::vmap(v);
8531///     let _: __FandheFunctionalTransformsHoldMarker = fandhe_ai::Var::jvp(v);
8532///     let _: __FandheFunctionalTransformsHoldMarker = fandhe_ai::Var::jacfwd(v);
8533///     let _: __FandheFunctionalTransformsHoldMarker = fandhe_ai::Var::jvp_multi(v);
8534///     let _: __FandheFunctionalTransformsHoldMarker = fandhe_ai::Var::jvp_create_graph(v);
8535///     let _: __FandheFunctionalTransformsHoldMarker = fandhe_ai::Var::vmap_grad(v);
8536///     let _: __FandheFunctionalTransformsHoldMarker = fandhe_ai::Tensor::<f32>::vjp(tf);
8537///     let _: __FandheFunctionalTransformsHoldMarker = fandhe_ai::Tensor::<f32>::hvp(tf);
8538///     let _: __FandheFunctionalTransformsHoldMarker = fandhe_ai::Tensor::<f32>::vmap(tf);
8539///     let _: __FandheFunctionalTransformsHoldMarker = fandhe_ai::Tensor::<f32>::jvp(tf);
8540///     let _: __FandheFunctionalTransformsHoldMarker = fandhe_ai::Tensor::<f32>::jacfwd(tf);
8541///     let _: __FandheFunctionalTransformsHoldMarker = fandhe_ai::Tensor::<f32>::jvp_multi(tf);
8542///     let _: __FandheFunctionalTransformsHoldMarker = fandhe_ai::Tensor::<f32>::jvp_create_graph(tf);
8543///     let _: __FandheFunctionalTransformsHoldMarker = fandhe_ai::Tensor::<f32>::vmap_grad(tf);
8544/// }
8545/// ```
8546#[cfg(doctest)]
8547#[allow(dead_code)]
8548struct FunctionalTransformsHoldDoctestGuard;
8549
8550#[cfg(test)]
8551mod tape_ref_tests {
8552    use super::*;
8553
8554    /// `pub(crate)` の `from_autodiff` 経路(統合テストから呼べない)で作った葉が
8555    /// facade `Tape::backward` で勾配を得られること。
8556    #[test]
8557    fn from_autodiff_leaf_receives_gradient() {
8558        let t = tape();
8559        let r = TapeRef::from_autodiff(&t.0);
8560        let x = Tensor::from_slice(&[1.0f32, 2.0, 3.0], &[3]).expect("テスト入力の構築");
8561        let v = r.var(&x);
8562        let loss = v.mul(&v).expect("mul").sum(None).expect("sum");
8563        let g = t.backward(&loss).expect("backward");
8564        assert!(g.get(&v).expect("get").is_some());
8565    }
8566}