Theory Example_Per_Origin_Widening_Precision
theory Example_Per_Origin_Widening_Precision
imports
"Voblint_Analysis_Interval.Interval_Exec"
begin
section ‹Per-origin widening keeps a precision the joined-then-widened slot loses›
text ‹
Two producers write a different constant to the same global unknown, and nothing else
happens: each producer issues one \<^const>‹Side› contribution and stabilises. The
concrete slot value is therefore exactly ‹[1, 2]›, and any update rule reporting more
than that is losing precision to its own combination discipline rather than to the
program.
This separates the two widening rules, which agree everywhere a global has a single
producer:
▪ \<^const>‹update_global_warrowing_apinis› widens the slot value ∗‹after› the join. The
left producer's write leaves the slot at ‹[1, 1]›. The right producer's write then
recomputes \<^const>‹sup_over_origins› as ‹[1, 2]› and widens ‹[1, 1] ∇ [1, 2]›; the upper
bound grew, so it goes to \<^const>‹PlusInf›. The growth is an artifact of two producers
sharing one slot -- neither producer's own contribution ever moved.
▪ \<^const>‹update_global_warrowing_per_origin› widens each contribution against that
origin's previous contribution and joins afterwards. Both writes are first writes for
their origin, so the ‹bot ∇ x = x› law (\<^theory>‹Voblint_Analysis_Interval.Interval_Warrowing›)
keeps each exact, and the read joins them to ‹[1, 2]›.
The narrowing half of warrowing cannot repair the joined rule here: once both producers
are stable neither re-issues its contribution, so there is no later recomputation for
\<^const>‹narrow› to descend from and ‹[1, +inf]› is a genuine fixpoint.
›