集合論の基礎
目的
このページでは、Reactive Entity Setsの数学的基礎を説明します。これらの概念を理解することで、RESがなぜそのように動作するのかについてより深い洞察が得られ、Viewなどの高度な機能への準備ができます。
数学的集合としてのReactiveEntitySet
ReactiveEntitySetは、各要素が(Entity ID, Data)のペアである数学的集合Sとして理解できます。
S = { (id₁, data₁), (id₂, data₂), ..., (idₙ, dataₙ) }
主要な性質
| 性質 | 説明 |
|---|---|
| 一意性 | 各エンティティIDは最大1回のみ出現 |
| 所属 | エンティティは集合に属するか属さないか(部分的な所属はない) |
| データ関連付け | 各メンバーは正確に1つの関連データ値を持つ |
演算と閉包
閉包性
集合族Sは、演算Oを適用してもS内の別の集合が生成される場合、演算Oに対して閉じていると言います。
∀O ∈ Operations, ∀S ∈ S: O(S) ∈ S
この性質により、ReactiveEntitySetへの演算は予測可能で明確に定義された結果を生成します。
ReactiveEntitySetの演算
| 演算 | 入力 | 出力 | 閉包を維持 |
|---|---|---|---|
| Register | S, (id, data) | S ∪ {(id, data)} | はい |
| Unregister | S, id | S \ {(id, _)} | はい |
| SetData | S, id, data’ | 更新されたデータを持つS | はい |
| Filter (View) | S, 述語 | S’ ⊆ S | はい |
すべての演算は閉包を維持します。結果は常に有効なReactiveEntitySet(またはそのサブセット)です。
View理論
Viewは述語によって定義されるReactiveEntitySetのサブセットです。2つの基本的なタイプがあります。
flowchart TB
subgraph Parent["ReactiveEntitySet S"]
direction TB
E1["(id:1, HP:80)"]
E2["(id:2, HP:25)"]
E3["(id:3, HP:100)"]
E4["(id:4, HP:15)"]
end
subgraph Static["静的View R(c₀)"]
direction TB
S1["固定述語: HP < 30"]
S2["id:2, id:4"]
end
subgraph Dynamic["動的View R(c₁)"]
direction TB
D1["コンテキスト付き述語"]
D2["P(data, ctx)"]
end
Parent --> Static
Parent --> Dynamic
style Static fill:#e6f3ff
style Dynamic fill:#fff3e6
静的View R(c₀)
静的ビューはエンティティデータのみに依存します。
R(c₀) = { (id, data) ∈ S | P(data) = true }
ここでPは述語関数: P: TData → bool
例
// 体力が30未満のすべての敵
var lowHealthView = enemies.CreateView(state => state.Health < 30);
特徴
- 述語は作成時に固定されます
- エンティティデータが変更されるとView所属が自動更新されます
- 外部コンテキストは不要です
動的View R(c₁)
動的ビューはエンティティデータと外部コンテキストの両方に依存します。
R(c₁) = { (id, data) ∈ S | P(data, context) = true }
ここでPは述語関数: P: (TData, TContext) → bool
例(概念)
動的/コンテキスト依存のViewは将来拡張であり、現時点では未実装です。概念としては次のようなイメージになります。
// 指定位置から10ユニット以内のすべての敵
// (予定API)
特徴
- 述語の評価にコンテキストが必要です
- エンティティデータの変更は自動再評価をトリガーします
- コンテキストの変更には明示的な再評価が必要です
Viewの「Reactive」
R(c₀)とR(c₁)の両方は、エンティティ状態の変更に対してReactiveです。
エンティティ状態変更 → 述語評価 → View所属更新 → 通知
違いはリアクティビティについてではなく、述語が外部コンテキストを必要とするかどうかです。
構造的閉包
定義
構造的閉包は、Viewへの演算が親集合に「逃げ出す」ことができないことを保証します。
View V = σ[P](S)
VはSのサブセットとして決定論的に定義
Vへの演算はV内に留まる
V外の要素にアクセスする経路は存在しない
安全なAPI設計
この原則がAPI設計を導きます。
var view = enemies.CreateView(state => state.Health < 30);
// ✅ View内へのアクセス
view.EntityIds
view.Count
view.ForEach(...)
// ❌ 親集合への逆流なし(APIが提供されない)
// view.ParentSet ← これは存在すべきでない
親集合への経路を公開しないことで、Viewで操作するコードがスコープ外のエンティティに誤ってアクセスすることを防ぎます。
パフォーマンスへの影響
従来のアプローチ
クエリ → すべてのエンティティを走査 → フィルタ → 結果
コスト: クエリあたりO(n)
Reactive Viewアプローチ
エンティティ状態変更
→ viewの述語を評価
→ viewから追加/削除
→ サブスクライバーに通知
コスト: 変更あたりO(v)、ここでv = viewの数
形式的定義
厳密な数学的定式化に興味がある方のための定義です。
ReactiveEntitySet
ReactiveEntitySet<TData> = (S, Σ, δ, notify)
ここで:
S: (id, data)ペアの集合
Σ: 演算の集合 {Register, Unregister, SetData}
δ: S × Σ → S (遷移関数)
notify: S × Σ → Events (通知関数)
静的View R(c₀)
R(c₀) = σ[P](S) = { e ∈ S | P(e.data) }
ここで:
P: TData → bool (述語)
σ: 選択演算子
動的View R(c₁)
R(c₁)(ctx) = σ[P(_, ctx)](S) = { e ∈ S | P(e.data, ctx) }
ここで:
P: (TData, TContext) → bool (パラメータ化された述語)
ctx: TContext (評価コンテキスト)
まとめ
| 概念 | 説明 |
|---|---|
| 集合意味論 | RESは一意のIDを持つ数学的集合 |
| 閉包 | すべての演算が有効な集合を生成 |
| 静的View R(c₀) | データのみでフィルタ |
| 動的View R(c₁) | データ + コンテキストでフィルタ |
| Reactive性 | エンティティ変更時にViewが自動更新 |
| 構造的閉包 | Viewは親集合に逃げ出せない |
実装状況
Viewはv2.2.0(未リリース)で実装済みです。
次のステップ
- Reactive Entity Setsガイド - 実装の詳細
- 設計アプローチ - ハイレベルな思想を確認