diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-19 18:47:24 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-19 18:47:24 +0800 |
| commit | ab0cdf47f453bf3e12df0201cd7bd1835fb03cae (patch) | |
| tree | c0b755429ead73c9177d0704c109e3aa71b59ce4 /src/LivingVillage.Headless/Program.fs | |
| parent | c1242ee391a25d5e5664befb5efe84b3e471ffd2 (diff) | |
| download | living-village-ab0cdf47f453bf3e12df0201cd7bd1835fb03cae.tar.gz | |
fix: M3c 关系半衰期单位错误 86400L(=24模拟分钟)→ticksPerDay(1模拟日=5,184,000tick) + 衰减改真半衰 exp(-ln2*age/halfLife)(age=halfLife 处权重恰0.5, 旧式 exp(-age/halfLife) 为 e^-1≈0.368) + 单测锁定(1天=5184000tick/halfLife=1天/半衰权重0.5, 手算期望随真半衰语义更新) + headless 批验新增旧判据 old_crit 观测报告(60% 覆盖判据保留为门)
Diffstat (limited to 'src/LivingVillage.Headless/Program.fs')
| -rw-r--r-- | src/LivingVillage.Headless/Program.fs | 24 |
1 files changed, 18 insertions, 6 deletions
diff --git a/src/LivingVillage.Headless/Program.fs b/src/LivingVillage.Headless/Program.fs index e8c7a88..be9c325 100644 --- a/src/LivingVillage.Headless/Program.fs +++ b/src/LivingVillage.Headless/Program.fs @@ -177,9 +177,16 @@ let gini (xs: int64[]) : float = let runBatch (worlds: int) (days: int64) : int = printfn "batch worlds=%d days=%d half_life_ticks=%d rel_threshold=%.2f" worlds days Sim.relationHalfLifeTicks Sim.relationThreshold - printfn "checks: (a) chats max/avg > 2.0 (b) rel_counts max > 2x min (c) no NaN" + // 判据语义(M3c 修正): + // (a) chats max/avg > 2.0 —— 行为分布非均匀(观测值,仍为 pass 条件) + // (b) 至少有一条 |r|>阈值 关系的 NPC 人数 >= 总人数 60% —— 关系网基本连通; + // gini 与 ratio 仅作观测打印,不再作为 pass 条件(旧判据 cntMax>2*cntMin 对 + // 明星集中型分布过严,relcnt_max=0 即判死,与"非均匀分布"的验收目标不符) + // (c) 无 NaN/Inf + printfn "checks: (a) chats max/avg > 2.0 (b) npcs_with_relation >= 0.6*npc_count (c) no NaN (old) relcnt_max > 2*relcnt_min (report only)" let mutable passed = 0 let mutable failed = 0 + let mutable oldPassed = 0 let ratios = ResizeArray<float> () let ginis = ResizeArray<float> () let sw = System.Diagnostics.Stopwatch.StartNew() @@ -201,23 +208,28 @@ let runBatch (worlds: int) (days: int64) : int = let counts = Sim.relationCounts m let cntMax = if counts.Length > 0 then Array.max counts else 0 let cntMin = if counts.Length > 0 then Array.min counts else 0 + let connected = Array.fold (fun acc c -> if c > 0 then acc + 1 else acc) 0 counts + let connectedNeed = int (System.Math.Ceiling(0.6 * float chats.Length)) let checkA = ratio > 2.0 - let checkB = float cntMax > 2.0 * float cntMin + let checkB = connected >= connectedNeed let checkC = not hasNonFinite + let checkOld = cntMax > 2 * cntMin let ok = checkA && checkB && checkC if ok then passed <- passed + 1 else failed <- failed + 1 + if checkOld then oldPassed <- oldPassed + 1 ratios.Add ratio ginis.Add g - printfn "world=%d seed=%d chats_max=%d chats_avg=%.2f ratio=%.3f gini=%.3f relcnt_max=%d relcnt_min=%d nonfinite=%d check_a=%s check_b=%s check_c=%s %s" - k seed chatsMax chatsAvg ratio g cntMax cntMin stats.NonFinite + printfn "world=%d seed=%d chats_max=%d chats_avg=%.2f ratio=%.3f gini=%.3f relcnt_max=%d relcnt_min=%d relconn=%d/%d nonfinite=%d check_a=%s check_b=%s check_c=%s old_crit=%s %s" + k seed chatsMax chatsAvg ratio g cntMax cntMin connected connectedNeed stats.NonFinite (if checkA then "PASS" else "FAIL") (if checkB then "PASS" else "FAIL") (if checkC then "PASS" else "FAIL") + (if checkOld then "PASS" else "FAIL") (if ok then "OK" else "BAD") sw.Stop() let allPass = failed = 0 - printfn "batch_summary worlds=%d passed=%d failed=%d ratio_min=%.3f ratio_max=%.3f gini_min=%.3f gini_max=%.3f elapsed_s=%.1f" - worlds passed failed (Seq.min ratios) (Seq.max ratios) (Seq.min ginis) (Seq.max ginis) sw.Elapsed.TotalSeconds + printfn "batch_summary worlds=%d passed=%d failed=%d old_passed=%d/%d ratio_min=%.3f ratio_max=%.3f gini_min=%.3f gini_max=%.3f elapsed_s=%.1f" + worlds passed failed oldPassed worlds (Seq.min ratios) (Seq.max ratios) (Seq.min ginis) (Seq.max ginis) sw.Elapsed.TotalSeconds printfn "M3_ACCEPTANCE=%s" (if allPass then "PASS" else "FAIL") if allPass then 0 else 1 |
