(* termination of the addition chain algorithm *)
(***********************************************)

(* termination order (based on recursive calls) *)

Inductive Call_lt : Call -> Call -> Prop :=
  | M_M_lt : forall p q : nat, p < q -> Call_lt (Call_M p) (Call_M q)
  | C_M_lt : forall p q : nat, p < q -> Call_lt (Call_C q p) (Call_M q)
  | M_C_lt : forall p q r : nat, p < r -> Call_lt (Call_M p) (Call_C r q)
  | M_K_lt : forall p q r : nat, p <= r -> Call_lt (Call_M p) (Call_K r q)
  | K_C_lt : forall p q r s : nat, q < s -> Call_lt (Call_K q p) (Call_C s r)
  | K_K_lt : forall p q r s : nat, q < s -> Call_lt (Call_K q p) (Call_K s r).(* termination of the addition chain algorithm *)
(***********************************************)

(* termination order (based on recursive calls) *)

Inductive Call_lt : Call -> Call -> Prop :=
  | M_M_lt : forall p q : nat, p < q -> Call_lt (Call_M p) (Call_M q)
  | C_M_lt : forall p q : nat, p < q -> Call_lt (Call_C q p) (Call_M q)
  | M_C_lt : forall p q r : nat, p < r -> Call_lt (Call_M p) (Call_C r q)
  | M_K_lt : forall p q r : nat, p <= r -> Call_lt (Call_M p) (Call_K r q)
  | K_C_lt : forall p q r s : nat, q < s -> Call_lt (Call_K q p) (Call_C s r)
  | K_K_lt : forall p q r s : nat, q < s -> Call_lt (Call_K q p) (Call_K s r).(* termination of the addition chain algorithm *)
(***********************************************)

(* termination order (based on recursive calls) *)

Inductive Call_lt : Call -> Call -> Prop :=
  | M_M_lt : forall p q : nat, p < q -> Call_lt (Call_M p) (Call_M q)
  | C_M_lt : forall p q : nat, p < q -> Call_lt (Call_C q p) (Call_M q)
  | M_C_lt : forall p q r : nat, p < r -> Call_lt (Call_M p) (Call_C r q)
  | M_K_lt : forall p q r : nat, p <= r -> Call_lt (Call_M p) (Call_K r q)
  | K_C_lt : forall p q r s : nat, q < s -> Call_lt (Call_K q p) (Call_C s r)
  | K_K_lt : forall p q r s : nat, q < s -> Call_lt (Call_K q p) (Call_K s r).(* termination of the addition chain algorithm *)
(***********************************************)

(* termination order (based on recursive calls) *)

Inductive Call_lt : Call -> Call -> Prop :=
  | M_M_lt : forall p q : nat, p < q -> Call_lt (Call_M p) (Call_M q)
  | C_M_lt : forall p q : nat, p < q -> Call_lt (Call_C q p) (Call_M q)
  | M_C_lt : forall p q r : nat, p < r -> Call_lt (Call_M p) (Call_C r q)
  | M_K_lt : forall p q r : nat, p <= r -> Call_lt (Call_M p) (Call_K r q)
  | K_C_lt : forall p q r s : nat, q < s -> Call_lt (Call_K q p) (Call_C s r)
  | K_K_lt : forall p q r s : nat, q < s -> Call_lt (Call_K q p) (Call_K s r).(* termination of the addition chain algorithm *)
(***********************************************)

(* termination order (based on recursive calls) *)

Inductive Call_lt : Call -> Call -> Prop :=
  | M_M_lt : forall p q : nat, p < q -> Call_lt (Call_M p) (Call_M q)
  | C_M_lt : forall p q : nat, p < q -> Call_lt (Call_C q p) (Call_M q)
  | M_C_lt : forall p q r : nat, p < r -> Call_lt (Call_M p) (Call_C r q)
  | M_K_lt : forall p q r : nat, p <= r -> Call_lt (Call_M p) (Call_K r q)
  | K_C_lt : forall p q r s : nat, q < s -> Call_lt (Call_K q p) (Call_C s r)
  | K_K_lt : forall p q r s : nat, q < s -> Call_lt (Call_K q p) (Call_K s r).(* termination of the addition chain algorithm *)
(***********************************************)

(* termination order (based on recursive calls) *)

Inductive Call_lt : Call -> Call -> Prop :=
  | M_M_lt : forall p q : nat, p < q -> Call_lt (Call_M p) (Call_M q)
  | C_M_lt : forall p q : nat, p < q -> Call_lt (Call_C q p) (Call_M q)
  | M_C_lt : forall p q r : nat, p < r -> Call_lt (Call_M p) (Call_C r q)
  | M_K_lt : forall p q r : nat, p <= r -> Call_lt (Call_M p) (Call_K r q)
  | K_C_lt : forall p q r s : nat, q < s -> Call_lt (Call_K q p) (Call_C s r)
  | K_K_lt : forall p q r s : nat, q < s -> Call_lt (Call_K q p) (Call_K s r).(* termination of the addition chain algorithm *)
(***********************************************)

(* termination order (based on recursive calls) *)

Inductive Call_lt : Call -> Call -> Prop :=
  | M_M_lt : forall p q : nat, p < q -> Call_lt (Call_M p) (Call_M q)
  | C_M_lt : forall p q : nat, p < q -> Call_lt (Call_C q p) (Call_M q)
  | M_C_lt : forall p q r : nat, p < r -> Call_lt (Call_M p) (Call_C r q)
  | M_K_lt : forall p q r : nat, p <= r -> Call_lt (Call_M p) (Call_K r q)
  | K_C_lt : forall p q r s : nat, q < s -> Call_lt (Call_K q p) (Call_C s r)
  | K_K_lt : forall p q r s : nat, q < s -> Call_lt (Call_K q p) (Call_K s r).(* In order to prove well-foundedness of Call_lt, we use an
   auxiliary ad-hoc measure *)


Definition Call_measure (c : Call) :=
  match c return nat with
  | Call_M n =>
      (* Call_M n *)
      S (three * n)
      (* Call_C n p *)
  | Call_C n p => three * n
      (* Call_K n p *)
  | Call_K n p => S (S (three * n))
  end.

(* Specifications: *)
Lemma measure_compat : coarser Call Call_lt (ltof Call Call_measure).
Lemma Wf_Call_lt : well_founded Call_lt.
Lemma chain_cases : forall p : nat, 0 < p -> {q : nat | q < p /\ two <= q} + {l : nat | p = two_power l} + {p = three}.
Lemma COND3 : forall (A : nat -> Set) (p : nat), (p = three -> A p) -> (forall q : nat, p = two_power q -> A p) -> (forall q : nat, q < p -> two <= q -> A p) -> 0 < p -> A p.
Lemma chain_algo : forall c : Call, conform c -> gencode c.
Lemma power_algo : forall n : nat, 0 < n -> addchain_spec n.