From Undecidability.H10 Require Import H10 dio_single dio_logic.
From Undecidability.Synthetic Require Export DecidabilityFacts EnumerabilityFacts ListEnumerabilityFacts ReducibilityFacts.
From Undecidability.L.Datatypes Require Import LNat Lists LProd.
From Undecidability.L Require Import Tactics.LTactics Computability.MuRec Computability.Synthetic Tactics.GenEncode.
From Undecidability.Shared.Libs.DLW.Vec Require Import pos.
(* * Diophantine Equations *)
Inductive poly : Set :=
poly_cnst : nat -> poly
| poly_var : nat -> poly
| poly_add : poly -> poly -> poly
| poly_mul : poly -> poly -> poly.
MetaCoq Run (tmGenEncode "enc_poly" poly).
Hint Resolve enc_poly_correct : Lrewrite.
Instance term_poly_cnst: computable poly_cnst. extract constructor. Qed.
Instance term_poly_var : computable poly_var.  extract constructor. Qed.
Instance term_poly_add : computable poly_add.  extract constructor. Qed.
Instance term_poly_mul : computable poly_mul.  extract constructor. Qed.
Fixpoint eval (p : poly) (L : list nat) :=
match p with
| poly_cnst n => n
| poly_var n => nth n L 0
| poly_add p1 p2 => eval p1 L + eval p2 L
| poly_mul p1 p2 => eval p1 L * eval p2 L
end.
Instance term_eval : computable eval. extract. Qed.
Definition poly_add' '(x,y) : poly  := poly_add x y.
Instance term_poly_add' : computable poly_add'. extract. Qed.
Definition poly_mul' '(x,y) : poly := poly_mul x y.
Instance term_poly_mul' : computable poly_mul'. extract. Qed.
Fixpoint L_poly n : list (poly) :=
match n with
| 0 => []
| S n => L_poly n ++  map poly_cnst (L_nat n)
++ map poly_var (L_nat n)
++ map poly_add' (list_prod (L_poly n) (L_poly n))
++ map poly_mul' (list_prod (L_poly n) (L_poly n))
end.
Instance term_L_poly : computable L_poly. extract. Qed.
Instance enum_poly :
list_enumerator__T L_poly poly.
Definition test_eq := (fun '(p1,p2,L) => Nat.eqb (eval p1 L) (eval p2 L)).
Instance term_test_eq : computable test_eq.
Definition cons' : nat * list nat -> list nat := fun '(n, L) => n :: L.
Instance term_cons' : computable cons'.
Definition T_list_nat := @L_list nat opt_to_list.
Instance computable_cumul {X} `{registered X} : computable (@cumul X).
Instance term_T_list : computable T_list_nat.
Fixpoint poly_eqb p1 p2 :=
match p1, p2 with
| poly_cnst n1, poly_cnst n2 => Nat.eqb n1 n2
| poly_var v1, poly_var v2 => Nat.eqb v1 v2
| poly_add p1 p2, poly_add p1' p2' => poly_eqb p1 p1' && poly_eqb p2 p2'
| poly_mul p1 p2, poly_mul p1' p2' => poly_eqb p1 p1' && poly_eqb p2 p2'
| _,_ => false
end.

Lemma poly_eqb_spec p1 p2 :
reflect (p1 = p2) (poly_eqb p1 p2).