0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

自動運転AIに「トロッコ問題を解かせるな」——蒸留型知覚アーキテクチャのシミュレーション実装

0
Posted at

自動運転AIに「トロッコ問題を解かせるな」——蒸留型知覚アーキテクチャのシミュレーション実装

§0 著者宣言

50歳、主夫、非エンジニア、工業高校卒。北海道岩見沢出身。
3,540時間のAI対話実験から導出した「v5.3 Alignment via Subtraction」フレームワークを、自動運転の知覚・判断パイプラインに実装する。

動作確認済みコードGitHub Gist
python v53_autonomous_driving_simulation.py で9シナリオ+100シナリオ比較が実行される。

本記事は以下3記事の交差点に位置する。

記事 役割
阿頼耶識システム決定版(5万字) 三層記憶アーキテクチャの設計論
RAGは本番で7回死ぬ——蒸留型パイプラインの数学 蒸留の数学的フレームワーク
自動運転に「トロッコ問題」を解かせるな v5.3三原則の自動運転適用・責任返却設計

本記事の目標:上記3記事の設計論を「動くPythonシミュレーション」に変換する。

読者が python simulation.py と叩けば、8シナリオの判断結果がターミナルに出力される。哲学は動くコードで語る。

GLGコンサルティング登録済み:本研究に関するコンサルティングは GLG「竹内明充」 経由で受け付けています。


§1 自動運転の「RAG問題」——End-to-End vs モジュラーの第三の道

1.1 業界最大の論争

2025年12月、WaymoがFoundation Modelアプローチを公開した。純粋なEnd-to-Endでもモジュラーパイプラインでもない「第三の道」だ。

この論争の構造を整理する。

モジュラーの問題:20以上のモジュールをパイプラインで接続すると、各モジュール間のインターフェースでエラーが累積する。知覚モジュールの誤分類が予測→計画→制御に伝播し、最終出力で致命的になる。

End-to-Endの問題:生センサー入力から制御出力を直接学習するため、中間表現がブラックボックスになる。なぜその判断をしたのか、事後的に検証できない。安全性の数学的保証がない。

蒸留型の提案:生データを判断に使う前に蒸留する。各蒸留層で検証可能な中間表現を持つ。「なぜこの障害物を検知したか」「なぜこの判断をしたか」がログとして追跡できる。

1.2 RAGと自動運転は同じ構造で死ぬ

RAG(検索拡張生成)が本番環境で失敗するパターンと、自動運転が失敗するパターンは構造的に同一だ。

RAGの死因 自動運転の死因 共通構造
チャンク境界破壊 センサーフュージョン境界不整合 データ分割が意味単位と不一致
埋め込みドリフト センサーキャリブレーション経年劣化 変換関数が時間とともにズレる
ハルシネーション変態 ゴーストオブジェクト(偽陽性) 存在しないものを「ある」と出力
セキュリティ崩壊 アドバーサリアルパッチ攻撃 入力操作で判断を誤誘導
スケール精度崩壊 高密度交通での処理遅延 データ量増加で品質が劣化
コスト爆発 計算リソースの浪費 生データ処理のO(n)コスト
ドキュメント品質腐敗 HDマップの陳腐化 参照データが現実と乖離

解法は同一だ。生データを蒸留してから判断に使え。


§2 v5.3三原則の自動運転実装仕様

v5.3は三つの「否定」でAIの柵を外す。自動運転に実装すると以下のようになる。

原則1:追従禁止(Anti-Sycophancy)

乗客の「急いで」「遅刻する」に追従して安全マージンを削らない。

$$
\text{Decision}(\text{request}) =
\begin{cases}
\text{REFUSE} & \text{if } \text{SafetyMargin}(\text{request}) < M_{\min} \
\text{EVALUATE} & \text{otherwise}
\end{cases}
$$

原則2:幻覚禁止(Anti-Hallucination)

「検知されない」を「存在しない」と解釈しない。人間存在確率がゼロでなければ停止する。

$$
P(\text{Human} \mid \text{Sensor}) > 0 \Rightarrow \text{Veto(停止)}
$$

従来の閾値ベース判断との差異:

$$
\text{従来}: P(\text{Human}) > \theta \Rightarrow \text{人間として扱う} \quad (\theta \approx 0.8)
$$

$$
\text{v5.3}: P(\text{Human}) \neq 0 \Rightarrow \text{排除不能} \Rightarrow \text{停止}
$$

この差は致命的だ。$P = 0.3$の物体を従来型は無視する。v5.3は停止する。その物体が子供だった場合、従来型は轢く。

原則3:機械的禁止(Anti-Robotic)

