From Undecidability.L.Tactics Require Import LTactics.
From Undecidability.L Require Import UpToC.
From Undecidability.L.Datatypes Require Export List_enc List_in List_basics LBool LNat.

Set Default Proof Using "Type".

Definition lengthEq A :=
  fix f (t:list A) n :=
    match n,t with
      0,nil true
    | (S n), _::t f t n
    | _,_ false
    end.
Lemma lengthEq_spec A (t:list A) n:
| t | =? n = lengthEq t n.
Proof.
  induction n in t|-*;destruct t;now cbn.
Qed.

Definition lengthEq_time k := k * 15 + 9.
#[global]
Instance term_lengthEq A `{registered A} : computableTime' (lengthEq (A:=A)) ( l _ (5, n _ (lengthEq_time (min (length l) n),tt))).
Proof.
  extract. unfold lengthEq_time. solverec.
Qed.


Definition c__seq := 20.
Definition seq_time (len : ) := (len + 1) * c__seq.
#[global]
Instance term_seq : computableTime' seq ( start _ (5, len _ (seq_time len, tt))).
Proof.
  extract. solverec.
  all: unfold seq_time, c__seq; solverec.
Qed.


Section fixprodLists.
  Variable (X Y : Type).
  Context `{Xint : registered X} `{Yint : registered Y}.

  Definition c__prodLists1 := 22 + c__map + c__app.
  Definition c__prodLists2 := 2 * c__map + 39 + c__app.
  Definition prodLists_time (l1 : list X) (l2 : list Y) := (||) * (|| + 1) * c__prodLists2 + c__prodLists1.
  Global Instance term_prodLists : computableTime' (@list_prod X Y) ( l1 _ (5, l2 _ (prodLists_time , tt))).
  Proof.
    apply computableTimeExt with (x := fix rec (A : list X) (B : list Y) : list (X * Y) :=
      match A with
      | [] []
      | x :: A' map (@pair X Y x) B rec A' B
      end).
    1: { unfold list_prod. change ( x ?h x) with h. intros . induction ; easy. }
    extract. solverec.
    all: unfold prodLists_time, c__prodLists1, c__prodLists2; solverec.
    rewrite map_length, map_time_const. leq_crossout.
  Qed.

End fixprodLists.