rabukasim / docs /plans /bytecode_extension_analysis.md
trioskosmos's picture
chore: remove large files for HF Space
9bd4ce5
# バイトコード拡張案の分析: 5x32 vs 64bit vs 現状維持
## 概要
ユーザーからの技術的異議を受けて、3つのアプローチを比較検討します:
1. **現状維持 (4x32)**: `[op, v, a, s]` - 4整数 x 32ビット
2. **5x32拡張**: `[op, v, s, a_low, a_high]` - 5整数 x 32ビット
3. **64bit拡張**: `[op, v, a64, s]` - aのみ64ビット
---
## 1. ユーザーの懸念点 (正当性の評価)
### 1.1 `v` への Color Filter 移動の問題
| 懸念 | 評価 | 理由 |
|-----|------|------|
| Card ID > 65535 での破損 | ✅ **正当** | プロモカード等で ID が 70050+ になる可能性あり |
| AI学習の複雑化 | ✅ **正当** | 「opcode が X の場合は v から色を探す」という条件分岐は NN に負担 |
### 1.2 Assembly-Style Unrolling の問題
| 懸念 | 評価 | 理由 |
|-----|------|------|
| MCTS深度爆発 | ✅ **正当** | 1効果 = 3-4ステップ は状態空間を不必要に拡大 |
| 部分状態の探索 | ✅ **正当** | 「フィルタ済みだが選択未完了」の中間状態が増加 |
### 1.3 拡張性の欠如
| 懸念 | 評価 | 理由 |
|-----|------|------|
| 将来のメカニクス対応 | ✅ **正当** | 学年フィルタ、ブレードサイズ等の新規フィルタで即座に限界 |
---
## 2. パフォーマンス影響の分析
### 2.1 Rust での影響
#### 現状 (4x32)
```rust
// bytecode: Vec<i32>
for chunk in bytecode.chunks(4) {
let (op, v, a, s) = (chunk[0], chunk[1], chunk[2], chunk[3]);
// 処理
}
```
#### 5x32拡張
```rust
// bytecode: Vec<i32>
for chunk in bytecode.chunks(5) {
let (op, v, s, a_low, a_high) = (chunk[0], chunk[1], chunk[2], chunk[3], chunk[4]);
let a = ((a_high as u64) << 32) | (a_low as u64);
// 処理
}
```
**影響**:
- メモリ: **+25%** 増加
- キャッシュミス率: 若干増加 (1命令あたり 20bytes → 25bytes)
- CPUサイクル: ほぼ変わらず (ビットシフトは高速)
#### 64bit拡張
```rust
// bytecode: Vec<i64> または混合型
for chunk in bytecode.chunks(4) {
let (op, v, a, s) = (chunk[0] as i32, chunk[1] as i32, chunk[2], chunk[3] as i32);
// a は i64
}
```
**影響**:
- メモリ: **+25%** 増加 (4x32=128bit → 2x32+1x64+1x32=160bit)
- キャッシュミス率: 若干増加
- CPUサイクル: ほぼ変わらず (64bit演算は現代CPUで高速)
### 2.2 WGSL (GPU) での影響
#### 現状 (4x32)
```wgsl
@group(0) @binding(2) var<storage, read> bytecode: array<i32>;
fn get_instruction(ip: u32) -> vec4<i32> {
return vec4<i32>(
bytecode[ip],
bytecode[ip + 1u],
bytecode[ip + 2u],
bytecode[ip + 3u]
);
}
```
#### 5x32拡張
```wgsl
@group(0) @binding(2) var<storage, read> bytecode: array<i32>;
fn get_instruction(ip: u32) -> vec5<i32> { // vec5 は存在しない!
// WGSL には vec5 がないため、個別にロードが必要
let op = bytecode[ip];
let v = bytecode[ip + 1u];
let s = bytecode[ip + 2u];
let a_lo = bytecode[ip + 3u];
let a_hi = bytecode[ip + 4u];
let a = (u32(a_lo) | (u32(a_hi) << 32u)); // u64 として結合
// ...
}
```
**影響**:
- **重大**: WGSL に `vec5` が存在しないため、個別ロードが必要
- メモリアクセス: 5回/命令 (現状は4回)
- レジスタ圧力: 若干増加
#### 64bit拡張
```wgsl
@group(0) @binding(2) var<storage, read> bytecode: array<i64>; // または混合
fn get_instruction(ip: u32) -> vec4<i64> { // 一部が i64
// WGSL は型統一が必要
return vec4<i64>(
bytecode[ip],
bytecode[ip + 1u],
bytecode[ip + 2u],
bytecode[ip + 3u]
);
}
```
**影響**:
- WGSL は `array<i64>` をサポート
- ただし、`op`, `v`, `s` も 64bit になるためメモリ無駄
- 混合型は WGSL で複雑化
---
## 3. 推奨アプローチ: 5x32 拡張
### 3.1 理由
| 基準 | 4x32 (現状) | 5x32 | 64bit |
|-----|-------------|------|-------|
| メモリ効率 | ✅ 最良 | 🟡 +25% | 🟡 +25% |
| WGSL互換性 | ✅ 最良 | 🟡 個別ロード必要 | 🟡 型統一必要 |
| 拡張性 | ❌ 不十分 | ✅ 64bit属性 | ✅ 64bit属性 |
| AI学習 | ❌ 複雑な条件 | ✅ クリーン | ✅ クリーン |
| 実装コスト | - | 🟡 中程度 | 🔴 高い |
### 3.2 新しいレイアウト (5x32)
```
[op, v, s, a_low, a_high]
op (i32): Opcode
v (i32): Value/Count (16bit) + Color Mask (6bit) + Flags (10bit)
s (i32): Slot/Zone (24bit) + Flags (8bit)
a (i64): Attribute Filter (64bit完全使用可能)
```
### 3.3 64bit `a` ワードの新しいレイアウト
```
┌─────────────────────────────────────────────────────────────────┐
│ Bit 0 : IS_OPTIONAL │
│ Bit 1 : DYNAMIC_VALUE │
│ Bits 2-3 : Card Type (0=Any, 1=Member, 2=Live) │
│ Bits 4-7 : Group ID (4 bits = 16 groups) │
│ Bits 8-12 : Unit ID (5 bits = 32 units) │
│ Bits 13-17 : Cost Threshold (5 bits = 0-31) │
│ Bit 18 : Cost Mode (0=GE, 1=LE) │
│ Bit 19 : Tapped Filter │
│ Bit 20 : Has Blade Heart │
│ Bit 21 : Not Has Blade Heart │
│ Bits 22-28 : Color Mask (7 bits = 7 colors) │
│ Bits 29-35 : Character ID 1 (7 bits = 128 chars) │
│ Bits 36-42 : Character ID 2 (7 bits) │
│ Bits 43-49 : Character ID 3 (7 bits) │
│ Bits 50-56 : Special Filter ID (7 bits) │
│ Bits 57-63 : Reserved for future use │
└─────────────────────────────────────────────────────────────────┘
```
**改善点**:
- Color Mask が `a` 内に配置 (v から分離)
- Character ID が 64bit 内に収まる (切り捨て問題解決)
- 将来の拡張用に 7ビット予備
---
## 4. 実装ステップ
### Phase 1: Rust インタープリタの更新
1. **バイトコードストレージの変更**
```rust
// Before
pub bytecode: Vec<i32>
// After
pub bytecode: Vec<i32> // 5要素ごとに1命令
```
2. **チャンク処理の変更**
```rust
// Before
for chunk in bytecode.chunks(4) { ... }
// After
for chunk in bytecode.chunks(5) {
let op = chunk[0];
let v = chunk[1];
let s = chunk[2];
let a = if chunk.len() >= 5 {
((chunk[4] as u64) << 32) | (chunk[3] as u64)
} else { 0 };
// ...
}
```
### Phase 2: Python コンパイラの更新
1. **`compile()` メソッドの変更**
```python
def compile(self) -> List[int]:
bytecode = []
# ... 既存のロジック ...
# 各命令に a_high を追加
for i in range(0, len(bytecode), 4):
a = bytecode[i+2]
a_low = a & 0xFFFFFFFF
a_high = (a >> 32) & 0xFFFFFFFF
bytecode[i+2] = a_low
bytecode.insert(i+3, a_high)
return bytecode
```
### Phase 3: WGSL シェーダーの更新
1. **命令読み込みの変更**
```wgsl
fn get_instruction(ip: u32) -> (i32, i32, i32, u64) {
let op = bytecode[ip];
let v = bytecode[ip + 1u];
let s = bytecode[ip + 2u];
let a_lo = bytecode[ip + 3u];
let a_hi = bytecode[ip + 4u];
let a = (u32(a_lo) | (u32(a_hi) << 32u));
return (op, v, s, a);
}
```
---
## 5. パフォーマンス予測
### 5.1 メモリ使用量
| 項目 | 現状 (4x32) | 5x32 | 増加率 |
|-----|-------------|------|-------|
| 1命令あたり | 16 bytes | 20 bytes | +25% |
| 全カードのバイトコード | ~1.5 MB | ~1.9 MB | +25% |
| GPU VRAM | ~2 MB | ~2.5 MB | +25% |
### 5.2 実行速度
| 環境 | 予測影響 |
|-----|---------|
| Rust (CPU) | < 1% 遅延 (メモリ帯域幅依存) |
| WGSL (GPU) | 1-3% 遅延 (メモリアクセス増加) |
| AI訓練 | **改善** (状態空間の削減) |
### 5.3 AI訓練への影響
| 側面 | 影響 |
|-----|------|
| 状態空間 | **削減** (Unrolling回避) |
| MCTS深度 | **削減** (1効果 = 1ステップ) |
| NN入力エンコーディング | **簡素化** (レジスタ意味が明確) |
---
## 6. 結論
**推奨**: 5x32 拡張アプローチ
**理由**:
1. 64bit 属性フィルタで全ての情報を1命令に収容
2. AI訓練にとって最適 (状態空間削減)
3. 実装コストが中程度
4. 将来の拡張性を確保
**次のステップ**:
1. ユーザーの承認
2. Codeモードでの実装開始