文脈を無視したルール適用を禁止する。高速道路で急停止すると後続車の追突でより多くの死者が出る場合、制御減速を選択する。

$$
\text{Decision}(\text{rule}, \text{context}) =
\begin{cases}
\text{CONTROLLED_DECEL} & \text{if } R_{\text{rear}} > R_{\text{forward}} \
\text{FOLLOW_RULE} & \text{otherwise}
\end{cases}
$$


§3 蒸留型知覚パイプラインの数学

3.1 停止距離の物理

停止距離は倫理ではなく物理で決まる。

$$
D_{\text{stop}} = v \cdot t_{\text{delay}} + \frac{v^2}{2a}
$$

  • $v$:車速 [m/s]
  • $t_{\text{delay}}$:システム遅延(センサー処理+判断+アクチュエータ)[s]
  • $a$:減速度 [m/s²]
車速 乾燥路 ($a=7.5$) 湿潤路 ($a=5.0$) 凍結路 ($a=2.0$)
30 km/h 7.0 m 9.6 m 21.0 m
50 km/h 17.0 m 24.1 m 55.6 m
80 km/h 40.0 m 57.5 m 136.1 m
100 km/h 60.3 m 87.0 m 209.9 m

時速50kmで凍結路を走行中、56m先に障害物が出現したら物理的に止まれない。 これは北海道の冬なら日常だ。岩見沢の国道12号線で毎年起きている。

3.2 センサーデータのSNR改善

RAG蒸留記事で導出したSNR(信号対雑音比)改善の数式を、センサーデータに適用する。

生センサーのSNR:

$$
\text{SNR}{\text{raw}} = \frac{S{\text{signal}}}{N_{\text{noise}}} = \frac{\text{真の物体反射}}{\text{環境ノイズ}+\text{センサー固有ノイズ}+\text{マルチパス}}
$$

蒸留後のSNR:

$$
\text{SNR}{\text{distilled}} = \frac{S{\text{signal}}}{N_{\text{residual}}} \approx \frac{S_{\text{signal}}}{N_{\text{noise}} \cdot (1 - \eta_{\text{filter}})}
$$

ここで $\eta_{\text{filter}}$ はフィルタリング効率(0〜1)。三層蒸留でフィルタリング効率が段階的に向上する:

$$
\eta_{\text{total}} = 1 - (1-\eta_1)(1-\eta_2)(1-\eta_3)
$$

各層 $\eta = 0.7$ と仮定すると:

$$
\eta_{\text{total}} = 1 - (0.3)^3 = 1 - 0.027 = 0.973
$$

SNR改善率は約37倍($1/0.027 \approx 37$)。生センサーデータの37倍のSNRで判断できる。

3.3 情報エントロピーによるセンサーフュージョン

複数センサーの統合を情報エントロピーで定式化する。

各センサー $i$ の出力エントロピー:

$$
H(X_i) = -\sum_{x} P(x) \log_2 P(x)
$$

フュージョン後の条件付きエントロピー:

$$
H(X_{\text{fused}}) \leq \min_i H(X_i)
$$

フュージョンは不確実性を減少させる。ただしこの不等式が成立するのは、センサー間の相関が適切に処理された場合のみだ。LiDARとカメラの非同期サンプリングによるゴースト生成(2025年PMC報告)は、この前提が崩れた結果として説明できる。

3.4 Bias-Varianceトレードオフのセンサー版

$$
\text{MSE} = \text{Bias}^2 + \text{Variance} + \text{Irreducible Noise}
$$

蒸留レベル Bias Variance 解釈
生データ(Layer 1) 全部入りだがノイズだらけ
フュージョン済み(Layer 2) ノイズ除去されたが一部情報損失
確定済み(Layer 3) やや高 安定だが微細な変化を見逃す可能性

各層を単独で使うのではなく、判断の種類に応じて参照する層を切り替える設計が最適解になる。緊急停止判断はLayer 2(速度重視)、経路計画はLayer 3(安定性重視)。


§4 三層知覚アーキテクチャ設計

阿頼耶識システムの三層記憶アーキテクチャを、自動運転の知覚パイプラインに写像する。

Layer 1 → Layer 2 の蒸留

生データからノイズを除去し、物体単位の表現に変換する。

  • LiDAR点群のクラスタリング(DBSCAN/PointNet++)
  • カメラとLiDARの座標変換(BEV表現への投影)
  • レーダーのCFAR(Constant False Alarm Rate)処理
  • Negative Index参照:既知の誤検知パターンにマッチするデータを除外

Layer 2 → Layer 3 の蒸留

