Load Common.

Require Import UserTactics.

Inductive diophantine : Set :=
  | dio_one (x : nat) : diophantine
  | dio_sum (x y z : nat) : diophantine
  | dio_prod (x y z : nat) : diophantine.

Module Diophantine.

Lemma eq_dec : forall (d1 d2 : diophantine), {d1 = d2} + {d1 <> d2}.
Proof.
case => [x |x y z |x y z]; case => [x' |x' y' z'|x' y' z'].
all : try (by right).
all : have := Nat.eq_dec x x'.
do ? (firstorder (do [by left | by right; case | auto])).
all : have := Nat.eq_dec y y'; have := Nat.eq_dec z z'.
all : do ? (firstorder (do [by left; f_equal | by right; case])).
Qed.

(*f encodes the variable valuation : V -> {1, 2, ...}*)
Definition eval (f : nat -> nat) (d : diophantine) : bool :=
  match d with
  | dio_one x => (1 + f x) =? 1
  | dio_sum x y z => (1 + f x) + (1 + f y) =? (1 + f z)
  | dio_prod x y z => (1 + f x) * (1 + f y) =? (1 + f z)
  end.

Inductive solvable (ds : list diophantine) : Prop :=
  | solution : (exists (f : nat -> nat), Forall (fun d => eval f d = true) ds) -> solvable ds.

Fixpoint variables (d : diophantine) : list nat :=
  match d with
  | (dio_one x) => [x]
  | (dio_sum x y z) => [x; y; z]
  | (dio_prod x y z) => [x; y; z]
  end.
End Diophantine.