(* 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.

Lemma chain_algo : forall c : Call, conform c -> gencode c.