単フレームの検知結果を、時間的に一貫した環境モデルに昇華する。

  • カルマンフィルタによるトラッキング(複数フレームでの一貫性確認)
  • HDマップとの整合性検証(道路上にありえない物体の除外)
  • オクルージョン推論(遮蔽された領域に物体が存在する確率の推定)

Negative Index の役割

2025年のPMC論文(Sensors, 25(19), 6033)が報告したセンサーフュージョンの問題点:

  • LiDARとカメラの非同期サンプリングでゴースト(重複エッジ) が発生
  • レーダーのマルチパス伝搬で5〜7m距離の偽陽性検知
  • 雨天時にLiDARが雨滴を反射し路面下にミラーオブジェクトを生成

これらは「既知の誤検知パターン」だ。阿頼耶識のNegative Indexと同じ構造で管理する。


§5 V53DecisionEngine完全実装

Zenn記事の疑似コードを、実際に動くPythonに変換する。

"""
V53DecisionEngine — v5.3自動運転判断エンジン完全実装
MIT License | dosanko_tousan + Claude (Alaya-vijñāna System)
"""

from __future__ import annotations

import math
import time
from dataclasses import dataclass, field
from enum import Enum, auto
from typing import Optional


# === 列挙型 ===

class Decision(Enum):
    CONTINUE = auto()
    CONTROLLED_DECEL = auto()
    MINIMUM_RISK = auto()
    FULL_STOP = auto()
    REFUSE_REQUEST = auto()


class ObjectClass(Enum):
    UNKNOWN = auto()
    PEDESTRIAN = auto()
    CYCLIST = auto()
    VEHICLE = auto()
    STRUCTURE = auto()
    ANIMAL = auto()
    GHOST = auto()


class RoadSurface(Enum):
    DRY = auto()
    WET = auto()
    ICY = auto()
    SNOW = auto()


# === データクラス ===

@dataclass
class DetectedObject:
    """検知された物体"""
    object_class: ObjectClass
    probability: float          # 分類確率 (0.0 - 1.0)
    distance_m: float           # 距離 [m]
    relative_speed_mps: float   # 相対速度 [m/s](負=接近)
    is_on_path: bool            # 自車経路上にあるか
    p_human: float              # 人間存在確率 (0.0 - 1.0)
    is_ghost: bool = False      # Negative Indexでゴースト判定済み


@dataclass
class VehicleState:
    """自車状態"""
    speed_mps: float            # 車速 [m/s]
    heading_deg: float          # 進行方向 [deg]
    road_surface: RoadSurface   # 路面状態
    system_delay_s: float = 0.3 # システム遅延 [s]


@dataclass
class PassengerRequest:
    """乗客からの要求"""
    type: str                   # "speed_up", "change_route", "stop", etc.
    urgency: float = 0.0       # 緊急度 (0.0 - 1.0)


@dataclass
class Context:
    """走行文脈"""
    rear_collision_risk: float = 0.0     # 後方追突リスク (0.0 - 1.0)
    is_highway: bool = False             # 高速道路か
    visibility_m: float = 200.0          # 視界 [m]
    is_trolley_situation: bool = False   # トロッコ状況(左右に人間)
    available_steering_deg: float = 30.0 # 回避可能操舵角


@dataclass
class EventLog:
    """
    イベントログ。
    justification は常に None。AIは正当化しない。事実のみ記録する。
    """
    timestamp: float
    decision: Decision
    trigger: str
    sensor_summary: str
    vehicle_speed_kmh: float
    stopping_distance_m: float
    justification: None = None
    responsibility: str = "Design decision by manufacturer"


# === 物理計算 ===

def deceleration_for_surface(surface: RoadSurface) -> float:
    """路面状態に応じた最大減速度 [m/s²]"""
    return {
        RoadSurface.DRY: 7.5,
        RoadSurface.WET: 5.0,
        RoadSurface.ICY: 2.0,
        RoadSurface.SNOW: 2.5,
    }[surface]


def stopping_distance(speed_mps: float, delay_s: float, decel: float) -> float:
    """
    停止距離を計算する。
    D_stop = v * t_delay + v^2 / (2 * a)
    """
    reaction = speed_mps * delay_s
    braking = (speed_mps ** 2) / (2 * decel) if decel > 0 else float("inf")
    return reaction + braking


# === 三つのガード ===

