(* Levelization (Lemma 2.5): a clocked netlist whose units have maximal depth d >= 1 is computed by a layered map of depth d. Each unit that contributes to a next value occurs in it with its weights and bias, once if its depth is less than d and once for each state bit whose next value it is if its depth is d, and every other row is an identity unit. *) From Stdlib Require Import List Bool Arith ZArith Lia. Import ListNotations. From TH Require Import TwoHead Net. (* ---- layered maps (Definition 2.3) ----------------------------------------------------------------------- *) (* a layer: rows reading the outputs of the layer before by position *) Definition lfire (L : list tu) (y : list bool) : list bool := map (fun u => fire u (fun i => nth i y false)) L. Definition lmap (Ls : list (list tu)) (x : list bool) : list bool := fold_left (fun y L => lfire L y) Ls x. (* the rows of each layer read positions of the layer before, distinct ones, with weights -1 or 1 *) Definition rowok (w : nat) (u : tu) : Prop := NoDup (map fst (tin u)) /\ forall i z, In (i, z) (tin u) -> i < w /\ (z = 1 \/ z = -1)%Z. Fixpoint lwf (w : nat) (Ls : list (list tu)) : Prop := match Ls with [] => True | L :: t => Forall (rowok w) L /\ lwf (length L) t end. Lemma lmap_app : forall Ls L x, lmap (Ls ++ [L]) x = lfire L (lmap Ls x). Proof. intros Ls L x. unfold lmap. rewrite fold_left_app. reflexivity. Qed. (* ---- depth -------------------------------------------------------------------------------------------- *) Fixpoint maxl (l : list nat) : nat := match l with [] => 0 | x :: t => Nat.max x (maxl t) end. Lemma maxl_ge : forall l a, In a l -> a <= maxl l. Proof. induction l as [|x t IH]; intros a H; [destruct H|]. destruct H as [<-|H]; cbn [maxl]; [lia|]. specialize (IH a H). lia. Qed. Lemma maxl_le : forall l c, (forall a, In a l -> a <= c) -> maxl l <= c. Proof. induction l as [|x t IH]; intros c H; cbn [maxl]; [lia|]. pose proof (H x (or_introl eq_refl)). pose proof (IH c (fun a Ha => H a (or_intror Ha))). lia. Qed. Lemma maxl_pos : forall l, 1 <= maxl l -> exists a, In a l /\ 1 <= a. Proof. induction l as [|x t IH]; cbn [maxl]; intro H; [lia|]. destruct (Nat.le_gt_cases 1 x) as [Hx|Hx]; [exists x; split; [left; reflexivity | exact Hx]|]. destruct (IH ltac:(lia)) as (a & Ha & H1). exists a. split; [right; exact Ha | exact H1]. Qed. (* the depth of a signal: 0 for a state bit, one more than its deepest predecessor for a unit *) Fixpoint depf (us : list tu) (m : nat) (D : nat -> nat) : nat -> nat := match us with | [] => D | u :: t => depf t (S m) (fun i => if Nat.eqb i m then S (maxl (map (fun p => D (fst p)) (tin u))) else D i) end. Lemma depf_prefix : forall us m D i, i < m -> depf us m D i = D i. Proof. induction us as [|u t IH]; intros m D i H; cbn [depf]; [reflexivity|]. rewrite IH by lia. destruct (Nat.eqb_spec i m); [lia | reflexivity]. Qed. Lemma depf_at : forall us m D j, j < length us -> (forall k, k < length us -> reads_below (nth k us tu0) (m + k)) -> depf us m D (m + j) = S (maxl (map (fun p => depf us m D (fst p)) (tin (nth j us tu0)))). Proof. induction us as [|u t IH]; intros m D j Hj Hwf; cbn [length] in Hj, Hwf; [lia|]. destruct j as [|j]. - cbn [nth depf]. rewrite Nat.add_0_r, depf_prefix by lia. rewrite Nat.eqb_refl. f_equal. f_equal. apply map_ext_in. intros [i z] Hin. cbn [fst]. pose proof (Hwf 0 ltac:(lia) i z Hin) as Hi. cbn [nth] in Hi. rewrite depf_prefix by lia. destruct (Nat.eqb_spec i m); [lia | reflexivity]. - cbn [nth depf]. replace (m + S j) with (S m + j) by lia. apply IH; [lia|]. intros k Hk i z Hin. specialize (Hwf (S k) ltac:(lia) i z Hin). lia. Qed. Lemma map_nth_self : forall (l : list nat) d, map (fun i => nth i l d) (seq 0 (length l)) = l. Proof. induction l as [|a t IH]; intro d; [reflexivity|]. cbn [length seq map nth]. f_equal. rewrite <- seq_shift, map_map. apply IH. Qed. Section Lev. Variable n : nat. Variable us : list tu. Variable nx : list nat. Definition NS : nat := n + length us. Definition wfn : Prop := forall k, k < length us -> reads_below (nth k us tu0) (n + k). Definition dep : nat -> nat := depf us n (fun _ => 0). Definition dmax : nat := maxl (map (fun k => dep (n + k)) (seq 0 (length us))). (* unit k reads signal s *) Definition reads (k s : nat) : bool := existsb (fun p => Nat.eqb (fst p) s) (tin (nth k us tu0)). Lemma reads_in : forall k s, reads k s = true <-> exists z, In (s, z) (tin (nth k us tu0)). Proof. intros k s. unfold reads. rewrite existsb_exists. split. - intros ([i z] & Hin & E). cbn [fst] in E. apply Nat.eqb_eq in E. subst i. exists z. exact Hin. - intros (z & Hin). exists (s, z). split; [exact Hin | apply Nat.eqb_refl]. Qed. Lemma dep_state : forall i, i < n -> dep i = 0. Proof. intros i H. unfold dep. rewrite depf_prefix by exact H. reflexivity. Qed. Lemma dep_unit : wfn -> forall k, k < length us -> dep (n + k) = S (maxl (map (fun p => dep (fst p)) (tin (nth k us tu0)))). Proof. intros Hwf k Hk. unfold dep. apply depf_at; assumption. Qed. Lemma dep_pred : wfn -> forall k p z, k < length us -> In (p, z) (tin (nth k us tu0)) -> dep p < dep (n + k). Proof. intros Hwf k p z Hk Hin. rewrite dep_unit by assumption. apply Nat.lt_succ_r. apply maxl_ge. apply in_map_iff. exists (p, z). split; [reflexivity | exact Hin]. Qed. Lemma dep_le_dmax : forall k, k < length us -> dep (n + k) <= dmax. Proof. intros k Hk. apply maxl_ge. apply in_map_iff. exists k. split; [reflexivity | apply in_seq; lia]. Qed. Lemma dep_unit_pos : wfn -> forall k, k < length us -> 1 <= dep (n + k). Proof. intros Hwf k Hk. rewrite dep_unit by assumption. lia. Qed. Lemma dep_zero : wfn -> forall s, s < NS -> dep s = 0 -> s < n. Proof. intros Hwf s Hs H. destruct (Nat.lt_ge_cases s n) as [Hl|Hg]; [exact Hl|]. pose proof (dep_unit_pos Hwf (s - n) ltac:(unfold NS in Hs; lia)). replace (n + (s - n)) with s in H0 by lia. lia. Qed. Lemma dep_le : forall s, s < NS -> dep s <= dmax. Proof. intros s Hs. destruct (Nat.lt_ge_cases s n) as [Hl|Hg]; [rewrite dep_state by exact Hl; lia|]. replace s with (n + (s - n)) by lia. apply dep_le_dmax. unfold NS in Hs. lia. Qed. (* ---- the signals some next value depends on -------------------------------------------------------- *) Fixpoint needf (vs : list tu) (m : nat) (S0 : nat -> bool) : nat -> bool := match vs with | [] => S0 | u :: t => let N' := needf t (S m) S0 in fun i => N' i || (N' m && existsb (fun p => Nat.eqb (fst p) i) (tin u)) end. Definition need : nat -> bool := needf us n (fun i => existsb (Nat.eqb i) nx). Lemma needf_seed : forall vs m S0 i, S0 i = true -> needf vs m S0 i = true. Proof. induction vs as [|u t IH]; intros m S0 i H; cbn [needf]; [exact H|]. rewrite IH by exact H. reflexivity. Qed. Lemma needf_closed : forall vs m S0 k p z, k < length vs -> (forall j, j < length vs -> reads_below (nth j vs tu0) (m + j)) -> needf vs m S0 (m + k) = true -> In (p, z) (tin (nth k vs tu0)) -> needf vs m S0 p = true. Proof. induction vs as [|u t IH]; intros m S0 k p z Hk Hwf Hn Hin; cbn [length] in Hk; [lia|]. assert (Hu : forall i z', In (i, z') (tin u) -> i < m) by (intros i z' H; specialize (Hwf 0 ltac:(cbn; lia) i z' H); cbn [nth] in Hwf; lia). assert (Hm : existsb (fun p0 => Nat.eqb (fst p0) (m + k)) (tin u) = true -> False). { intro E. apply existsb_exists in E as ([i z'] & Hi & E). cbn [fst] in E. apply Nat.eqb_eq in E. subst i. specialize (Hu _ _ Hi). lia. } cbn [needf] in *. destruct k as [|k]. - cbn [nth] in Hin. rewrite Nat.add_0_r in Hn. apply orb_true_iff in Hn as [Hn|Hn]. + apply orb_true_iff. right. rewrite Hn. cbn [andb]. apply existsb_exists. exists (p, z). split; [exact Hin|]. apply Nat.eqb_refl. + apply andb_true_iff in Hn as [Hn _]. apply orb_true_iff. right. rewrite Hn. cbn [andb]. apply existsb_exists. exists (p, z). split; [exact Hin | apply Nat.eqb_refl]. - cbn [nth] in Hin. apply orb_true_iff in Hn as [Hn|Hn]. + apply orb_true_iff. left. replace (m + S k) with (S m + k) in Hn by lia. apply (IH (S m) S0 k p z); [lia | | exact Hn | exact Hin]. intros j Hj. specialize (Hwf (S j) ltac:(cbn; lia)). cbn [nth] in Hwf. replace (S m + j) with (m + S j) by lia. exact Hwf. + apply andb_true_iff in Hn as [_ Hn]. exfalso. apply Hm. replace (m + k) with (m + k) by lia. replace (m + S k) with (m + S k) in Hn by lia. apply existsb_exists in Hn as ([i z'] & Hi & E). cbn [fst] in E. apply Nat.eqb_eq in E. subst i. specialize (Hu _ _ Hi). lia. Qed. Lemma needf_step : forall vs m S0 i, needf vs m S0 i = true -> S0 i = true \/ exists k z, k < length vs /\ needf vs m S0 (m + k) = true /\ In (i, z) (tin (nth k vs tu0)). Proof. induction vs as [|u t IH]; intros m S0 i H; cbn [needf] in *; [left; exact H|]. apply orb_true_iff in H as [H|H]. - destruct (IH (S m) S0 i H) as [H0|(k & z & Hk & Hn & Hin)]; [left; exact H0|]. right. exists (S k), z. cbn [length nth]. split; [lia|]. split; [|exact Hin]. replace (m + S k) with (S m + k) by lia. rewrite Hn. reflexivity. - apply andb_true_iff in H as [H1 H2]. apply existsb_exists in H2 as ([i' z] & Hi & E). cbn [fst] in E. apply Nat.eqb_eq in E. subst i'. right. exists 0, z. cbn [length nth]. split; [lia|]. split; [|exact Hi]. rewrite Nat.add_0_r, H1. reflexivity. Qed. (* contributing to a next value: being one, or a predecessor of a unit that contributes *) Inductive contrib : nat -> Prop := | contrib_out : forall s, In s nx -> contrib s | contrib_pred : forall k s z, k < length us -> contrib (n + k) -> In (s, z) (tin (nth k us tu0)) -> contrib s. Lemma need_nx : forall s, In s nx -> need s = true. Proof. intros s H. apply needf_seed. apply existsb_exists. exists s. split; [exact H | apply Nat.eqb_refl]. Qed. Lemma need_pred : wfn -> forall k p z, k < length us -> need (n + k) = true -> In (p, z) (tin (nth k us tu0)) -> need p = true. Proof. intros Hwf k p z Hk Hn Hin. exact (needf_closed us n _ k p z Hk Hwf Hn Hin). Qed. Theorem need_contrib : wfn -> forall s, need s = true <-> contrib s. Proof. intros Hwf s. split. - (* by induction on the distance to the last signal *) assert (G : forall d s, NS - s <= d -> need s = true -> contrib s \/ NS <= s). { induction d as [|d IH]; intros s' Hd Hn. - right. lia. - destruct (needf_step us n _ s' Hn) as [H0|(k & z & Hk & Hk2 & Hin)]. + left. apply contrib_out. apply existsb_exists in H0 as (y & Hy & E). apply Nat.eqb_eq in E. subst. exact Hy. + assert (Hs : s' < n + k) by (exact (Hwf k Hk s' z Hin)). destruct (IH (n + k) ltac:(unfold NS in *; lia) Hk2) as [Hc|Hc]; [|unfold NS in Hc; lia]. left. exact (contrib_pred k s' z Hk Hc Hin). } intro Hn. destruct (Nat.lt_ge_cases s NS) as [Hl|Hg]. + destruct (G (NS - s) s (le_n _) Hn) as [Hc|Hc]; [exact Hc | lia]. + destruct (needf_step us n _ s Hn) as [H0|(k & z & Hk & _ & Hin)]. * apply contrib_out. apply existsb_exists in H0 as (y & Hy & E). apply Nat.eqb_eq in E. subst. exact Hy. * exfalso. specialize (Hwf k Hk s z Hin). unfold NS in Hg. lia. - intro Hc. induction Hc as [s Hs|k s z Hk Hc IH Hin]; [apply need_nx; exact Hs|]. exact (need_pred Hwf k s z Hk IH Hin). Qed. (* ---- the last layer that reads a signal ------------------------------------------------------------ *) Definition lam (s : nat) : nat := Nat.max (if existsb (Nat.eqb s) nx then S dmax else 0) (maxl (map (fun k => if need (n + k) && reads k s then dep (n + k) else 0) (seq 0 (length us)))). Lemma lam_nx : forall s, In s nx -> S dmax <= lam s. Proof. intros s H. unfold lam. replace (existsb (Nat.eqb s) nx) with true; [lia|]. symmetry. apply existsb_exists. exists s. split; [exact H | apply Nat.eqb_refl]. Qed. Lemma lam_reader : forall k s z, k < length us -> need (n + k) = true -> In (s, z) (tin (nth k us tu0)) -> dep (n + k) <= lam s. Proof. intros k s z Hk Hn Hin. unfold lam. apply Nat.max_le_iff. right. replace (dep (n + k)) with (if need (n + k) && reads k s then dep (n + k) else 0). - apply maxl_ge. apply in_map_iff. exists k. split; [reflexivity | apply in_seq; lia]. - rewrite Hn. replace (reads k s) with true; [reflexivity|]. symmetry. apply reads_in. exists z. exact Hin. Qed. Lemma lam_need : wfn -> forall s, 1 <= lam s -> need s = true. Proof. intros Hwf s H. unfold lam in H. destruct (existsb (Nat.eqb s) nx) eqn:E. - apply existsb_exists in E as (y & Hy & E). apply Nat.eqb_eq in E. subst. apply need_nx. exact Hy. - cbn [Nat.max] in H. destruct (maxl_pos _ H) as (a & Ha & H1). apply in_map_iff in Ha as (k & Ea & Hk). apply in_seq in Hk. destruct (need (n + k) && reads k s) eqn:F; [|lia]. apply andb_true_iff in F as [F1 F2]. apply reads_in in F2 as (z & Hin). exact (need_pred Hwf k s z ltac:(lia) F1 Hin). Qed. (* ---- the layers ----------------------------------------------------------------------------------- *) Definition isunit (l s : nat) : bool := (n <=? s) && (dep s =? l). Definition live (l s : nat) : bool := isunit l s && need s || (dep s s | _ => length (filter (live l) (seq 0 s)) end. Definition idr (p : nat) : tu := TU (-1) [(p, 1%Z)]. Definition reidx (l : nat) (u : tu) : tu := TU (tb u) (map (fun p => (pos l (fst p), snd p)) (tin u)). (* the source of a row: a copy of a signal, or a unit *) Inductive src := Cp (s : nat) | Un (s : nat). Definition srcof (l s : nat) : src := if isunit l s then Un s else Cp s. Definition srcs (l : nat) : list src := map (srcof l) (filter (live l) (seq 0 NS)). Definition srcd : list src := map (fun i => srcof dmax (nth i nx 0)) (seq 0 n). Definition mkrow (l : nat) (c : src) : tu := match c with Cp s => idr (pos (l - 1) s) | Un s => reidx (l - 1) (nth (s - n) us tu0) end. (* layers 1 .. d - 1 hold the live signals, layer d one row for each state bit *) Definition lsrc : list (nat * list src) := map (fun l => (l, srcs l)) (seq 1 (dmax - 1)) ++ [(dmax, srcd)]. Definition lev : list (list tu) := map (fun p => map (mkrow (fst p)) (snd p)) lsrc. (* ---- positions --------------------------------------------------------------------------------------- *) Lemma seq_split : forall s M, s < M -> seq 0 M = seq 0 s ++ s :: seq (S s) (M - S s). Proof. intros s M H. replace M with (s + S (M - S s)) at 1 by lia. rewrite seq_app. reflexivity. Qed. Lemma nth_filter_count : forall (f : nat -> bool) s M d, s < M -> f s = true -> nth (length (filter f (seq 0 s))) (filter f (seq 0 M)) d = s. Proof. intros f s M d Hs Hf. rewrite (seq_split s M Hs). rewrite filter_app. cbn [filter]. rewrite Hf. rewrite app_nth2 by lia. rewrite Nat.sub_diag. reflexivity. Qed. Lemma count_lt : forall (f : nat -> bool) s M, s < M -> f s = true -> length (filter f (seq 0 s)) < length (filter f (seq 0 M)). Proof. intros f s M Hs Hf. rewrite (seq_split s M Hs). rewrite filter_app, length_app. cbn [filter]. rewrite Hf. cbn [length]. lia. Qed. Lemma count_mono : forall (f : nat -> bool) a b, a <= b -> length (filter f (seq 0 a)) <= length (filter f (seq 0 b)). Proof. intros f a b H. replace b with (a + (b - a)) by lia. rewrite seq_app, filter_app, length_app. lia. Qed. Lemma pos_inj : forall l s1 s2, 1 <= l -> live l s1 = true -> live l s2 = true -> pos l s1 = pos l s2 -> s1 = s2. Proof. intros l s1 s2 Hl H1 H2 E. destruct l as [|l]; [lia|]. cbn [pos] in E. destruct (Nat.lt_trichotomy s1 s2) as [Hlt|[Heq|Hgt]]; [|exact Heq|]. - pose proof (count_lt (live (S l)) s1 s2 Hlt H1). lia. - pose proof (count_lt (live (S l)) s2 s1 Hgt H2). lia. Qed. (* ---- firing the rows ------------------------------------------------------------------------------ *) Lemma wsum_reidx : forall l ins E, wsum (map (fun p => (pos l (fst p), snd p)) ins) E = wsum ins (fun i => E (pos l i)). Proof. intros l ins E. induction ins as [|[i z] t IH]; cbn [map wsum fst snd]; [reflexivity|]. rewrite IH. reflexivity. Qed. Lemma fire_reidx : forall l u E, fire (reidx l u) E = fire u (fun i => E (pos l i)). Proof. intros l u E. unfold fire, reidx. cbn [tb tin]. rewrite wsum_reidx. reflexivity. Qed. Lemma fire_idr : forall p E, fire (idr p) E = E p. Proof. intros p E. unfold fire, idr. cbn [tb tin wsum]. destruct (E p); reflexivity. Qed. Lemma lfire_nth : forall L y r, r < length L -> nth r (lfire L y) false = fire (nth r L tu0) (fun i => nth i y false). Proof. intros L y r Hr. unfold lfire. rewrite (nth_indep _ false (fire tu0 (fun i => nth i y false))) by (rewrite length_map; exact Hr). exact (map_nth (fun u => fire u (fun i => nth i y false)) L tu0 r). Qed. (* a signal has a row in layer l, l <= d - 1 *) Definition at_layer (l s : nat) : Prop := s < NS /\ (match l with O => s < n | _ => live l s = true end). (* the predecessors of a unit of depth l + 1 that contributes, and a signal live at l + 1 or a next value of depth at most l, have rows in layer l *) Lemma pred_at : wfn -> forall l k p z, k < length us -> need (n + k) = true -> dep (n + k) = S l -> In (p, z) (tin (nth k us tu0)) -> at_layer l p. Proof. intros Hwf l k p z Hk Hn Hdk Hin. pose proof (dep_pred Hwf k p z Hk Hin) as Hlt. assert (Hp : p < NS) by (pose proof (Hwf k Hk p z Hin); unfold NS; lia). split; [exact Hp|]. destruct l as [|l]. - apply (dep_zero Hwf p Hp). lia. - unfold live. pose proof (lam_reader k p z Hk Hn Hin) as Hlam. destruct (Nat.eq_dec (dep p) (S l)) as [E|E]. + apply orb_true_iff. left. apply andb_true_iff. split; [|exact (need_pred Hwf k p z Hk Hn Hin)]. unfold isunit. apply andb_true_iff. split; [|apply Nat.eqb_eq; exact E]. apply Nat.leb_le. destruct (Nat.lt_ge_cases p n) as [Hl|Hg]; [rewrite dep_state in E by exact Hl; lia | exact Hg]. + apply orb_true_iff. right. apply andb_true_iff. split; apply Nat.ltb_lt; lia. Qed. Lemma copy_at : wfn -> forall l s, s < NS -> dep s <= l -> S l < lam s -> at_layer l s. Proof. intros Hwf l s Hs Hdl Hlam. split; [exact Hs|]. destruct l as [|l]. - apply (dep_zero Hwf s Hs). lia. - unfold live. destruct (Nat.eq_dec (dep s) (S l)) as [E|E]. + apply orb_true_iff. left. apply andb_true_iff. split; [|apply lam_need; [exact Hwf | lia]]. unfold isunit. apply andb_true_iff. split; [|apply Nat.eqb_eq; exact E]. apply Nat.leb_le. destruct (Nat.lt_ge_cases s n) as [Hl|Hg]; [rewrite dep_state in E by exact Hl; lia | exact Hg]. + apply orb_true_iff. right. apply andb_true_iff. split; apply Nat.ltb_lt; lia. Qed. Section Sem. Hypothesis Hwf : wfn. Hypothesis Hnx : Forall (fun s => s < NS) nx. Hypothesis Hlen : length nx = n. Hypothesis Hd : 1 <= dmax. Variable x : list bool. Hypothesis Hx : length x = n. Let F : nat -> bool := run us n (fun i => nth i x false). Lemma F_unit : forall k, k < length us -> F (n + k) = fire (nth k us tu0) F. Proof. intros k Hk. unfold F. apply run_at; [exact Hk | exact Hwf]. Qed. Lemma F_state : forall i, i < n -> F i = nth i x false. Proof. intros i Hi. unfold F. apply run_prefix. exact Hi. Qed. (* the outputs after the first l layers, 0 <= l <= d - 1 *) Definition yl (l : nat) : list bool := lmap (map (fun l' => map (mkrow l') (srcs l')) (seq 1 l)) x. (* firing a row from the outputs of the layer before *) Lemma fire_row : forall l (y : list bool) c, (forall s, at_layer l s -> nth (pos l s) y false = F s) -> (forall s, c = Un s -> exists k, k < length us /\ s = n + k /\ need s = true /\ dep s = S l) -> (forall s, c = Cp s -> at_layer l s) -> fire (mkrow (S l) c) (fun i => nth i y false) = F (match c with Cp s => s | Un s => s end). Proof. intros l y c Hy HU HC. destruct c as [s|s]; cbn [mkrow]; replace (S l - 1) with l by lia. - rewrite fire_idr. apply Hy. apply HC. reflexivity. - destruct (HU s eq_refl) as (k & Hk & -> & Hn & Hdk). replace (n + k - n) with k by lia. rewrite fire_reidx, F_unit by exact Hk. apply fire_ext. intros p z Hin. apply Hy. exact (pred_at Hwf l k p z Hk Hn Hdk Hin). Qed. Lemma yl_spec : forall l, l <= dmax - 1 -> length (yl l) = (match l with O => n | _ => length (filter (live l) (seq 0 NS)) end) /\ forall s, at_layer l s -> nth (pos l s) (yl l) false = F s. Proof. induction l as [|l IH]; intros Hl. - unfold yl. cbn. split; [exact Hx|]. intros s [Hs Hn]. symmetry. apply F_state. exact Hn. - destruct (IH ltac:(lia)) as [IL IY]. assert (E : yl (S l) = lfire (map (mkrow (S l)) (srcs (S l))) (yl l)). { unfold yl. rewrite seq_S, map_app. cbn [map]. replace (1 + l) with (S l) by lia. apply lmap_app. } rewrite E. unfold lfire, srcs. rewrite !length_map. split; [reflexivity|]. intros s [Hs Hlv]. cbn [pos]. fold (lfire (map (mkrow (S l)) (map (srcof (S l)) (filter (live (S l)) (seq 0 NS)))) (yl l)). pose proof (count_lt (live (S l)) s NS Hs Hlv) as Hc. rewrite lfire_nth by (rewrite !length_map; exact Hc). rewrite nth_map_d with (d' := Cp 0) by (rewrite length_map; exact Hc). rewrite nth_map_d with (d' := 0) by exact Hc. rewrite nth_filter_count by assumption. assert (Hfs : F s = F (match srcof (S l) s with Cp s' => s' | Un s' => s' end)) by (unfold srcof; destruct (isunit (S l) s); reflexivity). rewrite Hfs. apply fire_row; [exact IY | |]. + intros s' Hs'. unfold srcof in Hs'. destruct (isunit (S l) s) eqn:Hu; [|discriminate]. injection Hs' as <-. unfold isunit in Hu. apply andb_true_iff in Hu as [H1 H2]. apply Nat.leb_le in H1. apply Nat.eqb_eq in H2. exists (s - n). split; [unfold NS in Hs; lia|]. split; [lia|]. split; [|exact H2]. unfold live in Hlv. apply orb_true_iff in Hlv as [Hlv|Hlv]. * apply andb_true_iff in Hlv as [_ Hlv]. exact Hlv. * apply andb_true_iff in Hlv as [Hlv _]. apply Nat.ltb_lt in Hlv. lia. + intros s' Hs'. unfold srcof in Hs'. destruct (isunit (S l) s) eqn:Hu; [discriminate|]. injection Hs' as <-. unfold live in Hlv. rewrite Hu in Hlv. cbn [andb orb] in Hlv. apply andb_true_iff in Hlv as [H1 H2]. apply Nat.ltb_lt in H1, H2. apply (copy_at Hwf); [exact Hs | lia | lia]. Qed. Theorem lev_correct : lmap lev x = netstep n us nx x. Proof. unfold lev, lsrc. rewrite map_app. cbn [map fst snd]. rewrite lmap_app. fold (yl (dmax - 1)). destruct (yl_spec (dmax - 1) (le_n _)) as [_ IY]. unfold netstep. fold F. unfold lfire, srcd. rewrite !map_map. transitivity (map F (map (fun i => nth i nx 0) (seq 0 n))). 2: { f_equal. rewrite <- Hlen. apply map_nth_self. } rewrite map_map. apply map_ext_in. intros i Hi. apply in_seq in Hi. set (s := nth i nx 0). assert (Hs : s < NS) by (rewrite Forall_forall in Hnx; apply Hnx; apply nth_In; lia). assert (Hin : In s nx) by (apply nth_In; lia). assert (Hfs : F s = F (match srcof dmax s with Cp s' => s' | Un s' => s' end)) by (unfold srcof; destruct (isunit dmax s); reflexivity). rewrite Hfs. replace (mkrow dmax) with (mkrow (S (dmax - 1))) by (f_equal; lia). apply fire_row; [exact IY | |]. - intros s' Hs'. unfold srcof in Hs'. destruct (isunit dmax s) eqn:Hu; [|discriminate]. injection Hs' as <-. unfold isunit in Hu. apply andb_true_iff in Hu as [H1 H2]. apply Nat.leb_le in H1. apply Nat.eqb_eq in H2. exists (s - n). split; [unfold NS in Hs; lia|]. split; [lia|]. split; [apply need_nx; exact Hin | lia]. - intros s' Hs'. unfold srcof in Hs'. destruct (isunit dmax s) eqn:Hu; [discriminate|]. injection Hs' as <-. pose proof (lam_nx s Hin). pose proof (dep_le s Hs). assert (dep s <> dmax \/ s < n) as Hne. { unfold isunit in Hu. apply andb_false_iff in Hu as [Hu|Hu]; [right; apply Nat.leb_gt in Hu; exact Hu|]. left. apply Nat.eqb_neq in Hu. lia. } apply (copy_at Hwf); [exact Hs | | lia]. destruct Hne as [Hne|Hne]; [lia | rewrite dep_state by exact Hne; lia]. Qed. End Sem. (* ---- the shape of the layered map ----------------------------------------------------------------------- *) Lemma length_lev : 1 <= dmax -> length lev = dmax. Proof. intro H. unfold lev, lsrc. rewrite length_map, length_app, length_map, length_seq. cbn [length]. lia. Qed. (* the width of layer l, 0 <= l <= d - 1 *) Definition width (l : nat) : nat := match l with O => n | _ => length (filter (live l) (seq 0 NS)) end. Lemma pos_lt : forall l s, at_layer l s -> pos l s < width l. Proof. intros l s [Hs Hl]. destruct l as [|l]; cbn [pos width]; [exact Hl|]. apply count_lt; assumption. Qed. Lemma pos_inj_at : forall l s1 s2, at_layer l s1 -> at_layer l s2 -> pos l s1 = pos l s2 -> s1 = s2. Proof. intros l s1 s2 [_ H1] [_ H2] E. destruct l as [|l]; [exact E|]. apply (pos_inj (S l)); [lia | exact H1 | exact H2 | exact E]. Qed. Lemma nodup_map_inj : forall (f : nat -> nat) (P : nat -> Prop) l, NoDup l -> (forall a, In a l -> P a) -> (forall a b, P a -> P b -> f a = f b -> a = b) -> NoDup (map f l). Proof. intros f P l Hnd. induction Hnd as [|a t Ha Hnd IH]; intros HP Hinj; cbn [map]; constructor. - intro Hin. apply in_map_iff in Hin as (b & Eb & Hb). apply Ha. rewrite (Hinj b a (HP b (or_intror Hb)) (HP a (or_introl eq_refl)) Eb) in Hb. exact Hb. - apply IH; [intros b Hb; apply HP; right; exact Hb | exact Hinj]. Qed. (* a row built from a source of layer l + 1 reads distinct positions of layer l with weights -1 or 1 *) Lemma mkrow_ok : wfn -> Forall (fun u => NoDup (map fst (tin u)) /\ forall i z, In (i, z) (tin u) -> z = 1%Z \/ z = (-1)%Z) us -> forall l c, (forall s, c = Un s -> exists k, k < length us /\ s = n + k /\ need s = true /\ dep s = S l) -> (forall s, c = Cp s -> at_layer l s) -> rowok (width l) (mkrow (S l) c). Proof. intros Hwf Hus l c HU HC. destruct c as [s|s]; cbn [mkrow]; replace (S l - 1) with l by lia. - specialize (HC s eq_refl). unfold rowok, idr. cbn [tin map fst]. split; [constructor; [intros []|constructor]|]. intros i z [E|[]]. injection E as <- <-. split; [apply pos_lt; exact HC | left; reflexivity]. - destruct (HU s eq_refl) as (k & Hk & -> & Hn & Hdk). replace (n + k - n) with k by lia. rewrite Forall_forall in Hus. destruct (Hus (nth k us tu0) (nth_In _ _ Hk)) as [Hnd Hz]. unfold rowok, reidx. cbn [tin]. split. + rewrite map_map. cbn [fst]. rewrite <- (map_map fst (pos l)). apply (nodup_map_inj (pos l) (at_layer l) (map fst (tin (nth k us tu0)))); [exact Hnd | |]. * intros p Hp. apply in_map_iff in Hp as ([p' z] & <- & Hin). exact (pred_at Hwf l k p' z Hk Hn Hdk Hin). * intros a b Ha Hb E. exact (pos_inj_at l a b Ha Hb E). + intros i z Hin. apply in_map_iff in Hin as ([p z'] & E & Hin). cbn [fst snd] in E. injection E as <- <-. split; [apply pos_lt; exact (pred_at Hwf l k p z' Hk Hn Hdk Hin) | exact (Hz p z' Hin)]. Qed. Lemma srcs_spec : forall l c, In c (srcs l) -> (forall s, c = Un s -> exists k, k < length us /\ s = n + k /\ need s = true /\ dep s = l) /\ (forall s, c = Cp s -> s < NS /\ dep s < l < lam s). Proof. intros l c Hc. unfold srcs in Hc. apply in_map_iff in Hc as (s & <- & Hs). apply filter_In in Hs as [Hs Hlv]. apply in_seq in Hs. unfold srcof. destruct (isunit l s) eqn:Hu; split; intros s' E; try discriminate; injection E as <-. - unfold isunit in Hu. apply andb_true_iff in Hu as [H1 H2]. apply Nat.leb_le in H1. apply Nat.eqb_eq in H2. exists (s - n). split; [unfold NS in Hs; lia|]. split; [lia|]. split; [|exact H2]. unfold live in Hlv. apply orb_true_iff in Hlv as [Hlv|Hlv]. + apply andb_true_iff in Hlv as [_ Hlv]. exact Hlv. + apply andb_true_iff in Hlv as [Hlv _]. apply Nat.ltb_lt in Hlv. lia. - unfold live in Hlv. rewrite Hu in Hlv. cbn [andb orb] in Hlv. apply andb_true_iff in Hlv as [H1 H2]. apply Nat.ltb_lt in H1, H2. split; [lia | lia]. Qed. Lemma srcd_spec : Forall (fun s => s < NS) nx -> length nx = n -> 1 <= dmax -> forall c, In c srcd -> (forall s, c = Un s -> exists k, k < length us /\ s = n + k /\ need s = true /\ dep s = dmax) /\ (forall s, c = Cp s -> s < NS /\ dep s < dmax /\ S dmax <= lam s). Proof. intros Hnx Hlen Hd c Hc. unfold srcd in Hc. apply in_map_iff in Hc as (i & <- & Hi). apply in_seq in Hi. set (s := nth i nx 0). assert (Hs : s < NS) by (rewrite Forall_forall in Hnx; apply Hnx; apply nth_In; lia). assert (Hin : In s nx) by (apply nth_In; lia). unfold srcof. destruct (isunit dmax s) eqn:Hu; split; intros s' E; try discriminate; injection E as <-. - unfold isunit in Hu. apply andb_true_iff in Hu as [H1 H2]. apply Nat.leb_le in H1. apply Nat.eqb_eq in H2. exists (s - n). split; [unfold NS in Hs; lia|]. split; [lia|]. split; [apply need_nx; exact Hin | exact H2]. - split; [exact Hs|]. split; [|apply lam_nx; exact Hin]. pose proof (dep_le s Hs). unfold isunit in Hu. apply andb_false_iff in Hu as [Hu|Hu]. + apply Nat.leb_gt in Hu. rewrite dep_state by exact Hu. lia. + apply Nat.eqb_neq in Hu. lia. Qed. (* Lemma 2.5: the layered map has depth d, every row reads distinct rows of the layer before with weights -1 or 1, and it computes the next state of the netlist *) Theorem lev_ok : wfn -> Forall (fun s => s < NS) nx -> length nx = n -> 1 <= dmax -> Forall (fun u => NoDup (map fst (tin u)) /\ forall i z, In (i, z) (tin u) -> z = 1%Z \/ z = (-1)%Z) us -> length lev = dmax /\ lwf n lev /\ length (last lev []) = n /\ forall x, length x = n -> lmap lev x = netstep n us nx x. Proof. intros Hwf Hnx Hlen Hd Hus. split; [apply length_lev; exact Hd|]. split; [|split]. - (* layer l + 1 reads layer l *) assert (G : forall m, m <= dmax - 1 -> lwf (width m) (map (fun p => map (mkrow (fst p)) (snd p)) (map (fun l => (l, srcs l)) (seq (S m) (dmax - 1 - m)) ++ [(dmax, srcd)]))). { intros m Hm. remember (dmax - 1 - m) as c eqn:Ec. revert m Hm Ec. induction c as [|c IH]; intros m Hm Ec. - cbn [seq map app lwf fst snd]. split; [|exact I]. apply Forall_forall. intros r Hr. apply in_map_iff in Hr as (c & <- & Hc). destruct (srcd_spec Hnx Hlen Hd c Hc) as [HU HC]. replace dmax with (S m) by lia. apply mkrow_ok; [exact Hwf | exact Hus | |]. + intros s E. destruct (HU s E) as (k & Hk & Es & Hn & Hdk). exists k. repeat split; try assumption. lia. + intros s E. destruct (HC s E) as (Hs & Hdl & Hlam). apply copy_at; [exact Hwf | exact Hs | lia | lia]. - cbn [seq map app lwf fst snd]. split. + apply Forall_forall. intros r Hr. apply in_map_iff in Hr as (c' & <- & Hc). destruct (srcs_spec (S m) c' Hc) as [HU HC]. apply mkrow_ok; [exact Hwf | exact Hus | exact HU |]. intros s E. destruct (HC s E) as (Hs & Hdl & Hlam). apply copy_at; [exact Hwf | exact Hs | lia | lia]. + rewrite length_map. unfold srcs. rewrite length_map. replace (length (filter (live (S m)) (seq 0 NS))) with (width (S m)) by reflexivity. apply IH; lia. } specialize (G 0 ltac:(lia)). unfold lev, lsrc. replace (dmax - 1) with (dmax - 1 - 0) by lia. exact G. - unfold lev, lsrc. rewrite map_app. cbn [map fst snd]. rewrite last_last. unfold srcd. rewrite !length_map, length_seq. reflexivity. - intros x Hx. apply lev_correct; assumption. Qed. (* every row is an identity unit H(x - 1) or a unit of the netlist with its bias and weights *) Theorem lev_rows : forall l cs c, In (l, cs) lsrc -> In c cs -> match c with | Cp s => exists p, mkrow l c = idr p | Un s => tb (mkrow l c) = tb (nth (s - n) us tu0) /\ map snd (tin (mkrow l c)) = map snd (tin (nth (s - n) us tu0)) end. Proof. intros l cs c _ _. destruct c as [s|s]; cbn [mkrow]. - eexists. reflexivity. - unfold reidx. cbn [tb tin]. split; [reflexivity|]. rewrite map_map. reflexivity. Qed. (* the occurrences of unit s among the rows *) Definition isun (s : nat) (c : src) : bool := match c with Un s' => Nat.eqb s' s | Cp _ => false end. Lemma length_filter_map : forall (A B : Type) (p : B -> bool) (f : A -> B) (L : list A), length (filter p (map f L)) = length (filter (fun a => p (f a)) L). Proof. intros A B p f L. induction L as [|a t IH]; cbn [map filter]; [reflexivity|]. destruct (p (f a)); cbn [length]; lia. Qed. Lemma length_filter_filter : forall (A : Type) (p q : A -> bool) (L : list A), length (filter p (filter q L)) = length (filter (fun a => q a && p a) L). Proof. intros A p q L. induction L as [|a t IH]; [reflexivity|]. cbn [filter]. destruct (q a); cbn [andb filter]; [destruct (p a); cbn [length]; lia | exact IH]. Qed. Lemma filter_eqb_seq : forall (g : nat -> bool) M s, s < M -> length (filter (fun s' => g s' && Nat.eqb s' s) (seq 0 M)) = if g s then 1 else 0. Proof. intros g M s Hs. rewrite (seq_split s M Hs), filter_app, length_app. cbn [filter]. rewrite Nat.eqb_refl, andb_true_r. assert (Z : forall a k, (a > s \/ a + k <= s) -> length (filter (fun s' => g s' && Nat.eqb s' s) (seq a k)) = 0). { intros a k Hak. revert a Hak. induction k as [|k IH]; intros a Hak; [reflexivity|]. cbn [seq filter]. destruct (Nat.eqb_spec a s); [lia|]. rewrite andb_false_r. apply IH. lia. } rewrite (Z 0 s) by lia. destruct (g s); cbn [length]; rewrite (Z (S s) (M - S s)) by lia; reflexivity. Qed. Lemma count_srcs : forall l s, s < NS -> length (filter (isun s) (srcs l)) = if isunit l s && need s then 1 else 0. Proof. intros l s Hs. unfold srcs. rewrite length_filter_map, length_filter_filter. rewrite (filter_ext _ (fun a => (live l a && isunit l a) && Nat.eqb a s)). - rewrite filter_eqb_seq by exact Hs. destruct (isunit l s) eqn:Hu. + unfold live. rewrite Hu. unfold isunit in Hu. apply andb_true_iff in Hu as [_ Hu]. apply Nat.eqb_eq in Hu. rewrite Hu, Nat.ltb_irrefl. destruct (need s); reflexivity. + rewrite andb_false_r. reflexivity. - intro a. unfold srcof. destruct (isunit l a); cbn [isun]; [rewrite andb_true_r; reflexivity|]. rewrite !andb_false_r. reflexivity. Qed. Lemma count_map_srcof : forall d s (L : list nat), length (filter (fun a => isun s (srcof d a)) L) = if isunit d s then length (filter (fun a => Nat.eqb a s) L) else 0. Proof. intros d s L. induction L as [|a t IH]; [destruct (isunit d s); reflexivity|]. cbn [filter]. destruct (Nat.eqb_spec a s) as [->|E]. - assert (Hs : isun s (srcof d s) = isunit d s) by (unfold srcof; destruct (isunit d s); cbn [isun]; [apply Nat.eqb_refl | reflexivity]). rewrite Hs. destruct (isunit d s) eqn:Hu. + cbn [length]. rewrite IH. reflexivity. + exact IH. - assert (Hf : isun s (srcof d a) = false) by (unfold srcof; destruct (isunit d a); cbn [isun]; [apply Nat.eqb_neq; exact E | reflexivity]). rewrite Hf. exact IH. Qed. Lemma count_srcd : length nx = n -> forall s, length (filter (isun s) srcd) = if isunit dmax s then length (filter (fun a => Nat.eqb a s) nx) else 0. Proof. intros Hlen s. unfold srcd. rewrite <- (map_map (fun i => nth i nx 0) (srcof dmax)). rewrite <- Hlen, map_nth_self, length_filter_map. apply count_map_srcof. Qed. Lemma length_filter_concat : forall (A : Type) (p : A -> bool) (L : list (list A)), length (filter p (concat L)) = fold_right Nat.add 0 (map (fun l => length (filter p l)) L). Proof. intros A p L. induction L as [|l t IH]; [reflexivity|]. cbn [concat map fold_right]. rewrite filter_app, length_app, IH. reflexivity. Qed. Lemma sum_indicator : forall x a k, fold_right Nat.add 0 (map (fun l => if Nat.eqb x l then 1 else 0) (seq a k)) = if (a <=? x) && (x |E]. + rewrite Nat.leb_refl. destruct (Nat.leb_spec (S a) a); [lia|]. cbn [andb]. destruct (Nat.ltb_spec a (a + S k)); lia. + destruct (Nat.leb_spec (S a) x), (Nat.ltb_spec x (S a + k)), (Nat.leb_spec a x), (Nat.ltb_spec x (a + S k)); cbn [andb]; lia. Qed. Lemma sum_zero : forall (L : list nat) (f : nat -> nat), (forall l, In l L -> f l = 0) -> fold_right Nat.add 0 (map f L) = 0. Proof. intros L f H. induction L as [|a t IH]; [reflexivity|]. cbn [map fold_right]. rewrite (H a (or_introl eq_refl)), IH by (intros l Hl; apply H; right; exact Hl). reflexivity. Qed. Lemma filter_none : forall (L : list nat) s, (forall a, In a L -> a <> s) -> length (filter (fun a => Nat.eqb a s) L) = 0. Proof. intros L s H. induction L as [|a t IH]; [reflexivity|]. cbn [filter]. destruct (Nat.eqb_spec a s) as [E|E]; [exfalso; exact (H a (or_introl eq_refl) E)|]. apply IH. intros b Hb. apply H. right. exact Hb. Qed. (* each unit that contributes occurs once if its depth is less than d and once for each state bit whose next value it is if its depth is d; no other unit occurs *) Theorem lev_units : wfn -> length nx = n -> forall s, n <= s < NS -> length (filter (isun s) (concat (map snd lsrc))) = if need s then (if dep s Nat.eqb a s) nx)) else 0. Proof. intros Hwf Hlen s Hs. unfold lsrc. rewrite map_app, concat_app, filter_app, length_app, map_map. cbn [map snd concat]. rewrite app_nil_r, count_srcd by exact Hlen. rewrite length_filter_concat, map_map. pose proof (dep_unit_pos Hwf (s - n) ltac:(unfold NS in Hs; lia)) as Hpos. replace (n + (s - n)) with s in Hpos by lia. pose proof (dep_le s (proj2 Hs)) as Hle. assert (Hu : forall l, isunit l s = Nat.eqb (dep s) l) by (intro l; unfold isunit; destruct (Nat.leb_spec n s); [reflexivity | lia]). rewrite Hu. destruct (need s) eqn:Hn. - rewrite (map_ext_in _ (fun l => if Nat.eqb (dep s) l then 1 else 0)). 2: { intros l Hl. rewrite count_srcs by lia. rewrite Hu, Hn, andb_true_r. reflexivity. } rewrite sum_indicator. destruct (Nat.ltb_spec (dep s) dmax) as [Hlt|Hge]. + replace ((1 <=? dep s) && (dep s map (@length tu) lev = map width (seq 1 (dmax - 1)) ++ [n]. Proof. intro Hlen. unfold lev, lsrc. rewrite map_app, map_app, !map_map. cbn [map fst snd]. f_equal. - apply map_ext_in. intros l Hl. apply in_seq in Hl. unfold srcs. rewrite !length_map. destruct l as [|l]; [lia | reflexivity]. - unfold srcd. rewrite !length_map, length_seq. reflexivity. Qed. (* the size of the layered map: its rows are those of the layers 1 .. d - 1 and one for each state bit *) Theorem lev_size : length nx = n -> fold_right Nat.add 0 (map (@length tu) lev) = fold_right Nat.add 0 (map width (seq 1 (dmax - 1))) + n. Proof. intro Hlen. unfold lev, lsrc. rewrite map_app, map_app, fold_right_app, !map_map. cbn [map fold_right fst snd]. unfold srcd. rewrite !length_map, length_seq. assert (G : forall (L : list nat) c, (forall l, In l L -> 1 <= l) -> fold_right Nat.add c (map (fun l => length (map (mkrow l) (srcs l))) L) = fold_right Nat.add 0 (map width L) + c). { intros L c HL. induction L as [|a t IH]; [reflexivity|]. cbn [map fold_right]. rewrite IH by (intros l Hl; apply HL; right; exact Hl). unfold srcs. rewrite !length_map. destruct a as [|a]; [specialize (HL 0 (or_introl eq_refl)); lia|]. cbn [width]. lia. } rewrite G by (intros l Hl; apply in_seq in Hl; lia). lia. Qed. End Lev.