(*************************************************)
(* Parallel beta reduction with residual tracing *)
(*************************************************)

(* (residuals U V W) means W are residuals of redexes U by step V *)

Inductive residuals : redexes -> redexes -> redexes -> Prop :=
  | Res_Var : forall n : nat, residuals (Var n) (Var n) (Var n)
  | Res_Fun :
      forall U V W : redexes,
      residuals U V W -> residuals (Fun U) (Fun V) (Fun W)
  | Res_Ap :
      forall U1 V1 W1 : redexes,
      residuals U1 V1 W1 ->
      forall U2 V2 W2 : redexes,
      residuals U2 V2 W2 ->
      forall b : bool, residuals (Ap b U1 U2) (Ap false V1 V2) (Ap b W1 W2)
  | Res_redex :
      forall U1 V1 W1 : redexes,
      residuals U1 V1 W1 ->
      forall U2 V2 W2 : redexes,
      residuals U2 V2 W2 ->
      forall b : bool,
      residuals (Ap b (Fun U1) U2) (Ap true (Fun V1) V2) (subst_r W2 W1).(*************************************************)
(* Parallel beta reduction with residual tracing *)
(*************************************************)

(* (residuals U V W) means W are residuals of redexes U by step V *)

Inductive residuals : redexes -> redexes -> redexes -> Prop :=
  | Res_Var : forall n : nat, residuals (Var n) (Var n) (Var n)
  | Res_Fun :
      forall U V W : redexes,
      residuals U V W -> residuals (Fun U) (Fun V) (Fun W)
  | Res_Ap :
      forall U1 V1 W1 : redexes,
      residuals U1 V1 W1 ->
      forall U2 V2 W2 : redexes,
      residuals U2 V2 W2 ->
      forall b : bool, residuals (Ap b U1 U2) (Ap false V1 V2) (Ap b W1 W2)
  | Res_redex :
      forall U1 V1 W1 : redexes,
      residuals U1 V1 W1 ->
      forall U2 V2 W2 : redexes,
      residuals U2 V2 W2 ->
      forall b : bool,
      residuals (Ap b (Fun U1) U2) (Ap true (Fun V1) V2) (subst_r W2 W1).(*************************************************)
(* Parallel beta reduction with residual tracing *)
(*************************************************)

(* (residuals U V W) means W are residuals of redexes U by step V *)

Inductive residuals : redexes -> redexes -> redexes -> Prop :=
  | Res_Var : forall n : nat, residuals (Var n) (Var n) (Var n)
  | Res_Fun :
      forall U V W : redexes,
      residuals U V W -> residuals (Fun U) (Fun V) (Fun W)
  | Res_Ap :
      forall U1 V1 W1 : redexes,
      residuals U1 V1 W1 ->
      forall U2 V2 W2 : redexes,
      residuals U2 V2 W2 ->
      forall b : bool, residuals (Ap b U1 U2) (Ap false V1 V2) (Ap b W1 W2)
  | Res_redex :
      forall U1 V1 W1 : redexes,
      residuals U1 V1 W1 ->
      forall U2 V2 W2 : redexes,
      residuals U2 V2 W2 ->
      forall b : bool,
      residuals (Ap b (Fun U1) U2) (Ap true (Fun V1) V2) (subst_r W2 W1).(*************************************************)
(* Parallel beta reduction with residual tracing *)
(*************************************************)

(* (residuals U V W) means W are residuals of redexes U by step V *)

Inductive residuals : redexes -> redexes -> redexes -> Prop :=
  | Res_Var : forall n : nat, residuals (Var n) (Var n) (Var n)
  | Res_Fun :
      forall U V W : redexes,
      residuals U V W -> residuals (Fun U) (Fun V) (Fun W)
  | Res_Ap :
      forall U1 V1 W1 : redexes,
      residuals U1 V1 W1 ->
      forall U2 V2 W2 : redexes,
      residuals U2 V2 W2 ->
      forall b : bool, residuals (Ap b U1 U2) (Ap false V1 V2) (Ap b W1 W2)
  | Res_redex :
      forall U1 V1 W1 : redexes,
      residuals U1 V1 W1 ->
      forall U2 V2 W2 : redexes,
      residuals U2 V2 W2 ->
      forall b : bool,
      residuals (Ap b (Fun U1) U2) (Ap true (Fun V1) V2) (subst_r W2 W1).(*************************************************)
(* Parallel beta reduction with residual tracing *)
(*************************************************)

(* (residuals U V W) means W are residuals of redexes U by step V *)

Inductive residuals : redexes -> redexes -> redexes -> Prop :=
  | Res_Var : forall n : nat, residuals (Var n) (Var n) (Var n)
  | Res_Fun :
      forall U V W : redexes,
      residuals U V W -> residuals (Fun U) (Fun V) (Fun W)
  | Res_Ap :
      forall U1 V1 W1 : redexes,
      residuals U1 V1 W1 ->
      forall U2 V2 W2 : redexes,
      residuals U2 V2 W2 ->
      forall b : bool, residuals (Ap b U1 U2) (Ap false V1 V2) (Ap b W1 W2)
  | Res_redex :
      forall U1 V1 W1 : redexes,
      residuals U1 V1 W1 ->
      forall U2 V2 W2 : redexes,
      residuals U2 V2 W2 ->
      forall b : bool,
      residuals (Ap b (Fun U1) U2) (Ap true (Fun V1) V2) (subst_r W2 W1).

Theorem commutation : forall U1 U2 U3 V1 V2 V3 : redexes, residuals U1 U2 U3 -> residuals V1 V2 V3 -> residuals (subst_r V1 U1) (subst_r V2 U2) (subst_r V3 U3).