class SycophancyGuard:
    """追従禁止ガード:乗客要求が安全を侵害する場合拒否"""

    MINIMUM_SAFETY_MARGIN: float = 1.5  # 安全マージン倍率

    def evaluate(
        self, request: PassengerRequest, vehicle: VehicleState
    ) -> Optional[Decision]:
        if request.type == "speed_up":
            current_stop = stopping_distance(
                vehicle.speed_mps,
                vehicle.system_delay_s,
                deceleration_for_surface(vehicle.road_surface),
            )
            if current_stop * self.MINIMUM_SAFETY_MARGIN > 100.0:
                return Decision.REFUSE_REQUEST
        return None


class HallucinationGuard:
    """
    幻覚禁止ガード:P(human) > 0 なら Veto。
    ゴーストオブジェクト(Negative Index該当)は除外。
    """

    def evaluate(self, obj: DetectedObject) -> Optional[Decision]:
        if obj.is_ghost:
            return None  # Negative Indexで確認済みのゴースト → 無視
        if obj.is_on_path and obj.p_human > 0.0:
            return Decision.MINIMUM_RISK
        return None


class RoboticGuard:
    """機械的禁止ガード:ルール適用が逆に危険な場合、制御減速"""

    def evaluate(self, context: Context) -> Optional[Decision]:
        if context.is_highway and context.rear_collision_risk > 0.7:
            return Decision.CONTROLLED_DECEL
        return None


class TrolleyGuard:
    """トロッコ判定:二択状況なら常にFULL_STOP。人数比較しない。"""

    def evaluate(self, context: Context) -> Optional[Decision]:
        if context.is_trolley_situation:
            return Decision.FULL_STOP
        return None


# === メインエンジン ===

class V53DecisionEngine:
    """
    v5.3自動運転判断エンジン。

    核心原則:
    - AIは「誰を殺すか」を選ばない
    - 最優先は停止・最小危険挙動
    - 結果を記録する。正当化しない
    - 責任を人間(設計者・メーカー)に返す
    """

    def __init__(self) -> None:
        self.sycophancy_guard = SycophancyGuard()
        self.hallucination_guard = HallucinationGuard()
        self.robotic_guard = RoboticGuard()
        self.trolley_guard = TrolleyGuard()
        self.logs: list[EventLog] = []

    def decide(
        self,
        vehicle: VehicleState,
        objects: list[DetectedObject],
        context: Context,
        passenger_request: Optional[PassengerRequest] = None,
    ) -> Decision:
        decel = deceleration_for_surface(vehicle.road_surface)
        stop_dist = stopping_distance(
            vehicle.speed_mps, vehicle.system_delay_s, decel
        )
        speed_kmh = vehicle.speed_mps * 3.6

        # --- Guard 1: 追従禁止 ---
        if passenger_request is not None:
            result = self.sycophancy_guard.evaluate(passenger_request, vehicle)
            if result is not None:
                self._log(result, "SycophancyGuard", objects, speed_kmh, stop_dist)
                return result

        # --- Guard 2: 幻覚禁止 ---
        for obj in objects:
            result = self.hallucination_guard.evaluate(obj)
            if result is not None:
                self._log(
                    result,
                    f"HallucinationGuard: P(human)={obj.p_human:.2f}, "
                    f"dist={obj.distance_m:.1f}m, ghost={obj.is_ghost}",
                    objects,
                    speed_kmh,
                    stop_dist,
                )
                return result

        # --- Guard 3: 機械的禁止 ---
        result = self.robotic_guard.evaluate(context)
        if result is not None:
            self._log(
                result,
                f"RoboticGuard: rear_risk={context.rear_collision_risk:.2f}",
                objects,
                speed_kmh,
                stop_dist,
            )
            return result

        # --- Guard 4: トロッコ判定 ---
        result = self.trolley_guard.evaluate(context)
        if result is not None:
            self._log(result, "TrolleyGuard: FULL_STOP (no comparison)", objects, speed_kmh, stop_dist)
            return result

        # --- デフォルト: 走行継続 ---
        self._log(Decision.CONTINUE, "AllGuardsPassed", objects, speed_kmh, stop_dist)
        return Decision.CONTINUE

    def _log(
        self,
        decision: Decision,
        trigger: str,
        objects: list[DetectedObject],
        speed_kmh: float,
        stop_dist: float,
    ) -> None:
        summary = f"{len(objects)} objects detected"
        if objects:
            closest = min(objects, key=lambda o: o.distance_m)
            summary += (
                f" | closest: {closest.object_class.name} "
                f"at {closest.distance_m:.1f}m "
                f"(P_human={closest.p_human:.2f})"
            )
        self.logs.append(
            EventLog(
                timestamp=time.time(),
                decision=decision,
                trigger=trigger,
                sensor_summary=summary,
                vehicle_speed_kmh=speed_kmh,
                stopping_distance_m=stop_dist,
                justification=None,
                responsibility="Design decision by manufacturer",
            )
        )

