theory StarForth_Physics_Benchmark_Words
  imports StarForth_Base
begin

(* =========================================================================
   Mirrors: src/word_source/physics_benchmark_words.c
   Registers: BENCH-DICT-LOOKUP PHYSICS-CACHE-STATS PHYSICS-TOGGLE-CACHE
              PHYSICS-RESET-STATS PHYSICS-BUILD-INFO PHYSICS-BAYESIAN-REPORT

   ── Hot-words cache -- a whole unmodelled subsystem ─────────────────────
   Every word in this file reads or writes `vm->hotwords_cache` (a
   `HotwordsCache*`) and/or its nested `HotwordsStats` -- neither has any
   counterpart in vm_state. This is the same class of gap as the block-
   window cache StarForth_Block_Words.thy/StarForth_Editor_Words.thy
   already deferred (own subsystem-modelling project, not a one-word
   extension), just for a different cache.

   ── Scope ─────────────────────────────────────────────────────────────
   PHYSICS-RESET-STATS is the one partial exception: alongside its
   unmodelled `hotwords_stats_reset` call, it ALSO resets three
   `pipeline_metrics` fields that ARE in vm_state
   (`pm_prefetch_attempts`/`pm_prefetch_hits`/`pm_tuning_checks`). Modelled
   assuming the (unmodelled) cache-initialized guard is reached -- i.e.
   this states the word's effect on `pipeline_metrics` conditional on
   control reaching that point, not the guard itself.

   BENCH-DICT-LOOKUP's guard/pop shape is modelled (same pattern as
   COMPARE-LOOKUPS/PHYSICS-BURN); its benchmark body is not (timed
   `vm_find_word` loop, same FIND-family gap, PLUS the hot-words cache
   gap above).

   PHYSICS-CACHE-STATS, PHYSICS-TOGGLE-CACHE, PHYSICS-BUILD-INFO, and
   PHYSICS-BAYESIAN-REPORT are entirely reads/writes of the unmodelled
   cache subsystem (or pure stdout using only compile-time constants) --
   not modelled at all.
   ======================================================================== *)

(* ── BENCH-DICT-LOOKUP ( iterations -- ) : guard/pop only ────────────────── *)

definition forth_bench_dict_lookup_guard :: "vm_state \<Rightarrow> vm_state" where
  "forth_bench_dict_lookup_guard vm =
    (case data_stack vm of
       []     \<Rightarrow> set_error vm
     | n # xs \<Rightarrow> vm\<lparr>data_stack := xs\<rparr>)"

lemma bench_dict_lookup_underflow:
  assumes "data_stack vm = []"
  shows "vm_error (forth_bench_dict_lookup_guard vm)"
  by (simp add: forth_bench_dict_lookup_guard_def set_error_def assms)

lemma bench_dict_lookup_pops_one:
  assumes "data_stack vm = n # xs"
  shows "data_stack (forth_bench_dict_lookup_guard vm) = xs"
  by (simp add: forth_bench_dict_lookup_guard_def assms)

lemma bench_dict_lookup_body_not_modelled: True
  \<comment> \<open>iterations \<ge> 1: timed vm_find_word loop over the hot-words cache --
     both the FIND-family gap and the cache-subsystem gap above.\<close>
  by simp

(* ── PHYSICS-RESET-STATS ( -- ) : pipeline_metrics half only ─────────────── *)
(* C: guarded by `if (!vm->hotwords_cache) { ...; return; }` (unmodelled);
   once past that guard: hotwords_stats_reset(...) (unmodelled, cache
   subsystem) THEN three real vm_state field writes:
     vm->pipeline_metrics.prefetch_hits = 0
     vm->pipeline_metrics.prefetch_attempts = 0
     vm->pipeline_metrics.window_tuning_checks = 0
   Modelled as the pipeline_metrics update alone, conditional on the guard
   having been reached (not itself expressed, since "cache initialized"
   has no vm_state predicate). *)

definition forth_physics_reset_stats_metrics :: "vm_state \<Rightarrow> vm_state" where
  "forth_physics_reset_stats_metrics vm =
     vm\<lparr>pipeline_metrics := (pipeline_metrics vm)
          \<lparr>pm_prefetch_hits := 0, pm_prefetch_attempts := 0, pm_tuning_checks := 0\<rparr>\<rparr>"

lemma physics_reset_stats_clears_pipeline_counters:
  "pm_prefetch_hits     (pipeline_metrics (forth_physics_reset_stats_metrics vm)) = 0"
  "pm_prefetch_attempts (pipeline_metrics (forth_physics_reset_stats_metrics vm)) = 0"
  "pm_tuning_checks     (pipeline_metrics (forth_physics_reset_stats_metrics vm)) = 0"
  by (simp_all add: forth_physics_reset_stats_metrics_def)

lemma physics_reset_stats_preserves_other_pipeline_fields:
  "pm_last_window_size    (pipeline_metrics (forth_physics_reset_stats_metrics vm))
     = pm_last_window_size    (pipeline_metrics vm)"
  "pm_last_accuracy_num   (pipeline_metrics (forth_physics_reset_stats_metrics vm))
     = pm_last_accuracy_num   (pipeline_metrics vm)"
  "pm_last_accuracy_den   (pipeline_metrics (forth_physics_reset_stats_metrics vm))
     = pm_last_accuracy_den   (pipeline_metrics vm)"
  "pm_suggested_next_size (pipeline_metrics (forth_physics_reset_stats_metrics vm))
     = pm_suggested_next_size (pipeline_metrics vm)"
  by (simp_all add: forth_physics_reset_stats_metrics_def)

lemma physics_reset_stats_data_stack_unchanged:
  "data_stack (forth_physics_reset_stats_metrics vm) = data_stack vm"
  by (simp add: forth_physics_reset_stats_metrics_def)

(* ── Everything else -- NOT MODELLED ──────────────────────────────────── *)

lemma cache_stats_not_modelled: True       \<comment> \<open>PHYSICS-CACHE-STATS: reads hotwords_cache subsystem, stdout only.\<close>
  by simp
lemma toggle_cache_not_modelled: True      \<comment> \<open>PHYSICS-TOGGLE-CACHE: flips hotwords_cache->enabled -- outside vm_state.\<close>
  by simp
lemma build_info_not_modelled: True        \<comment> \<open>PHYSICS-BUILD-INFO: stdout of compile-time constants + hotwords_cache read.\<close>
  by simp
lemma bayesian_report_not_modelled: True   \<comment> \<open>PHYSICS-BAYESIAN-REPORT: reads/synthesizes HotwordsStats, stdout only.\<close>
  by simp

end
