Skip to main content

swarm_engine_core/exploration/
map.rs

1//! Exploration Map - 探索マップの抽象層
2//!
3//! 課題空間を「マップ走査」として解くための抽象インターフェース。
4//!
5//! # 設計思想
6//!
7//! - **Tick ベース更新**: `apply(update) -> Result` で状態を確定的に更新
8//! - **Node の抽象化**: 何を Node とするかは実装が決める
9//! - **内部表現の自由**: Graph / Grid / Tree など実装詳細は隠蔽
10//!
11//! # 使用例
12//!
13//! ```ignore
14//! // 課題を Node とするマップ
15//! let mut map = TaskMap::new();
16//!
17//! // Tick ごとに更新を適用
18//! let result = map.apply(update);
19//!
20//! // フロンティアから次の探索対象を取得
21//! for node_id in map.frontiers() {
22//!     let node = map.get(node_id);
23//!     // ...
24//! }
25//! ```
26//!
27//! # 旧 ExplorationSpace からの移行
28//!
29//! 旧 `ExplorationSpace` には以下の機能があったが、クリーンな探索マップ設計では
30//! 多くが不要になる(または別レイヤーの責務となる)。
31//!
32//! ## 新設計で解決済み
33//!
34//! | 旧機能 | 問題点 | 新設計での解決 |
35//! |--------|--------|----------------|
36//! | `NodeKind` (Exploration/ActionNode) | 分岐がコード全体に散らばる | Node 型パラメータ `<N>` で柔軟に |
37//! | 2つの apply API | `apply_update` と `apply_results` 混在 | `apply()` に統一 |
38//! | `ExplorationNode` 固定 | 拡張性がない | `MapNode<T>` で任意データを格納 |
39//!
40//! ## 別レイヤーの責務(マップ外で処理)
41//!
42//! | 旧機能 | 新設計での扱い |
43//! |--------|----------------|
44//! | `DependencyGraph` 統合 | Orchestrator/Strategy 層で注入 |
45//! | `SubRoot` 管理 | 上位レイヤーで課題分解を担当 |
46//! | `NodeSelectionStrategy` | Strategy 層で `frontiers()` を使って実装 |
47//! | `has_successful_action_globally` | 上位レイヤーで履歴管理 |
48//!
49//! ## シンプル化により不要
50//!
51//! | 旧機能 | 理由 |
52//! |--------|------|
53//! | `NodeState` (5状態) | `Open`/`Closed` の2状態で十分。詳細は Node データ `T` で管理 |
54//! | `TrialPolicy` (OneShot/Retriable/Probabilistic) | Node データ `T` でリトライ回数を管理 |
55//! | `ActionCategory` (NodeExpand/NodeStateChange) | Update バリアントで明示 |
56//! | `ExplorationTarget` / `ExplorationUpdate` | `GraphMapUpdate` で統一 |
57//! | `NodeAssignment` (複雑なメタデータ) | シンプルな `MapNodeId` で足りる |
58//!
59//! ## 設計原則
60//!
61//! 1. **マップは純粋なデータ構造**: 戦略やポリシーは外から注入
62//! 2. **Tick ベースの確定的更新**: `apply()` で全ての状態遷移を表現
63//! 3. **Node の抽象化**: 課題/Action/状態など、用途に応じて型で表現
64//! 4. **複雑さは上位レイヤーへ**: DependencyGraph、SubRoot 等は Orchestrator の責務
65
66use std::collections::hash_map::DefaultHasher;
67use std::fmt::Debug;
68use std::hash::{Hash, Hasher};
69
70use serde::{Deserialize, Serialize};
71
72// ============================================================================
73// Core ID Types
74// ============================================================================
75
76/// ノード ID(マップ内で一意)
77#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
78pub struct MapNodeId(pub u64);
79
80impl MapNodeId {
81    pub fn new(id: u64) -> Self {
82        Self(id)
83    }
84}
85
86/// エッジ ID(マップ内で一意)
87#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
88pub struct MapEdgeId(pub u64);
89
90impl MapEdgeId {
91    pub fn new(id: u64) -> Self {
92        Self(id)
93    }
94}
95
96// ============================================================================
97// Error Types
98// ============================================================================
99
100/// マップ操作のエラー
101#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
102pub enum MapError {
103    /// ノードが見つからない
104    #[error("Node not found: {0:?}")]
105    NodeNotFound(MapNodeId),
106
107    /// エッジが見つからない
108    #[error("Edge not found: {0:?}")]
109    EdgeNotFound(MapEdgeId),
110
111    /// ノード ID の衝突
112    #[error("Node ID conflict: {0:?}")]
113    NodeConflict(MapNodeId),
114
115    /// エッジ ID の衝突
116    #[error("Edge ID conflict: {0:?}")]
117    EdgeConflict(MapEdgeId),
118
119    /// 無効な状態遷移
120    #[error("Invalid state transition: {from:?} -> {to:?}")]
121    InvalidStateTransition {
122        node_id: MapNodeId,
123        from: MapNodeState,
124        to: MapNodeState,
125    },
126
127    /// ルートノードが既に存在
128    #[error("Root node already exists: {0:?}")]
129    RootAlreadyExists(MapNodeId),
130
131    /// 親ノードが見つからない
132    #[error("Parent node not found: {0:?}")]
133    ParentNotFound(MapNodeId),
134
135    /// ノードが既に Closed
136    #[error("Node already closed: {0:?}")]
137    AlreadyClosed(MapNodeId),
138}
139
140/// マップ操作の結果型
141pub type MapResult<T> = Result<T, MapError>;
142
143/// 追加操作の結果
144#[derive(Debug, Clone, Copy, PartialEq, Eq)]
145pub enum AddResult<T> {
146    /// 新規追加された
147    Added(T),
148    /// 既に存在していた(既存の値を返す)
149    AlreadyExists(T),
150}
151
152impl<T> AddResult<T> {
153    /// 追加されたかどうか
154    pub fn is_added(&self) -> bool {
155        matches!(self, Self::Added(_))
156    }
157
158    /// 既に存在していたかどうか
159    pub fn is_already_exists(&self) -> bool {
160        matches!(self, Self::AlreadyExists(_))
161    }
162
163    /// 内部の値を取得
164    pub fn into_inner(self) -> T {
165        match self {
166            Self::Added(v) | Self::AlreadyExists(v) => v,
167        }
168    }
169
170    /// 内部の値への参照を取得
171    pub fn as_inner(&self) -> &T {
172        match self {
173            Self::Added(v) | Self::AlreadyExists(v) => v,
174        }
175    }
176}
177
178// ============================================================================
179// Core Trait: ExplorationMap
180// ============================================================================
181
182/// 探索マップの抽象インターフェース
183///
184/// Tick ベースでマップを更新し、探索状態を管理する。
185///
186/// # 型パラメータ
187///
188/// - `Node`: ノードに持たせるデータ(課題 / Action / 状態 など)
189/// - `Edge`: エッジに持たせるデータ(遷移情報など)
190/// - `Update`: Tick 更新の入力型
191/// - `Result`: apply の結果型
192///
193/// # 実装例
194///
195/// - `GraphMap`: グラフ構造のマップ(現在の ExplorationSpace に相当)
196/// - `GridMap`: グリッド構造のマップ
197/// - `TreeMap`: 木構造のマップ
198pub trait ExplorationMap {
199    /// ノードに持たせるデータ型
200    type Node: Debug + Clone;
201
202    /// エッジに持たせるデータ型
203    type Edge: Debug + Clone;
204
205    /// Tick 更新の入力型
206    type Update;
207
208    /// apply の結果型
209    type Result;
210
211    // ========================================================================
212    // Core Tick API
213    // ========================================================================
214
215    /// 更新を適用する(Tick の中心 API)
216    ///
217    /// 毎 Tick でこのメソッドを呼び、マップ状態を更新する。
218    /// 更新は確定的に処理され、結果が返される。
219    fn apply(&mut self, update: Self::Update) -> Self::Result;
220
221    /// 複数の更新をバッチ適用
222    fn apply_batch(&mut self, updates: Vec<Self::Update>) -> Vec<Self::Result> {
223        updates.into_iter().map(|u| self.apply(u)).collect()
224    }
225
226    // ========================================================================
227    // Node API
228    // ========================================================================
229
230    /// ノードを取得
231    fn get(&self, id: MapNodeId) -> Option<&Self::Node>;
232
233    /// ノードを変更可能で取得
234    fn get_mut(&mut self, id: MapNodeId) -> Option<&mut Self::Node>;
235
236    /// ノード数
237    fn node_count(&self) -> usize;
238
239    // ========================================================================
240    // Frontier API
241    // ========================================================================
242
243    /// 現在のフロンティア(Expandable なノード群)を取得
244    ///
245    /// Closed になったノードは含まれない。
246    /// これを「枯渇」「完了」と解釈するかは利用者の責務。
247    fn frontiers(&self) -> Vec<MapNodeId>;
248}
249
250// ============================================================================
251// Extended Traits
252// ============================================================================
253
254/// グラフ構造を持つマップ
255///
256/// ノード間のエッジ関係をクエリ可能。
257pub trait GraphExplorationMap: ExplorationMap {
258    /// エッジを取得
259    fn get_edge(&self, id: MapEdgeId) -> Option<&Self::Edge>;
260
261    /// ノードからの出ていくエッジを取得
262    fn outgoing_edges(&self, node: MapNodeId) -> Vec<MapEdgeId>;
263
264    /// ノードに入ってくるエッジを取得(親エッジ)
265    fn incoming_edge(&self, node: MapNodeId) -> Option<MapEdgeId>;
266
267    /// エッジ数
268    fn edge_count(&self) -> usize;
269
270    /// ルートノードを取得
271    fn root(&self) -> Option<MapNodeId>;
272}
273
274/// 階層構造を持つマップ
275///
276/// 親子関係をクエリ可能。
277pub trait HierarchicalMap: ExplorationMap {
278    /// 親ノードを取得
279    fn parent(&self, node: MapNodeId) -> Option<MapNodeId>;
280
281    /// 子ノード群を取得
282    fn children(&self, node: MapNodeId) -> Vec<MapNodeId>;
283
284    /// ノードの深さを取得
285    fn depth(&self, node: MapNodeId) -> u32;
286}
287
288// ============================================================================
289// Common Update Types
290// ============================================================================
291
292/// 汎用的な更新結果
293#[derive(Debug, Clone, PartialEq, Eq)]
294pub enum MapApplyResult<N> {
295    /// 新しいノードが作成された
296    NodeCreated { node_id: MapNodeId, data: N },
297    /// ノードの状態が更新された
298    NodeUpdated { node_id: MapNodeId },
299    /// ノードが完了としてマークされた
300    NodeCompleted { node_id: MapNodeId },
301    /// ノードが行き止まりとしてマークされた
302    NodeDeadEnd { node_id: MapNodeId },
303    /// 失敗(リトライ可能かどうかを含む)
304    Failed {
305        node_id: MapNodeId,
306        can_retry: bool,
307        reason: String,
308    },
309    /// 無視された(重複や Pending など)
310    Ignored,
311}
312
313// ============================================================================
314// MapState Trait - 状態型の最小制約
315// ============================================================================
316
317/// Map が状態型 S に要求する制約
318///
319/// Map は状態の「意味」を知らない。Map が興味を持つのは2点のみ:
320///
321/// - **Expandable**: 子ノード追加可能(フロンティアとして管理)
322/// - **Closed**: 終了(フロンティアから除外)
323///
324/// 具体的な状態の詳細(Unexplored/Exploring/Explored/DeadEnd/Completed/Processing 等)は
325/// この trait を実装する型で自由に定義できる。Map はそれらを
326/// `is_expandable()` / `is_closed()` で抽象化して扱う。
327///
328/// # 例: カスタム状態型
329///
330/// ```ignore
331/// #[derive(Clone, Debug)]
332/// enum MyState {
333///     Pending,      // → Expandable
334///     Processing,   // → neither (Map は関与しない)
335///     Completed,    // → Closed
336///     Failed,       // → Closed
337/// }
338///
339/// impl MapState for MyState {
340///     fn is_expandable(&self) -> bool {
341///         matches!(self, Self::Pending)
342///     }
343///     fn is_closed(&self) -> bool {
344///         matches!(self, Self::Completed | Self::Failed)
345///     }
346///     fn closed() -> Self {
347///         Self::Completed
348///     }
349/// }
350/// ```
351pub trait MapState: Clone + std::fmt::Debug {
352    /// フロンティアとして展開可能か
353    fn is_expandable(&self) -> bool;
354
355    /// 終了状態か(フロンティアから除外される)
356    fn is_closed(&self) -> bool;
357
358    /// デフォルトの Closed 状態を返す(カスケード操作等で使用)
359    fn closed() -> Self;
360}
361
362// ============================================================================
363// MapNodeState - デフォルトの2状態実装
364// ============================================================================
365
366/// ノードの基本状態
367///
368/// シンプルに Open(探索可能)と Closed(終了)の2状態のみ。
369/// 詳細な状態(成功/失敗/リトライ回数など)は Node のデータ `T` で管理する。
370#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
371pub enum MapNodeState {
372    /// 探索可能(フロンティア)
373    #[default]
374    Open,
375    /// 終了(フロンティアから除外)
376    Closed,
377}
378
379impl MapState for MapNodeState {
380    fn is_expandable(&self) -> bool {
381        matches!(self, Self::Open)
382    }
383
384    fn is_closed(&self) -> bool {
385        matches!(self, Self::Closed)
386    }
387
388    fn closed() -> Self {
389        Self::Closed
390    }
391}
392
393impl MapNodeState {
394    /// フロンティアになりうる状態か
395    pub fn is_open(&self) -> bool {
396        matches!(self, Self::Open)
397    }
398
399    /// 終了状態か
400    pub fn is_closed(&self) -> bool {
401        matches!(self, Self::Closed)
402    }
403}
404
405// ============================================================================
406// Node Wrapper
407// ============================================================================
408
409/// 汎用ノードラッパー
410///
411/// ユーザー定義のデータ `N` と状態 `S` に共通のメタデータを付与する。
412///
413/// # 型パラメータ
414///
415/// - `N`: ノードデータの型
416/// - `S`: 状態の型(MapState を実装)
417#[derive(Debug, Clone, Serialize, Deserialize)]
418pub struct MapNode<N, S: MapState> {
419    /// ノード ID
420    pub id: MapNodeId,
421    /// ユーザー定義データ
422    pub data: N,
423    /// 状態
424    pub state: S,
425    /// 深さ
426    pub depth: u32,
427    /// 親エッジ(ルートは None)
428    pub parent_edge: Option<MapEdgeId>,
429}
430
431impl<N, S: MapState> MapNode<N, S> {
432    pub fn new(id: MapNodeId, data: N, state: S) -> Self {
433        Self {
434            id,
435            data,
436            state,
437            depth: 0,
438            parent_edge: None,
439        }
440    }
441
442    pub fn with_state(mut self, state: S) -> Self {
443        self.state = state;
444        self
445    }
446
447    pub fn with_depth(mut self, depth: u32) -> Self {
448        self.depth = depth;
449        self
450    }
451
452    pub fn with_parent(mut self, edge: MapEdgeId) -> Self {
453        self.parent_edge = Some(edge);
454        self
455    }
456}
457
458// ============================================================================
459// Edge Wrapper
460// ============================================================================
461
462/// 汎用エッジラッパー
463///
464/// ユーザー定義のデータ `T` に共通のメタデータを付与する。
465#[derive(Debug, Clone, Serialize, Deserialize)]
466pub struct MapEdge<T> {
467    /// エッジ ID
468    pub id: MapEdgeId,
469    /// 元ノード
470    pub from: MapNodeId,
471    /// 先ノード(成功時のみ設定)
472    pub to: Option<MapNodeId>,
473    /// ユーザー定義データ
474    pub data: T,
475    /// 試行回数
476    pub attempts: u32,
477    /// 成功したか
478    pub succeeded: bool,
479}
480
481impl<T> MapEdge<T> {
482    pub fn new(id: MapEdgeId, from: MapNodeId, data: T) -> Self {
483        Self {
484            id,
485            from,
486            to: None,
487            data,
488            attempts: 0,
489            succeeded: false,
490        }
491    }
492
493    pub fn mark_success(&mut self, to: MapNodeId) {
494        self.succeeded = true;
495        self.to = Some(to);
496        self.attempts += 1;
497    }
498
499    pub fn mark_failure(&mut self) {
500        self.succeeded = false;
501        self.attempts += 1;
502    }
503}
504
505// ============================================================================
506// GraphMap - グラフ構造のマップ実装
507// ============================================================================
508
509use std::collections::{HashMap, HashSet};
510
511/// グラフベースの探索マップ
512///
513/// ノードとエッジでグラフ構造を表現する。
514/// `ExplorationMap` と `GraphExplorationMap` を実装。
515///
516/// # 型パラメータ
517///
518/// - `N`: ノードデータの型(課題 / Action / 状態 など)
519/// - `E`: エッジデータの型(アクション / 遷移情報 など)
520/// - `S`: 状態の型(MapState を実装)
521///
522/// # 使用例
523///
524/// ```ignore
525/// // 文字列をノードデータとするマップ
526/// let mut map: GraphMap<String, String, MapNodeState> = GraphMap::new();
527///
528/// // ルートノードを作成
529/// let root = map.create_root("start".to_string(), MapNodeState::Open);
530///
531/// // 子ノードを追加
532/// let update = GraphMapUpdate::AddChild {
533///     parent: root,
534///     edge_data: "action-1".to_string(),
535///     node_data: "state-1".to_string(),
536///     node_state: MapNodeState::Open,
537///     dedup_key: "state-1".to_string(),
538/// };
539/// let result = map.apply(update);
540/// ```
541#[derive(Debug, Clone)]
542pub struct GraphMap<N, E, S: MapState> {
543    /// ノード群
544    nodes: HashMap<MapNodeId, MapNode<N, S>>,
545    /// エッジ群
546    edges: HashMap<MapEdgeId, MapEdge<E>>,
547    /// フロンティア(展開可能なノード群)- O(1) 操作のため HashSet
548    expandables: HashSet<MapNodeId>,
549    /// ルートノード
550    root: Option<MapNodeId>,
551    /// 次のノード ID
552    next_node_id: u64,
553    /// 次のエッジ ID
554    next_edge_id: u64,
555    /// ノードインデックス(キーハッシュ → ノードID)
556    /// 重複チェック用。キー抽出関数のハッシュ値でノードを検索可能にする。
557    index: HashMap<u64, MapNodeId>,
558}
559
560impl<N, E, S: MapState> Default for GraphMap<N, E, S> {
561    fn default() -> Self {
562        Self::new()
563    }
564}
565
566impl<N, E, S: MapState> GraphMap<N, E, S> {
567    /// 空のマップを作成
568    pub fn new() -> Self {
569        Self {
570            nodes: HashMap::new(),
571            edges: HashMap::new(),
572            expandables: HashSet::new(),
573            root: None,
574            next_node_id: 0,
575            next_edge_id: 0,
576            index: HashMap::new(),
577        }
578    }
579
580    // ========================================================================
581    // Index API (D)
582    // ========================================================================
583
584    /// キーのハッシュ値を計算
585    fn compute_hash<K: Hash>(key: &K) -> u64 {
586        let mut hasher = DefaultHasher::new();
587        key.hash(&mut hasher);
588        hasher.finish()
589    }
590
591    /// ノードをインデックスに登録
592    ///
593    /// キー抽出関数でキーを取得し、ハッシュ値でインデックスに登録する。
594    pub fn index_node<K, F>(&mut self, node_id: MapNodeId, key_fn: F)
595    where
596        K: Hash,
597        F: FnOnce(&N) -> K,
598    {
599        if let Some(node) = self.nodes.get(&node_id) {
600            let key = key_fn(&node.data);
601            let hash = Self::compute_hash(&key);
602            self.index.insert(hash, node_id);
603        }
604    }
605
606    /// キーでノードを検索
607    ///
608    /// インデックスを使って O(1) で検索。
609    pub fn get_by_key<K: Hash>(&self, key: &K) -> Option<MapNodeId> {
610        let hash = Self::compute_hash(key);
611        self.index.get(&hash).copied()
612    }
613
614    /// キーが存在するか確認
615    pub fn contains_key<K: Hash>(&self, key: &K) -> bool {
616        self.get_by_key(key).is_some()
617    }
618
619    /// インデックスをクリア
620    pub fn clear_index(&mut self) {
621        self.index.clear();
622    }
623
624    /// インデックスを再構築
625    ///
626    /// 全ノードに対してキー抽出関数を適用し、インデックスを再構築する。
627    pub fn rebuild_index<K, F>(&mut self, key_fn: F)
628    where
629        K: Hash,
630        F: Fn(&N) -> K,
631    {
632        self.index.clear();
633        for (&node_id, node) in &self.nodes {
634            let key = key_fn(&node.data);
635            let hash = Self::compute_hash(&key);
636            self.index.insert(hash, node_id);
637        }
638    }
639
640    // ========================================================================
641    // Search API (B)
642    // ========================================================================
643
644    /// 条件に一致する最初のノードを検索
645    ///
646    /// O(n) の線形検索。頻繁に呼ぶ場合はインデックスを使う。
647    pub fn find_node<F>(&self, predicate: F) -> Option<MapNodeId>
648    where
649        F: Fn(&MapNode<N, S>) -> bool,
650    {
651        self.nodes.values().find(|n| predicate(n)).map(|n| n.id)
652    }
653
654    /// 条件に一致する全ノードを検索
655    pub fn find_nodes<F>(&self, predicate: F) -> Vec<MapNodeId>
656    where
657        F: Fn(&MapNode<N, S>) -> bool,
658    {
659        self.nodes
660            .values()
661            .filter(|n| predicate(n))
662            .map(|n| n.id)
663            .collect()
664    }
665
666    /// データで検索(N: PartialEq の場合)
667    pub fn find_by_data(&self, data: &N) -> Option<MapNodeId>
668    where
669        N: PartialEq,
670    {
671        self.nodes.values().find(|n| &n.data == data).map(|n| n.id)
672    }
673
674    /// 状態で検索(S: PartialEq の場合)
675    ///
676    /// 指定した状態のノードを全て返す。
677    /// 利用者が「Completed 状態のノード」「Failed 状態のノード」等を
678    /// 取得するのに使う。
679    pub fn find_by_state(&self, state: &S) -> Vec<MapNodeId>
680    where
681        S: PartialEq,
682    {
683        self.nodes
684            .values()
685            .filter(|n| &n.state == state)
686            .map(|n| n.id)
687            .collect()
688    }
689
690    /// 状態の条件で検索
691    ///
692    /// 状態に対する任意の条件でノードを検索する。
693    pub fn find_nodes_by_state<F>(&self, predicate: F) -> Vec<MapNodeId>
694    where
695        F: Fn(&S) -> bool,
696    {
697        self.nodes
698            .values()
699            .filter(|n| predicate(&n.state))
700            .map(|n| n.id)
701            .collect()
702    }
703
704    // ========================================================================
705    // Add with Dedup API
706    // ========================================================================
707
708    /// 重複チェック付きルートノード作成
709    ///
710    /// キーが既に存在する場合は既存ノードを返す。
711    pub fn create_root_if_absent<K, F>(
712        &mut self,
713        data: N,
714        state: S,
715        key_fn: F,
716    ) -> AddResult<MapNodeId>
717    where
718        K: Hash,
719        F: FnOnce(&N) -> K,
720    {
721        let key = key_fn(&data);
722        let hash = Self::compute_hash(&key);
723
724        if let Some(&existing) = self.index.get(&hash) {
725            return AddResult::AlreadyExists(existing);
726        }
727
728        let id = self.create_root(data, state);
729        self.index.insert(hash, id);
730        AddResult::Added(id)
731    }
732
733    /// 重複チェック付きノード追加(親ノード指定)
734    ///
735    /// キーが既に存在する場合は既存ノードを返す。
736    /// 親ノードが見つからない場合はエラー。
737    pub fn add_child_if_absent<K, F>(
738        &mut self,
739        parent: MapNodeId,
740        edge_data: E,
741        node_data: N,
742        node_state: S,
743        key_fn: F,
744    ) -> MapResult<AddResult<MapNodeId>>
745    where
746        K: Hash,
747        F: FnOnce(&N) -> K,
748    {
749        let key = key_fn(&node_data);
750        let hash = Self::compute_hash(&key);
751
752        if let Some(&existing) = self.index.get(&hash) {
753            return Ok(AddResult::AlreadyExists(existing));
754        }
755
756        // 親ノードの深さを取得
757        let parent_depth = self
758            .nodes
759            .get(&parent)
760            .map(|n| n.depth)
761            .ok_or(MapError::ParentNotFound(parent))?;
762
763        // エッジとノードを作成
764        let edge_id = self.add_edge(parent, edge_data);
765        let id = self.add_node(node_data, node_state, edge_id, parent_depth + 1);
766
767        // エッジの to を設定(親子関係を確立)
768        if let Some(edge) = self.edges.get_mut(&edge_id) {
769            edge.to = Some(id);
770        }
771
772        // インデックスに登録
773        self.index.insert(hash, id);
774
775        Ok(AddResult::Added(id))
776    }
777
778    /// ルートノードを作成
779    pub fn create_root(&mut self, data: N, state: S) -> MapNodeId {
780        let id = self.allocate_node_id();
781        let node = MapNode::new(id, data, state.clone());
782        self.nodes.insert(id, node);
783        if state.is_expandable() {
784            self.expandables.insert(id);
785        }
786        self.root = Some(id);
787        id
788    }
789
790    /// ノードを追加(内部用)
791    fn add_node(&mut self, data: N, state: S, parent_edge: MapEdgeId, depth: u32) -> MapNodeId {
792        let id = self.allocate_node_id();
793        let node = MapNode::new(id, data, state.clone())
794            .with_parent(parent_edge)
795            .with_depth(depth);
796        self.nodes.insert(id, node);
797        if state.is_expandable() {
798            self.expandables.insert(id);
799        }
800        id
801    }
802
803    /// エッジを追加(内部用)
804    fn add_edge(&mut self, from: MapNodeId, data: E) -> MapEdgeId {
805        let id = self.allocate_edge_id();
806        let edge = MapEdge::new(id, from, data);
807        self.edges.insert(id, edge);
808
809        id
810    }
811
812    /// ノード ID を割り当て
813    fn allocate_node_id(&mut self) -> MapNodeId {
814        let id = MapNodeId(self.next_node_id);
815        self.next_node_id += 1;
816        id
817    }
818
819    /// エッジ ID を割り当て
820    fn allocate_edge_id(&mut self) -> MapEdgeId {
821        let id = MapEdgeId(self.next_edge_id);
822        self.next_edge_id += 1;
823        id
824    }
825
826    /// ノードの状態を更新
827    ///
828    /// 状態変更時に expandables インデックスを自動更新する。
829    pub fn set_state(&mut self, id: MapNodeId, state: S) {
830        if let Some(node) = self.nodes.get_mut(&id) {
831            let was_expandable = node.state.is_expandable();
832            node.state = state;
833            let is_expandable = node.state.is_expandable();
834
835            // expandables インデックス更新(O(1))
836            if was_expandable && !is_expandable {
837                self.expandables.remove(&id);
838            } else if !was_expandable && is_expandable {
839                self.expandables.insert(id);
840            }
841        }
842    }
843
844    // ========================================================================
845    // Batch Operations
846    // ========================================================================
847
848    /// 複数ノードを一括追加
849    ///
850    /// 各 (data, state) ペアからノードを作成。
851    /// 最初のノードがルートになり、以降は独立したノードとして追加。
852    pub fn add_nodes(&mut self, nodes: Vec<(N, S)>) -> Vec<MapNodeId> {
853        nodes
854            .into_iter()
855            .map(|(data, state)| {
856                if self.root.is_none() {
857                    self.create_root(data, state)
858                } else {
859                    // ルートが既にある場合は独立ノードとして追加
860                    let id = self.allocate_node_id();
861                    let is_expandable = state.is_expandable();
862                    let node = MapNode::new(id, data, state);
863                    self.nodes.insert(id, node);
864                    if is_expandable {
865                        self.expandables.insert(id);
866                    }
867                    id
868                }
869            })
870            .collect()
871    }
872
873    /// 複数ノードの状態を一括変更
874    pub fn set_states(&mut self, ids: &[MapNodeId], state: S) -> Vec<MapNodeId> {
875        let mut changed = Vec::new();
876        for &id in ids {
877            if self.nodes.contains_key(&id) {
878                self.set_state(id, state.clone());
879                changed.push(id);
880            }
881        }
882        changed
883    }
884
885    /// 複数ノードを一括 Close(S::closed() を使用)
886    ///
887    /// 存在しないノード ID はスキップされる。
888    /// 戻り値は実際に Close されたノード ID のリスト。
889    pub fn close_nodes(&mut self, ids: &[MapNodeId]) -> Vec<MapNodeId> {
890        self.set_states(ids, S::closed())
891    }
892
893    // ========================================================================
894    // Cascade Operations
895    // ========================================================================
896
897    /// 下方向カスケード: 自身と全子孫を Close
898    ///
899    /// 戻り値は Close されたノード ID のリスト(指定ノード含む)。
900    pub fn cascade_down(&mut self, id: MapNodeId) -> Vec<MapNodeId> {
901        let mut closed = Vec::new();
902        self.cascade_down_recursive(id, &mut closed);
903        closed
904    }
905
906    fn cascade_down_recursive(&mut self, id: MapNodeId, closed: &mut Vec<MapNodeId>) {
907        if !self.nodes.contains_key(&id) {
908            return;
909        }
910
911        // 子ノードを先に処理(深さ優先)
912        let children: Vec<MapNodeId> = self.children_internal(id);
913        for child in children {
914            self.cascade_down_recursive(child, closed);
915        }
916
917        // 自身を Close
918        self.set_state(id, S::closed());
919        closed.push(id);
920    }
921
922    /// 子ノード一覧を取得
923    pub fn children(&self, node: MapNodeId) -> Vec<MapNodeId> {
924        self.children_internal(node)
925    }
926
927    /// 子ノード一覧を取得(内部用)
928    fn children_internal(&self, node: MapNodeId) -> Vec<MapNodeId> {
929        self.edges
930            .values()
931            .filter(|e| e.from == node && e.to.is_some())
932            .filter_map(|e| e.to)
933            .collect()
934    }
935
936    /// 上方向カスケード: 全子が is_closed() なら親を Close(再帰)
937    ///
938    /// 戻り値は Close されたノード ID のリスト。
939    pub fn cascade_up_if_all_closed(&mut self, id: MapNodeId) -> Vec<MapNodeId> {
940        let mut closed = Vec::new();
941        self.cascade_up_recursive(id, &mut closed);
942        closed
943    }
944
945    fn cascade_up_recursive(&mut self, id: MapNodeId, closed: &mut Vec<MapNodeId>) {
946        let parent = self.parent_internal(id);
947        if let Some(parent_id) = parent {
948            let all_children_closed = self.children_internal(parent_id).iter().all(|&child| {
949                self.nodes
950                    .get(&child)
951                    .map(|n| n.state.is_closed())
952                    .unwrap_or(true)
953            });
954
955            if all_children_closed {
956                self.set_state(parent_id, S::closed());
957                closed.push(parent_id);
958                self.cascade_up_recursive(parent_id, closed);
959            }
960        }
961    }
962
963    /// 親ノードを取得
964    pub fn parent(&self, node: MapNodeId) -> Option<MapNodeId> {
965        self.parent_internal(node)
966    }
967
968    /// 親ノードを取得(内部用)
969    fn parent_internal(&self, node: MapNodeId) -> Option<MapNodeId> {
970        self.nodes
971            .get(&node)
972            .and_then(|n| n.parent_edge)
973            .and_then(|edge_id| self.edges.get(&edge_id))
974            .map(|e| e.from)
975    }
976
977    /// 状態変更 + 上方向カスケード
978    ///
979    /// ノードを Close した後、親が Close 可能ならカスケード。
980    /// 戻り値は Close されたノード ID のリスト(自身含む)。
981    pub fn close_with_cascade_up(&mut self, id: MapNodeId) -> Vec<MapNodeId> {
982        let mut closed = Vec::new();
983
984        if self.nodes.contains_key(&id) {
985            self.set_state(id, S::closed());
986            closed.push(id);
987            closed.extend(self.cascade_up_if_all_closed(id));
988        }
989
990        closed
991    }
992
993    // ========================================================================
994    // Query Operations
995    // ========================================================================
996
997    /// 複数ノードを一括取得
998    ///
999    /// 存在しない ID はスキップされる。
1000    /// 順序は入力の順序を保持。
1001    pub fn get_nodes(&self, ids: &[MapNodeId]) -> Vec<&MapNode<N, S>> {
1002        ids.iter().filter_map(|id| self.nodes.get(id)).collect()
1003    }
1004
1005    /// 複数ノードのデータを一括取得
1006    ///
1007    /// 存在しない ID はスキップされる。
1008    /// ノード全体ではなくデータ部分のみが必要な場合に使用。
1009    pub fn get_node_data(&self, ids: &[MapNodeId]) -> Vec<&N> {
1010        ids.iter()
1011            .filter_map(|id| self.nodes.get(id).map(|n| &n.data))
1012            .collect()
1013    }
1014
1015    /// 展開可能なノード一覧(= expandables)
1016    pub fn expandables(&self) -> impl Iterator<Item = MapNodeId> + '_ {
1017        self.expandables.iter().copied()
1018    }
1019
1020    /// 展開可能なノード数
1021    pub fn expandables_count(&self) -> usize {
1022        self.expandables.len()
1023    }
1024
1025    /// Closed なノード一覧
1026    pub fn closed_nodes(&self) -> Vec<MapNodeId> {
1027        self.nodes
1028            .values()
1029            .filter(|n| n.state.is_closed())
1030            .map(|n| n.id)
1031            .collect()
1032    }
1033
1034    /// 作業中のノード一覧(!is_expandable && !is_closed)
1035    ///
1036    /// フロンティアでも終了でもない中間状態のノード。
1037    /// 例: Processing, Pending など。
1038    pub fn working_nodes(&self) -> Vec<MapNodeId> {
1039        self.nodes
1040            .values()
1041            .filter(|n| !n.state.is_expandable() && !n.state.is_closed())
1042            .map(|n| n.id)
1043            .collect()
1044    }
1045}
1046
1047// ============================================================================
1048// GraphMap Update Types
1049// ============================================================================
1050
1051/// GraphMap の更新入力
1052#[derive(Debug, Clone)]
1053pub enum GraphMapUpdate<N, E, S: MapState> {
1054    /// 子ノードを追加
1055    AddChild {
1056        /// 親ノード
1057        parent: MapNodeId,
1058        /// エッジデータ
1059        edge_data: E,
1060        /// 新しいノードのデータ
1061        node_data: N,
1062        /// 新しいノードの状態
1063        node_state: S,
1064        /// 重複チェック用キー
1065        dedup_key: String,
1066    },
1067    /// 状態変更
1068    SetState {
1069        /// 対象ノード
1070        node_id: MapNodeId,
1071        /// 新しい状態
1072        state: S,
1073    },
1074    /// 何もしない
1075    Noop,
1076}
1077
1078// ============================================================================
1079// ExplorationMap impl for GraphMap
1080// ============================================================================
1081
1082impl<N, E, S> ExplorationMap for GraphMap<N, E, S>
1083where
1084    N: Debug + Clone,
1085    E: Debug + Clone,
1086    S: MapState,
1087{
1088    type Node = MapNode<N, S>;
1089    type Edge = MapEdge<E>;
1090    type Update = GraphMapUpdate<N, E, S>;
1091    type Result = MapApplyResult<N>;
1092
1093    fn apply(&mut self, update: Self::Update) -> Self::Result {
1094        match update {
1095            GraphMapUpdate::AddChild {
1096                parent,
1097                edge_data,
1098                node_data,
1099                node_state,
1100                dedup_key,
1101            } => {
1102                // 重複チェック
1103                if self.contains_key(&dedup_key) {
1104                    return MapApplyResult::Ignored;
1105                }
1106
1107                // 親ノードが存在するか確認
1108                let parent_depth = match self.nodes.get(&parent) {
1109                    Some(node) => node.depth,
1110                    None => {
1111                        return MapApplyResult::Failed {
1112                            node_id: parent,
1113                            can_retry: false,
1114                            reason: "Parent node not found".to_string(),
1115                        }
1116                    }
1117                };
1118
1119                // エッジを作成
1120                let edge_id = self.add_edge(parent, edge_data);
1121
1122                // 新しいノードを作成
1123                let new_node_id =
1124                    self.add_node(node_data.clone(), node_state, edge_id, parent_depth + 1);
1125
1126                // エッジを成功としてマーク
1127                if let Some(edge) = self.edges.get_mut(&edge_id) {
1128                    edge.mark_success(new_node_id);
1129                }
1130
1131                // インデックスに登録
1132                self.index_node(new_node_id, |_| dedup_key);
1133
1134                MapApplyResult::NodeCreated {
1135                    node_id: new_node_id,
1136                    data: node_data,
1137                }
1138            }
1139
1140            GraphMapUpdate::SetState { node_id, state } => {
1141                self.set_state(node_id, state);
1142                MapApplyResult::NodeUpdated { node_id }
1143            }
1144
1145            GraphMapUpdate::Noop => MapApplyResult::Ignored,
1146        }
1147    }
1148
1149    fn get(&self, id: MapNodeId) -> Option<&Self::Node> {
1150        self.nodes.get(&id)
1151    }
1152
1153    fn get_mut(&mut self, id: MapNodeId) -> Option<&mut Self::Node> {
1154        self.nodes.get_mut(&id)
1155    }
1156
1157    fn node_count(&self) -> usize {
1158        self.nodes.len()
1159    }
1160
1161    fn frontiers(&self) -> Vec<MapNodeId> {
1162        self.expandables.iter().copied().collect()
1163    }
1164}
1165
1166// ============================================================================
1167// GraphExplorationMap impl for GraphMap
1168// ============================================================================
1169
1170impl<N, E, S> GraphExplorationMap for GraphMap<N, E, S>
1171where
1172    N: Debug + Clone,
1173    E: Debug + Clone,
1174    S: MapState,
1175{
1176    fn get_edge(&self, id: MapEdgeId) -> Option<&Self::Edge> {
1177        self.edges.get(&id)
1178    }
1179
1180    fn outgoing_edges(&self, node: MapNodeId) -> Vec<MapEdgeId> {
1181        self.edges
1182            .values()
1183            .filter(|e| e.from == node)
1184            .map(|e| e.id)
1185            .collect()
1186    }
1187
1188    fn incoming_edge(&self, node: MapNodeId) -> Option<MapEdgeId> {
1189        self.nodes.get(&node).and_then(|n| n.parent_edge)
1190    }
1191
1192    fn edge_count(&self) -> usize {
1193        self.edges.len()
1194    }
1195
1196    fn root(&self) -> Option<MapNodeId> {
1197        self.root
1198    }
1199}
1200
1201// ============================================================================
1202// HierarchicalMap impl for GraphMap
1203// ============================================================================
1204
1205impl<N, E, S> HierarchicalMap for GraphMap<N, E, S>
1206where
1207    N: Debug + Clone,
1208    E: Debug + Clone,
1209    S: MapState,
1210{
1211    fn parent(&self, node: MapNodeId) -> Option<MapNodeId> {
1212        self.nodes
1213            .get(&node)
1214            .and_then(|n| n.parent_edge)
1215            .and_then(|edge_id| self.edges.get(&edge_id))
1216            .map(|e| e.from)
1217    }
1218
1219    fn children(&self, node: MapNodeId) -> Vec<MapNodeId> {
1220        self.edges
1221            .values()
1222            .filter(|e| e.from == node && e.to.is_some())
1223            .filter_map(|e| e.to)
1224            .collect()
1225    }
1226
1227    fn depth(&self, node: MapNodeId) -> u32 {
1228        self.nodes.get(&node).map(|n| n.depth).unwrap_or(0)
1229    }
1230}
1231
1232// ============================================================================
1233// Tests
1234// ============================================================================
1235
1236#[cfg(test)]
1237mod tests {
1238    use super::*;
1239
1240    #[test]
1241    fn test_map_node_state() {
1242        assert!(MapNodeState::Open.is_open());
1243        assert!(!MapNodeState::Open.is_closed());
1244        assert!(!MapNodeState::Closed.is_open());
1245        assert!(MapNodeState::Closed.is_closed());
1246    }
1247
1248    #[test]
1249    fn test_map_node_builder() {
1250        // MapNode::new は (id, data, state) の3引数
1251        let node = MapNode::new(MapNodeId(1), "task-1", MapNodeState::Open).with_depth(2);
1252
1253        assert_eq!(node.id, MapNodeId(1));
1254        assert_eq!(node.data, "task-1");
1255        assert_eq!(node.state, MapNodeState::Open);
1256        assert_eq!(node.depth, 2);
1257        assert!(node.parent_edge.is_none()); // ルートなので親エッジなし
1258    }
1259
1260    #[test]
1261    fn test_map_node_with_parent() {
1262        // 親エッジ付きノード
1263        let node = MapNode::new(MapNodeId(2), "child", MapNodeState::Open)
1264            .with_parent(MapEdgeId(0))
1265            .with_depth(1);
1266
1267        assert_eq!(node.depth, 1);
1268        assert_eq!(node.parent_edge, Some(MapEdgeId(0)));
1269    }
1270
1271    #[test]
1272    fn test_map_edge() {
1273        let mut edge = MapEdge::new(MapEdgeId(1), MapNodeId(0), "action-1");
1274        assert!(!edge.succeeded);
1275        assert_eq!(edge.attempts, 0);
1276
1277        edge.mark_success(MapNodeId(1));
1278        assert!(edge.succeeded);
1279        assert_eq!(edge.attempts, 1);
1280        assert_eq!(edge.to, Some(MapNodeId(1)));
1281    }
1282
1283    // ========================================================================
1284    // GraphMap Tests
1285    // ========================================================================
1286
1287    #[test]
1288    fn test_graph_map_create_root() {
1289        // GraphMap<N, E, S> - 3つのジェネリック引数が必要
1290        let mut map: GraphMap<String, String, MapNodeState> = GraphMap::new();
1291        let root = map.create_root("root".to_string(), MapNodeState::Open);
1292
1293        assert_eq!(map.node_count(), 1);
1294        assert_eq!(map.frontiers().len(), 1);
1295        assert_eq!(map.root(), Some(root));
1296
1297        let node = map.get(root).unwrap();
1298        assert_eq!(node.data, "root");
1299        assert_eq!(node.state, MapNodeState::Open);
1300        assert_eq!(node.depth, 0);
1301        assert!(node.parent_edge.is_none()); // ルートは親エッジなし
1302    }
1303
1304    #[test]
1305    fn test_graph_map_create_root_closed() {
1306        // Closed 状態でルートを作成した場合、frontiers には含まれない
1307        let mut map: GraphMap<String, String, MapNodeState> = GraphMap::new();
1308        let root = map.create_root("root".to_string(), MapNodeState::Closed);
1309
1310        assert_eq!(map.node_count(), 1);
1311        assert!(map.frontiers().is_empty()); // Closed なのでフロンティアに含まれない
1312        assert_eq!(map.root(), Some(root));
1313    }
1314
1315    /// AddChild で子ノードが追加されることを検証
1316    ///
1317    /// マップの責務:
1318    /// - 子ノードが作成される
1319    /// - エッジが作成される
1320    /// - 深さが親+1 になる
1321    /// - 親エッジが設定される
1322    /// - 状態に応じて frontiers に含まれる
1323    #[test]
1324    fn test_graph_map_apply_add_child() {
1325        let mut map: GraphMap<String, String, MapNodeState> = GraphMap::new();
1326        let root = map.create_root("root".to_string(), MapNodeState::Open);
1327
1328        // AddChild で子ノードを追加
1329        let update = GraphMapUpdate::AddChild {
1330            parent: root,
1331            edge_data: "action-1".to_string(),
1332            node_data: "child-1".to_string(),
1333            node_state: MapNodeState::Open,
1334            dedup_key: "child-1".to_string(),
1335        };
1336        let result = map.apply(update);
1337
1338        // 結果を確認
1339        match result {
1340            MapApplyResult::NodeCreated { node_id, data } => {
1341                assert_eq!(data, "child-1");
1342
1343                let node = map.get(node_id).unwrap();
1344                assert_eq!(node.depth, 1); // 親の深さ + 1
1345                assert!(node.parent_edge.is_some()); // 親エッジあり
1346                assert_eq!(node.state, MapNodeState::Open);
1347            }
1348            _ => panic!("Expected NodeCreated, got {:?}", result),
1349        }
1350
1351        // マップ状態を確認
1352        assert_eq!(map.node_count(), 2); // root + child
1353        assert_eq!(map.edge_count(), 1); // 1本のエッジ
1354
1355        // 両方 Open なので frontiers に含まれる
1356        assert_eq!(map.frontiers().len(), 2);
1357
1358        // 注意: マップは親を自動的に Close しない
1359        // それは上位レイヤーの責務
1360        let root_node = map.get(root).unwrap();
1361        assert_eq!(root_node.state, MapNodeState::Open);
1362    }
1363
1364    /// 存在しない親に AddChild した場合、Failed が返る
1365    #[test]
1366    fn test_graph_map_add_child_parent_not_found() {
1367        let mut map: GraphMap<String, String, MapNodeState> = GraphMap::new();
1368        // ルートを作らずに、存在しない親を指定
1369
1370        let update = GraphMapUpdate::AddChild {
1371            parent: MapNodeId(999), // 存在しない
1372            edge_data: "action".to_string(),
1373            node_data: "child".to_string(),
1374            node_state: MapNodeState::Open,
1375            dedup_key: "child".to_string(),
1376        };
1377        let result = map.apply(update);
1378
1379        match result {
1380            MapApplyResult::Failed {
1381                node_id, reason, ..
1382            } => {
1383                assert_eq!(node_id, MapNodeId(999));
1384                assert!(reason.contains("not found"));
1385            }
1386            _ => panic!("Expected Failed, got {:?}", result),
1387        }
1388
1389        // ノードもエッジも作成されない
1390        assert_eq!(map.node_count(), 0);
1391        assert_eq!(map.edge_count(), 0);
1392    }
1393
1394    /// 重複キーで AddChild した場合、Ignored が返る
1395    #[test]
1396    fn test_graph_map_add_child_duplicate_key() {
1397        let mut map: GraphMap<String, String, MapNodeState> = GraphMap::new();
1398        let root = map.create_root("root".to_string(), MapNodeState::Open);
1399
1400        // 1回目: 成功
1401        let update1 = GraphMapUpdate::AddChild {
1402            parent: root,
1403            edge_data: "action-1".to_string(),
1404            node_data: "child".to_string(),
1405            node_state: MapNodeState::Open,
1406            dedup_key: "unique-key".to_string(),
1407        };
1408        let result1 = map.apply(update1);
1409        assert!(matches!(result1, MapApplyResult::NodeCreated { .. }));
1410
1411        // 2回目: 同じキーで追加 → Ignored
1412        let update2 = GraphMapUpdate::AddChild {
1413            parent: root,
1414            edge_data: "action-2".to_string(),
1415            node_data: "child-different-data".to_string(), // データは違う
1416            node_state: MapNodeState::Open,
1417            dedup_key: "unique-key".to_string(), // キーが同じ
1418        };
1419        let result2 = map.apply(update2);
1420        assert!(matches!(result2, MapApplyResult::Ignored));
1421
1422        // ノードは2つのまま(root + child)
1423        assert_eq!(map.node_count(), 2);
1424        // エッジも1つのまま
1425        assert_eq!(map.edge_count(), 1);
1426    }
1427
1428    /// SetState で状態が変わり、frontiers が更新されることを検証
1429    ///
1430    /// マップの責務:
1431    /// - 状態が変わる
1432    /// - Open → Closed で frontiers から除外される
1433    /// - Closed → Open で frontiers に追加される
1434    #[test]
1435    fn test_graph_map_apply_set_state() {
1436        let mut map: GraphMap<String, String, MapNodeState> = GraphMap::new();
1437        let root = map.create_root("root".to_string(), MapNodeState::Open);
1438
1439        // 子ノードを追加
1440        let update = GraphMapUpdate::AddChild {
1441            parent: root,
1442            edge_data: "action-1".to_string(),
1443            node_data: "child".to_string(),
1444            node_state: MapNodeState::Open,
1445            dedup_key: "child".to_string(),
1446        };
1447        let child = match map.apply(update) {
1448            MapApplyResult::NodeCreated { node_id, .. } => node_id,
1449            _ => panic!("Expected NodeCreated"),
1450        };
1451
1452        // 初期状態: 両方 Open → frontiers に2つ
1453        assert_eq!(map.frontiers().len(), 2);
1454
1455        // child を Closed に変更
1456        let update = GraphMapUpdate::SetState {
1457            node_id: child,
1458            state: MapNodeState::Closed,
1459        };
1460        let result = map.apply(update);
1461
1462        // 結果確認
1463        assert!(matches!(result, MapApplyResult::NodeUpdated { .. }));
1464
1465        // child は Closed になった
1466        let child_node = map.get(child).unwrap();
1467        assert_eq!(child_node.state, MapNodeState::Closed);
1468
1469        // frontiers から除外された
1470        assert_eq!(map.frontiers().len(), 1);
1471        assert!(map.frontiers().contains(&root));
1472        assert!(!map.frontiers().contains(&child));
1473    }
1474
1475    /// SetState で Closed → Open に戻せることを検証
1476    #[test]
1477    fn test_graph_map_set_state_reopen() {
1478        let mut map: GraphMap<String, String, MapNodeState> = GraphMap::new();
1479        let root = map.create_root("root".to_string(), MapNodeState::Closed);
1480
1481        // 初期状態: Closed → frontiers は空
1482        assert!(map.frontiers().is_empty());
1483
1484        // Open に変更
1485        let update = GraphMapUpdate::SetState {
1486            node_id: root,
1487            state: MapNodeState::Open,
1488        };
1489        map.apply(update);
1490
1491        // frontiers に追加された
1492        assert_eq!(map.frontiers().len(), 1);
1493        assert!(map.frontiers().contains(&root));
1494    }
1495
1496    /// 階層構造(親子関係、深さ)が正しく維持されることを検証
1497    #[test]
1498    fn test_graph_map_hierarchical() {
1499        let mut map: GraphMap<String, String, MapNodeState> = GraphMap::new();
1500        let root = map.create_root("root".to_string(), MapNodeState::Open);
1501
1502        // 2段階のノードを作成: root → node1 → node2
1503        let node1 = match map.apply(GraphMapUpdate::AddChild {
1504            parent: root,
1505            edge_data: "edge-1".to_string(),
1506            node_data: "node-1".to_string(),
1507            node_state: MapNodeState::Open,
1508            dedup_key: "node-1".to_string(),
1509        }) {
1510            MapApplyResult::NodeCreated { node_id, .. } => node_id,
1511            r => panic!("Expected NodeCreated, got {:?}", r),
1512        };
1513
1514        let node2 = match map.apply(GraphMapUpdate::AddChild {
1515            parent: node1,
1516            edge_data: "edge-2".to_string(),
1517            node_data: "node-2".to_string(),
1518            node_state: MapNodeState::Open,
1519            dedup_key: "node-2".to_string(),
1520        }) {
1521            MapApplyResult::NodeCreated { node_id, .. } => node_id,
1522            r => panic!("Expected NodeCreated, got {:?}", r),
1523        };
1524
1525        // 親子関係を確認
1526        assert_eq!(map.parent(node1), Some(root));
1527        assert_eq!(map.parent(node2), Some(node1));
1528        assert_eq!(map.parent(root), None); // ルートは親なし
1529
1530        // 子ノードを確認
1531        assert_eq!(map.children(root), vec![node1]);
1532        assert_eq!(map.children(node1), vec![node2]);
1533        assert!(map.children(node2).is_empty()); // 葉ノード
1534
1535        // 深さを確認
1536        assert_eq!(map.depth(root), 0);
1537        assert_eq!(map.depth(node1), 1);
1538        assert_eq!(map.depth(node2), 2);
1539    }
1540
1541    // ========================================================================
1542    // Search API Tests (B)
1543    // ========================================================================
1544
1545    #[test]
1546    fn test_find_node() {
1547        let mut map: GraphMap<String, String, MapNodeState> = GraphMap::new();
1548        let root = map.create_root("root".to_string(), MapNodeState::Open);
1549
1550        // 子ノードを作成
1551        let target_id = match map.apply(GraphMapUpdate::AddChild {
1552            parent: root,
1553            edge_data: "edge".to_string(),
1554            node_data: "target".to_string(),
1555            node_state: MapNodeState::Open,
1556            dedup_key: "target".to_string(),
1557        }) {
1558            MapApplyResult::NodeCreated { node_id, .. } => node_id,
1559            r => panic!("Expected NodeCreated, got {:?}", r),
1560        };
1561
1562        // 条件で検索
1563        let found = map.find_node(|n| n.data == "target");
1564        assert_eq!(found, Some(target_id));
1565
1566        // 存在しないものは None
1567        let not_found = map.find_node(|n| n.data == "nonexistent");
1568        assert!(not_found.is_none());
1569    }
1570
1571    #[test]
1572    fn test_find_nodes() {
1573        let mut map: GraphMap<String, String, MapNodeState> = GraphMap::new();
1574        let root = map.create_root("root".to_string(), MapNodeState::Open);
1575
1576        // 複数ノードを作成
1577        let id1 = match map.apply(GraphMapUpdate::AddChild {
1578            parent: root,
1579            edge_data: "edge-1".to_string(),
1580            node_data: "match-1".to_string(),
1581            node_state: MapNodeState::Open,
1582            dedup_key: "match-1".to_string(),
1583        }) {
1584            MapApplyResult::NodeCreated { node_id, .. } => node_id,
1585            r => panic!("Expected NodeCreated, got {:?}", r),
1586        };
1587
1588        let id2 = match map.apply(GraphMapUpdate::AddChild {
1589            parent: id1,
1590            edge_data: "edge-2".to_string(),
1591            node_data: "match-2".to_string(),
1592            node_state: MapNodeState::Open,
1593            dedup_key: "match-2".to_string(),
1594        }) {
1595            MapApplyResult::NodeCreated { node_id, .. } => node_id,
1596            r => panic!("Expected NodeCreated, got {:?}", r),
1597        };
1598
1599        // "match" で始まるものを検索
1600        let found = map.find_nodes(|n| n.data.starts_with("match"));
1601        assert_eq!(found.len(), 2);
1602        assert!(found.contains(&id1));
1603        assert!(found.contains(&id2));
1604    }
1605
1606    #[test]
1607    fn test_find_by_data() {
1608        let mut map: GraphMap<String, String, MapNodeState> = GraphMap::new();
1609        let root = map.create_root("root".to_string(), MapNodeState::Open);
1610
1611        let found = map.find_by_data(&"root".to_string());
1612        assert_eq!(found, Some(root));
1613
1614        let not_found = map.find_by_data(&"nonexistent".to_string());
1615        assert!(not_found.is_none());
1616    }
1617
1618    // ========================================================================
1619    // Index API Tests (D)
1620    // ========================================================================
1621
1622    #[test]
1623    fn test_index_basic() {
1624        let mut map: GraphMap<String, String, MapNodeState> = GraphMap::new();
1625        let root = map.create_root("file:auth.rs".to_string(), MapNodeState::Open);
1626
1627        // インデックスに登録
1628        map.index_node(root, |data| data.clone());
1629
1630        // キーで検索
1631        let found = map.get_by_key(&"file:auth.rs".to_string());
1632        assert_eq!(found, Some(root));
1633
1634        // 存在しないキー
1635        let not_found = map.get_by_key(&"file:other.rs".to_string());
1636        assert!(not_found.is_none());
1637    }
1638
1639    #[test]
1640    fn test_contains_key() {
1641        let mut map: GraphMap<String, String, MapNodeState> = GraphMap::new();
1642        let root = map.create_root("task-1".to_string(), MapNodeState::Open);
1643        map.index_node(root, |data| data.clone());
1644
1645        assert!(map.contains_key(&"task-1".to_string()));
1646        assert!(!map.contains_key(&"task-2".to_string()));
1647    }
1648
1649    #[test]
1650    fn test_rebuild_index() {
1651        let mut map: GraphMap<String, String, MapNodeState> = GraphMap::new();
1652        let root = map.create_root("root".to_string(), MapNodeState::Open);
1653
1654        let child = match map.apply(GraphMapUpdate::AddChild {
1655            parent: root,
1656            edge_data: "edge".to_string(),
1657            node_data: "child".to_string(),
1658            node_state: MapNodeState::Open,
1659            dedup_key: "child".to_string(),
1660        }) {
1661            MapApplyResult::NodeCreated { node_id, .. } => node_id,
1662            r => panic!("Expected NodeCreated, got {:?}", r),
1663        };
1664
1665        // インデックスを再構築
1666        map.rebuild_index(|data| data.clone());
1667
1668        // 両方検索できる
1669        assert_eq!(map.get_by_key(&"root".to_string()), Some(root));
1670        assert_eq!(map.get_by_key(&"child".to_string()), Some(child));
1671    }
1672
1673    // ========================================================================
1674    // Add with Dedup Tests
1675    // ========================================================================
1676
1677    #[test]
1678    fn test_create_root_if_absent() {
1679        let mut map: GraphMap<String, String, MapNodeState> = GraphMap::new();
1680
1681        // 最初の追加
1682        let result1 =
1683            map.create_root_if_absent("task-1".to_string(), MapNodeState::Open, |d| d.clone());
1684        assert!(result1.is_added());
1685        let id1 = result1.into_inner();
1686
1687        // 同じキーで追加しようとすると AlreadyExists
1688        let result2 =
1689            map.create_root_if_absent("task-1".to_string(), MapNodeState::Open, |d| d.clone());
1690        assert!(result2.is_already_exists());
1691        assert_eq!(result2.into_inner(), id1);
1692
1693        // 違うキーは追加できる
1694        let result3 =
1695            map.create_root_if_absent("task-2".to_string(), MapNodeState::Open, |d| d.clone());
1696        assert!(result3.is_added());
1697        assert_ne!(result3.into_inner(), id1);
1698    }
1699
1700    #[test]
1701    fn test_add_child_if_absent() {
1702        let mut map: GraphMap<String, String, MapNodeState> = GraphMap::new();
1703        let root = map
1704            .create_root_if_absent("root".to_string(), MapNodeState::Open, |d| d.clone())
1705            .into_inner();
1706
1707        // 子ノードを追加
1708        let result1 = map
1709            .add_child_if_absent(
1710                root,
1711                "edge-1".to_string(),
1712                "child-1".to_string(),
1713                MapNodeState::Open,
1714                |d| d.clone(),
1715            )
1716            .unwrap();
1717        assert!(result1.is_added());
1718        let child1 = result1.into_inner();
1719
1720        // 同じキーで追加しようとすると AlreadyExists
1721        let result2 = map
1722            .add_child_if_absent(
1723                root,
1724                "edge-2".to_string(),
1725                "child-1".to_string(),
1726                MapNodeState::Open,
1727                |d| d.clone(),
1728            )
1729            .unwrap();
1730        assert!(result2.is_already_exists());
1731        assert_eq!(result2.into_inner(), child1);
1732
1733        // 違うキーは追加できる
1734        let result3 = map
1735            .add_child_if_absent(
1736                root,
1737                "edge-3".to_string(),
1738                "child-2".to_string(),
1739                MapNodeState::Open,
1740                |d| d.clone(),
1741            )
1742            .unwrap();
1743        assert!(result3.is_added());
1744    }
1745
1746    #[test]
1747    fn test_add_child_if_absent_parent_not_found() {
1748        let mut map: GraphMap<String, String, MapNodeState> = GraphMap::new();
1749
1750        // 存在しない親に追加しようとするとエラー
1751        let result = map.add_child_if_absent(
1752            MapNodeId(999),
1753            "edge".to_string(),
1754            "child".to_string(),
1755            MapNodeState::Open,
1756            |d| d.clone(),
1757        );
1758        assert!(result.is_err());
1759        assert!(matches!(result.unwrap_err(), MapError::ParentNotFound(_)));
1760    }
1761
1762    #[test]
1763    fn test_dedup_prevents_infinite_loop() {
1764        // シナリオ: Grep で同じファイルが繰り返し発見される
1765        let mut map: GraphMap<String, String, MapNodeState> = GraphMap::new();
1766        let root = map
1767            .create_root_if_absent("search:auth".to_string(), MapNodeState::Open, |d| d.clone())
1768            .into_inner();
1769
1770        // Worker A: auth.rs を発見
1771        let result_a = map.add_child_if_absent(
1772            root,
1773            "grep".to_string(),
1774            "file:auth.rs".to_string(),
1775            MapNodeState::Open,
1776            |d| d.clone(),
1777        );
1778        assert!(result_a.unwrap().is_added());
1779
1780        // Worker B: 同じ auth.rs を発見(重複追加されない)
1781        let result_b = map.add_child_if_absent(
1782            root,
1783            "grep".to_string(),
1784            "file:auth.rs".to_string(),
1785            MapNodeState::Open,
1786            |d| d.clone(),
1787        );
1788        assert!(result_b.unwrap().is_already_exists());
1789
1790        // Worker C: 別のファイル user.rs を発見
1791        let result_c = map.add_child_if_absent(
1792            root,
1793            "grep".to_string(),
1794            "file:user.rs".to_string(),
1795            MapNodeState::Open,
1796            |d| d.clone(),
1797        );
1798        assert!(result_c.unwrap().is_added());
1799
1800        // ノード数は 3 (root + auth.rs + user.rs)
1801        assert_eq!(map.node_count(), 3);
1802    }
1803
1804    #[test]
1805    fn test_add_result_methods() {
1806        let added: AddResult<i32> = AddResult::Added(42);
1807        assert!(added.is_added());
1808        assert!(!added.is_already_exists());
1809        assert_eq!(*added.as_inner(), 42);
1810        assert_eq!(added.into_inner(), 42);
1811
1812        let exists: AddResult<i32> = AddResult::AlreadyExists(42);
1813        assert!(!exists.is_added());
1814        assert!(exists.is_already_exists());
1815        assert_eq!(*exists.as_inner(), 42);
1816        assert_eq!(exists.into_inner(), 42);
1817    }
1818}