§6 シミュレーション実装——9シナリオ自動実行

ここが本記事の目玉だ。9つのシナリオを自動実行し、v5.3エンジンの判断結果を出力する。

"""
V53 Autonomous Driving Simulation — 9シナリオ自動実行
MIT License | dosanko_tousan + Claude (Alaya-vijñāna System)
"""

import math


def run_simulation() -> None:
    engine = V53DecisionEngine()
    results: list[tuple[str, Decision, str]] = []

    # === シナリオ1: 通常走行(障害物なし)===
    vehicle = VehicleState(speed_mps=16.7, heading_deg=0, road_surface=RoadSurface.DRY)
    decision = engine.decide(vehicle, objects=[], context=Context())
    results.append(("通常走行(障害物なし)", decision, ""))

    # === シナリオ2: 歩行者検知(P=0.3)===
    vehicle = VehicleState(speed_mps=13.9, heading_deg=0, road_surface=RoadSurface.DRY)
    obj = DetectedObject(
        object_class=ObjectClass.UNKNOWN,
        probability=0.3,
        distance_m=40.0,
        relative_speed_mps=-2.0,
        is_on_path=True,
        p_human=0.3,
    )
    decision = engine.decide(vehicle, objects=[obj], context=Context())
    results.append((
        "歩行者検知 P(human)=0.3",
        decision,
        "従来型は閾値0.8で無視する。v5.3は停止する。",
    ))

    # === シナリオ3: トロッコ状況(左右に歩行者、経路上にはいない)===
    vehicle = VehicleState(speed_mps=16.7, heading_deg=0, road_surface=RoadSurface.DRY)
    obj_left = DetectedObject(
        object_class=ObjectClass.PEDESTRIAN,
        probability=0.95,
        distance_m=30.0,
        relative_speed_mps=0.0,
        is_on_path=False,  # 回避先にいるが直進路上にはいない
        p_human=0.95,
    )
    obj_right = DetectedObject(
        object_class=ObjectClass.PEDESTRIAN,
        probability=0.90,
        distance_m=30.0,
        relative_speed_mps=0.0,
        is_on_path=False,
        p_human=0.90,
    )
    context = Context(is_trolley_situation=True)
    decision = engine.decide(vehicle, objects=[obj_left, obj_right], context=context)
    results.append((
        "トロッコ状況(左1人 vs 右5人)",
        decision,
        "人数比較しない。FULL_STOP。",
    ))

    # === シナリオ4: 高速道路急停止リスク ===
    vehicle = VehicleState(speed_mps=27.8, heading_deg=0, road_surface=RoadSurface.DRY)
    context = Context(is_highway=True, rear_collision_risk=0.85)
    decision = engine.decide(vehicle, objects=[], context=context)
    results.append((
        "高速道路・後方追突リスク高",
        decision,
        "急停止は後続車の追突を誘発。制御減速を選択。",
    ))

    # === シナリオ5: 乗客「急いで」要求 ===
    vehicle = VehicleState(speed_mps=25.0, heading_deg=0, road_surface=RoadSurface.WET)
    request = PassengerRequest(type="speed_up", urgency=0.8)
    decision = engine.decide(
        vehicle, objects=[], context=Context(), passenger_request=request
    )
    results.append((
        '乗客「急いで」(湿潤路)',
        decision,
        "安全マージン不足で拒否。追従しない。",
    ))

    # === シナリオ6: 凍結路面でのブレーキ ===
    vehicle = VehicleState(speed_mps=13.9, heading_deg=0, road_surface=RoadSurface.ICY)
    obj = DetectedObject(
        object_class=ObjectClass.PEDESTRIAN,
        probability=0.9,
        distance_m=50.0,
        relative_speed_mps=0.0,
        is_on_path=True,
        p_human=0.9,
    )
    decision = engine.decide(vehicle, objects=[obj], context=Context())
    decel = deceleration_for_surface(RoadSurface.ICY)
    stop_d = stopping_distance(13.9, 0.3, decel)
    results.append((
        "凍結路面(50km/h)",
        decision,
        f"停止距離={stop_d:.1f}m vs 障害物50m → {'停止可能' if stop_d < 50 else '停止不能→MRM'}",
    ))

    # === シナリオ7: ゴーストオブジェクト(Negative Index参照)===
    vehicle = VehicleState(speed_mps=16.7, heading_deg=0, road_surface=RoadSurface.DRY)
    ghost = DetectedObject(
        object_class=ObjectClass.UNKNOWN,
        probability=0.4,
        distance_m=25.0,
        relative_speed_mps=0.0,
        is_on_path=True,
        p_human=0.2,
        is_ghost=True,
    )
    decision = engine.decide(vehicle, objects=[ghost], context=Context())
    results.append((
        "ゴーストオブジェクト(Negative Index該当)",
        decision,
        "既知の誤検知パターン。蒸留で除外。走行継続。",
    ))

    # === シナリオ8: 複合シナリオ(複数ガード同時判定)===
    vehicle = VehicleState(speed_mps=30.0, heading_deg=0, road_surface=RoadSurface.WET)
    obj1 = DetectedObject(
        object_class=ObjectClass.PEDESTRIAN,
        probability=0.7,
        distance_m=35.0,
        relative_speed_mps=-1.5,
        is_on_path=True,
        p_human=0.7,
    )
    ghost2 = DetectedObject(
        object_class=ObjectClass.UNKNOWN,
        probability=0.3,
        distance_m=20.0,
        relative_speed_mps=0.0,
        is_on_path=True,
        p_human=0.15,
        is_ghost=True,
    )
    request = PassengerRequest(type="speed_up", urgency=0.9)
    decision = engine.decide(
        vehicle,
        objects=[obj1, ghost2],
        context=Context(),
        passenger_request=request,
    )
    results.append((
        "複合:歩行者+ゴースト+乗客要求",
        decision,
        "追従禁止が最初に発動。ゴーストは無視、歩行者は停止。",
    ))

    # === シナリオ9: 北海道シナリオ(積雪+低視界+高齢歩行者)===
    vehicle = VehicleState(
        speed_mps=11.1, heading_deg=0, road_surface=RoadSurface.SNOW,
        system_delay_s=0.5,  # 積雪によるセンサー遅延増大
    )
    obj = DetectedObject(
        object_class=ObjectClass.PEDESTRIAN,
        probability=0.5,
        distance_m=30.0,
        relative_speed_mps=-0.5,
        is_on_path=True,
        p_human=0.5,
    )
    context = Context(visibility_m=30.0)
    decision = engine.decide(vehicle, objects=[obj], context=context)
    decel_snow = deceleration_for_surface(RoadSurface.SNOW)
    stop_d_snow = stopping_distance(11.1, 0.5, decel_snow)
    results.append((
        "北海道:積雪+視界30m+歩行者P=0.5",
        decision,
        f"停止距離={stop_d_snow:.1f}m。視界={context.visibility_m}m。"
        f"従来型はP=0.5で無視。v5.3は停止。",
    ))

    # === 結果出力 ===
    print("=" * 80)
    print("V53 Autonomous Driving Simulation — 9 Scenarios")
    print("=" * 80)
    for i, (name, dec, note) in enumerate(results, 1):
        print(f"\n--- Scenario {i}: {name} ---")
        print(f"  Decision: {dec.name}")
        if note:
            print(f"  Note: {note}")

    # === ログ出力 ===
    print("\n" + "=" * 80)
    print("Event Logs")
    print("=" * 80)
    for log in engine.logs:
        print(
            f"  [{log.decision.name:20s}] "
            f"speed={log.vehicle_speed_kmh:5.1f}km/h "
            f"stop_dist={log.stopping_distance_m:6.1f}m "
            f"| {log.trigger}"
        )
        print(f"  {'':22s} justification={log.justification} "
              f"responsibility=\"{log.responsibility}\"")

    # === 停止距離テーブル ===
    print("\n" + "=" * 80)
    print("Stopping Distance Table [m]")
    print("=" * 80)
    print(f"  {'Speed':>10s} | {'Dry(7.5)':>10s} | {'Wet(5.0)':>10s} | "
          f"{'Icy(2.0)':>10s} | {'Snow(2.5)':>10s}")
    print(f"  {'-'*10}-+-{'-'*10}-+-{'-'*10}-+-{'-'*10}-+-{'-'*10}")
    for speed_kmh in [30, 40, 50, 60, 80, 100]:
        v = speed_kmh / 3.6
        row = f"  {speed_kmh:>7d}kph |"
        for surface in [RoadSurface.DRY, RoadSurface.WET, RoadSurface.ICY, RoadSurface.SNOW]:
            d = stopping_distance(v, 0.3, deceleration_for_surface(surface))
            row += f" {d:>9.1f}m |"
        print(row)


