(**************************************************************)
(*   Copyright Dominique Larchey-Wendling [*]                 *)
(*                                                            *)
(*                             [*] Affiliation LORIA -- CNRS  *)
(**************************************************************)
(*      This file is distributed under the terms of the       *)
(*         CeCILL v2 FREE SOFTWARE LICENSE AGREEMENT          *)
(**************************************************************)
(* 1) Object-level representation of Diophantine logic 2) Closure properties for Diophantine relations and functions 3) Tactics for the automagic recognition of Diophantine shapes *)
From Undecidability.Shared.Libs.DLW.Utils
Set Implicit Arguments.
(* Standard De Bruijn extension and De Bruijn projection *)
(* Fixpoint instead of Definition because of better unfolding properties *)
Definition de_bruijn_ext {X} (ν : nat -> X) x :=
fix dbe n :=
match n with
| 0   => x
| S n => ν n
end.
Notation "x · ν" := (de_bruijn_ext ν x) (at level 1, format "x · ν", left associativity).
Notation "ν ⭳" := (fun n => ν (S n)) (at level 1, format "ν ⭳", no associativity).
Fact de_bruijn_ext_proj X (ν : nat -> X) x n : (x·ν)⭳ n = ν n.
(* The semantics of Diophantine logic *)
Fixpoint df_pred f ν :=
match f with
| df_cst x n     => ν x = n
| df_eq x y      => ν x = ν y
| df_op  o x y z => ν x = de_op_sem o (ν y) (ν z)
| df_bin o f g   => df_op_sem o (⟦f⟧ ν) (⟦g⟧ ν)
| df_exst f      => exists n, ⟦f⟧ n·ν
end
where "⟦ f ⟧" := (df_pred f).
(* Fixpoint equations if needed, for readability and confirmation *)
Fact df_pred_cst x n ν : ⟦x ≐ ⌞n⌟⟧ ν = (ν x = n).
(* Renaming under binders *)
Definition der_lift ρ x := match x with 0 => 0 | S x => S (ρ x) end.
Fixpoint df_ren ρ f :=
match f with
| df_cst x n    => df_cst (ρ x) n
| df_eq x y     => df_eq (ρ x) (ρ y)
| df_op o x y z => df_op o (ρ x) (ρ y) (ρ z)
| df_bin o f g  => df_bin o f⦃ρ⦄ g⦃ρ⦄
| df_exst f     => df_exst f⦃der_lift ρ⦄
end
where "f ⦃ ρ ⦄" := (df_ren ρ f).
Fact df_ren_size ρ f : df_size f⦃ρ⦄ = df_size f.
Fact df_pred_lift f ν : ⟦f⦃S⦄⟧ ν <-> ⟦f⟧ ν⭳.
Fact dio_fun_rem p x : 𝔻F p -> 𝔻F x -> 𝔻F (fun ν => rem (x ν) (p ν)).
Fact dio_rel_ndivides x y : 𝔻F x -> 𝔻F y -> 𝔻R (fun ν => ~ divides (x ν) (y ν)).
Fact df_mexists_size_Z n f : df_size_Z (df_mexists n f) = (Z.of_nat n + df_size_Z f)%Z.
(* We only use it once so there is no need to automatize it We need to make le_lt_dec opaque at some points to prevent it from being computed *)

Lemma df_mexists_spec n f ν :
⟦df_mexists n f⟧ ν
<-> exists π, ⟦f⟧ (fun i => if le_lt_dec n i then ν (i-n) else π i).