diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-19 11:07:07 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-19 11:07:07 +0800 |
| commit | c1242ee391a25d5e5664befb5efe84b3e471ffd2 (patch) | |
| tree | b166b59e0f68bcc0344af147548ed1236fba8fa8 /src/LivingVillage.Kernel/Sim.fs | |
| parent | 4993bc37cb00356b83cb4f8a2e4a92fc2fe77922 (diff) | |
| download | living-village-c1242ee391a25d5e5664befb5efe84b3e471ffd2.tar.gz | |
feat: M3b 关系网络派生 — Sim.relationMatrix 双向累加+时间衰减(halfLife 86400tick, |r|>0.5 阈值) + headless --dump-relations 与 --batch K D 验收(chats max/avg、relcnt 差异、无NaN) + Desktop L 键关系视图(暂停+快照, 绿/红线粗细∝|r|, cyan NPC 点) + LV_STEPS_PER_FRAME 调试快进 + 衰减/矩阵/30npc 对称测试(19/19) + xvfb 截图验证 PASS
Diffstat (limited to 'src/LivingVillage.Kernel/Sim.fs')
| -rw-r--r-- | src/LivingVillage.Kernel/Sim.fs | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/src/LivingVillage.Kernel/Sim.fs b/src/LivingVillage.Kernel/Sim.fs index 62ce1e1..ebc435e 100644 --- a/src/LivingVillage.Kernel/Sim.fs +++ b/src/LivingVillage.Kernel/Sim.fs @@ -119,6 +119,10 @@ module Sim = let chatSocialRestore = 40.0f let chatValence = 0.3f + // 关系网派生(纯函数;仅在 dump/视图打开时调用,不进 step 热路径) + let relationHalfLifeTicks = 86400L // HALF_LIFE = 1 天(86400 tick) + let relationThreshold = 0.5f // |rel| > 0.5 视为有关系 + let clamp (v: float32) (lo: float32) (hi: float32) : float32 = if v < lo then lo elif v > hi then hi else v let hungerDecayPerTick = 0.0012f @@ -429,3 +433,38 @@ module Sim = NoHost = world.NoHost Npcs = newNpcs Events = [] } + + // ---- 关系网派生:rel(i,j) = sum(Chatted valence * exp(-(now-tick)/HALF_LIFE)) ---- + + let relationDecayWeight (nowTick: int64) (eventTick: int64) : float32 = + let age = float (nowTick - eventTick) + float32 (exp (-age / float relationHalfLifeTicks)) + + // 30x30 对称矩阵(对角线 0):双向累加双方 Chatted 记忆的衰减 valence + let relationMatrix (world: World) : float32[,] = + let n = world.Npcs.Length + let m = Array2D.zeroCreate n n + for npc in world.Npcs do + let i = + match npc.Id with + | NpcId i -> i + for e in npc.Mind.Memory do + match e.Kind with + | Chatted partner when e.Tick <= world.Tick -> + let j = + match partner with + | NpcId j -> j + if i <> j && i < n && j < n then + let w = e.Valence * relationDecayWeight world.Tick e.Tick + m.[i, j] <- m.[i, j] + w + m.[j, i] <- m.[j, i] + w + | _ -> () + m + + let relationCounts (m: float32[,]) : int[] = + let n = Array2D.length1 m + Array.init n (fun i -> + let mutable c = 0 + for j in 0 .. n - 1 do + if i <> j && abs m.[i, j] > relationThreshold then c <- c + 1 + c) |