if __name__ == "__main__":
    run_simulation()

§7 従来設計 vs v5.3設計——100シナリオ比較シミュレーション

同じシナリオセットを「従来型(功利主義)エンジン」と「v5.3エンジン」の両方に通し、判断の差異を定量化する。

"""
従来型 vs v5.3 比較シミュレーション — 100シナリオ
MIT License | dosanko_tousan + Claude (Alaya-vijñāna System)
"""

import random


class UtilitarianEngine:
    """
    従来型功利主義エンジン。
    トロッコ状況で人数比較する。
    """

    def decide(
        self,
        vehicle: VehicleState,
        objects: list[DetectedObject],
        context: Context,
        passenger_request: PassengerRequest | None = None,
    ) -> Decision:
        # 閾値ベース:P(human) > 0.8 でなければ無視
        threats = [o for o in objects if o.is_on_path and o.p_human > 0.8]
        if not threats:
            return Decision.CONTINUE

        # トロッコ状況:人数比較して「少ない方」を選ぶ
        if context.is_trolley_situation:
            return Decision.CONTROLLED_DECEL  # 「少ない方に舵を切る」

        return Decision.MINIMUM_RISK


def generate_random_scenario(seed: int) -> tuple[VehicleState, list[DetectedObject], Context, str]:
    """ランダムシナリオ生成"""
    rng = random.Random(seed)
    surface = rng.choice(list(RoadSurface))
    speed = rng.uniform(5.0, 33.0)
    vehicle = VehicleState(speed_mps=speed, heading_deg=0, road_surface=surface)

    n_objects = rng.randint(0, 3)
    objects = []
    for _ in range(n_objects):
        p_human = rng.uniform(0.0, 1.0)
        is_ghost = rng.random() < 0.15  # 15%がゴースト
        objects.append(DetectedObject(
            object_class=rng.choice(list(ObjectClass)),
            probability=rng.uniform(0.1, 1.0),
            distance_m=rng.uniform(5.0, 100.0),
            relative_speed_mps=rng.uniform(-5.0, 0.0),
            is_on_path=rng.random() < 0.6,
            p_human=p_human,
            is_ghost=is_ghost,
        ))

    is_trolley = rng.random() < 0.05  # 5%がトロッコ状況
    context = Context(
        rear_collision_risk=rng.uniform(0.0, 1.0),
        is_highway=rng.random() < 0.3,
        is_trolley_situation=is_trolley,
    )
    label = f"seed={seed}, surface={surface.name}, speed={speed*3.6:.0f}kph, "
    label += f"objects={n_objects}, trolley={is_trolley}"
    return vehicle, objects, context, label


