Theory Parity_Numeric_Queries

theory Parity_Numeric_Queries
  imports Parity_Domain
begin

section ‹Parity interpretation of the generic numeric-query interface›

text ‹
  Third-domain validation for ‹sound_numeric_queries›
  (theory‹Voblint_Domain.Numeric_Queries›), hand-tuned like
  ‹Voblint_Analysis_Interval.Interval_Numeric_Queries› rather than derived through
  ‹sound_refinement›: parity has no ‹inv_less› instance (guards do not
  refine parity), so there is nothing for
  the generic derivations to read off. Parity carries no order information at
  all, so ‹parity_less_true›/‹parity_less_false› are provable only in the
  vacuous case (one side ‹PBot›); every genuine pair is unknown. ‹PBot› is the
  lattice's unique empty representative (unlike Interval's raw ‹ivl› type,
  which has infinitely many non-canonical empty representations), so the
  vacuous case is a single clean equality test, as for Sign's ‹SBot›.
›

subsection ‹Comparison judgments: vacuous only›

text ‹
  ‹parity_less_true a b›/‹parity_less_false a b› both hold exactly when one
  side concretizes to nothing: neither judgment can ever be established from
  parity alone, since knowing a value's evenness says nothing about its order
  against another value's evenness. The two coincide definitionally --- both
  are the same vacuity test --- which is itself the content of the "usually
  unknown" fact about Parity's order queries.
›

definition parity_vacuous :: "parity ⇒ parity ⇒ bool" where
  "parity_vacuous a b ⟷ (a = PBot ∨ b = PBot)"

definition parity_less_true :: "parity ⇒ parity ⇒ bool" where
  "parity_less_true = parity_vacuous"

definition parity_less_false :: "parity ⇒ parity ⇒ bool" where
  "parity_less_false = parity_vacuous"

lemma parity_less_true_sound:
  assumes "parity_less_true a b" and "i ∈ gamma_parity a" and "j ∈ gamma_parity b"
  shows "i < j"
  using assms unfolding parity_less_true_def parity_vacuous_def by (cases a; cases b; auto)

lemma parity_less_false_sound:
  assumes "parity_less_false a b" and "i ∈ gamma_parity a" and "j ∈ gamma_parity b"
  shows "¬ i < j"
  using assms unfolding parity_less_false_def parity_vacuous_def by (cases a; cases b; auto)

subsection ‹Equality judgments›

text ‹
  ‹parity_eq_true› is vacuous-only for the same reason as the order queries:
  no parity class concretizes to a singleton (unlike Sign's ‹SZero› or an
  Interval point interval), so no non-vacuous pair is ever provably equal.
  ‹parity_eq_true a b› asks provable equality of every witness pair, so a
  reflexive-looking check such as ‹x == x› is ∗‹not› classified true by this
  interface either: ‹aval_abs› only ever hands both sides the same
  ∗‹abstract› value ‹PEven›/‹POdd›/‹PTop›, which still ranges over
  infinitely many concrete integers, so ‹eq_true› stays false there too ---
  correctly: this classification layer never assumes two occurrences of the
  same syntactic expression carry a hidden equality constraint.

  ‹parity_eq_true› is genuinely provable to be true for identical parity
  classes when combined at the check level with the compiler-independent
  evaluator; this file states it as it is, no more.
›

definition parity_eq_true :: "parity ⇒ parity ⇒ bool" where
  "parity_eq_true = parity_vacuous"

lemma parity_eq_true_sound:
  assumes "parity_eq_true a b" and "i ∈ gamma_parity a" and "j ∈ gamma_parity b"
  shows "i = j"
  using assms unfolding parity_eq_true_def parity_vacuous_def by (cases a; cases b; auto)

text ‹
  ‹parity_eq_false› is where parity earns its keep: two values of disjoint
  parity classes --- one ‹PEven›, the other ‹POdd› --- can never be equal,
  regardless of how imprecise Sign or Interval are about the same pair (both
  may see fully overlapping sign/range information). This is the one query
  Parity answers strictly better than a vacuity check.
›

fun parity_eq_false :: "parity ⇒ parity ⇒ bool" where
    "parity_eq_false PEven POdd = True"
  | "parity_eq_false POdd PEven = True"
  | "parity_eq_false a b = (a = PBot ∨ b = PBot)"

lemma parity_eq_false_sound:
  assumes "parity_eq_false a b" and "i ∈ gamma_parity a" and "j ∈ gamma_parity b"
  shows "i ≠ j"
  using assms by (cases a; cases b; auto)

subsection ‹Goblint-style optional-Boolean queries›

text ‹
  ‹parity_less›/‹parity_eq› are the generic packaging of the four judgments
  above, so one interpretation both introduces them and discharges the query
  interface. Nothing about that packaging is backward-specific: it asks only
  for four judgments and their soundness, which is why parity can reuse it
  while having no ‹inv_less› for the derivations beside it to read off. The
  ⬚‹defines› clause is what keeps the two queries ordinary
  top-level constants, with the code equation the check layer needs.
›

global_interpretation parity_numeric_queries:
  numeric_query_judgments
    parity_less_true parity_less_false parity_eq_true parity_eq_false
  defines parity_less = parity_numeric_queries.query_less
    and parity_eq = parity_numeric_queries.query_eq
  by unfold_locales
     (auto intro: parity_less_true_sound parity_eq_true_sound
            dest: parity_less_false_sound parity_eq_false_sound)


end