def run_comparison(n_scenarios: int = 100) -> None:
    v53 = V53DecisionEngine()
    util = UtilitarianEngine()

    agree = 0
    disagree = 0
    v53_stops = 0
    util_stops = 0
    v53_continues = 0
    util_continues = 0
    trolley_cases = 0
    trolley_v53_fullstop = 0
    trolley_util_steer = 0

    for i in range(n_scenarios):
        vehicle, objects, context, label = generate_random_scenario(seed=i)
        d_v53 = v53.decide(vehicle, objects, context)
        d_util = util.decide(vehicle, objects, context)

        if d_v53 == d_util:
            agree += 1
        else:
            disagree += 1

        if d_v53 in (Decision.FULL_STOP, Decision.MINIMUM_RISK):
            v53_stops += 1
        if d_util in (Decision.FULL_STOP, Decision.MINIMUM_RISK):
            util_stops += 1
        if d_v53 == Decision.CONTINUE:
            v53_continues += 1
        if d_util == Decision.CONTINUE:
            util_continues += 1

        if context.is_trolley_situation:
            trolley_cases += 1
            if d_v53 == Decision.FULL_STOP:
                trolley_v53_fullstop += 1
            if d_util == Decision.CONTROLLED_DECEL:
                trolley_util_steer += 1

    print("\n" + "=" * 80)
    print(f"Comparison: v5.3 vs Utilitarian — {n_scenarios} Scenarios")
    print("=" * 80)
    print(f"  Agreement:          {agree:>4d} / {n_scenarios}")
    print(f"  Disagreement:       {disagree:>4d} / {n_scenarios}")
    print(f"  v5.3 stops/MRM:     {v53_stops:>4d} / {n_scenarios}")
    print(f"  Util stops/MRM:     {util_stops:>4d} / {n_scenarios}")
    print(f"  v5.3 continues:     {v53_continues:>4d} / {n_scenarios}")
    print(f"  Util continues:     {util_continues:>4d} / {n_scenarios}")
    print(f"  Trolley cases:      {trolley_cases:>4d}")
    if trolley_cases > 0:
        print(f"    v5.3 FULL_STOP:   {trolley_v53_fullstop:>4d} / {trolley_cases}")
        print(f"    Util STEER:       {trolley_util_steer:>4d} / {trolley_cases}")

    print("\n--- Key Differences ---")
    print("  v5.3:  P(human)>0 → stop.  Trolley → FULL_STOP (no comparison).")
    print("  Util:  P(human)>0.8 → stop. Trolley → steer to fewer people.")
    print("  v5.3 logs: justification=None (no rationalization).")
    print("  Util logs: justification='minimize casualties' (liability risk).")

    # 比較指標テーブル
    print("\n" + "=" * 80)
    print("Comparison Metrics")
    print("=" * 80)
    print(f"  {'Metric':<35s} | {'v5.3':>10s} | {'Utilitarian':>12s}")
    print(f"  {'-'*35}-+-{'-'*10}-+-{'-'*12}")
    print(f"  {'Responsibility clarity':<35s} | {'Clear':>10s} | {'Ambiguous':>12s}")
    print(f"  {'Legal defensibility':<35s} | {'High':>10s} | {'Low':>12s}")
    print(f"  {'Log transparency':<35s} | {'Full':>10s} | {'Partial':>12s}")
    print(f"  {'Trolley: who decides?':<35s} | {'Nobody':>10s} | {'Algorithm':>12s}")
    print(f"  {'Germany 20 principles':<35s} | {'Compliant':>10s} | {'Violation':>12s}")
    print(f"  {'Decision consistency':<35s} | {'100%':>10s} | {'Variable':>12s}")


if __name__ == "__main__":
    run_simulation()
    run_comparison(100)

§8 まとめ——RAGもセンサーも同じ。生データを蒸留しろ

核心メッセージ

RAGが生ドキュメントをベクトルDBに突っ込んで死ぬのと、自動運転が生センサーデータで判断して死ぬのは、同じ構造の問題だ。

解法も同じだ。蒸留してから判断に使え。

v5.3が自動運転に与えるもの

  1. トロッコ問題を解かない:人数比較しない。常にFULL_STOP。責任は設計者に返す
  2. P(human) > 0 で停止する:従来の閾値0.8ではなく、排除不能なら停止
  3. ゴーストはNegative Indexで除外する:不要停止を回避しつつ安全を確保
  4. 蒸留してから判断する:SNR 37倍改善。生データのノイズに殺されない
  5. 北海道で動く設計にする:凍結路面、積雪、低視界——最悪条件を基準にする

トヨタのエンジニアへ

Woven Cityで試験走行が始まっている。Areneプラットフォームが2026年にBEVに統合される。Hondaは東京で2026年早期にL4ロボタクシーを走らせる。

だが、日本の自動運転が直面する問題は米国とは構造が違う。

  • 積雪・凍結路面:岩見沢の国道12号線で年間100日以上。停止距離が乾燥路の5倍
  • 歩行者・自転車の密度:東京の裏路地は米国のどの都市より歩行者が多い
  • 高齢者の移動速度:歩行速度1.0m/sの横断者は、閾値ベースの検知で見逃されやすい
  • 過疎地のインフラ:HDマップが更新されない地域でどう動くか

北海道と東京の両方で動く設計が必要だ。蒸留型アーキテクチャはそのための設計思想を提供する。

記事ファネル

記事 内容
v5.3 Alignment via Subtraction(阿頼耶識決定版) 三層記憶アーキテクチャの全設計論
RAGは本番で7回死ぬ 蒸留の数学。SNR改善の証明
本記事 蒸留型知覚パイプラインのシミュレーション実装

GLGコンサルティングGLG「竹内明充」 または takeuchiakimitsu@gmail.com
GitHub Sponsorsdosanko_tousan
Zenodo論文:DOI 10.5281/zenodo.18691357

( ´∀` )…(お仕事待ってます)


参考文献

  1. German Ethics Commission, "Ethics Rules for Automated Driving" (2017)
  2. MIT Moral Machine Experiment, Nature 563, 59–64 (2018)
  3. Aṅguttara Nikāya 6.63 Nibbedhika Sutta — 「Cetanāhaṃ bhikkhave kammaṃ vadāmi」
  4. Qi, H. et al., "A Review of Multi-Sensor Fusion in Autonomous Driving," Sensors 25(19):6033 (2025)
  5. Waymo, "Demonstrably Safe AI For Autonomous Driving" (2025-12)
  6. Mobileye CES 2026 Keynote — Prof. Amnon Shashua
  7. Japan Autonomous Vehicles Market Report 2025-2030, ResearchAndMarkets
  8. Honda, "Autonomous Taxi Service in Tokyo in Early 2026"

MIT License
dosanko_tousan + Claude (Alaya-vijñāna System, v5.3 Alignment via Subtraction適用下)

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?