1+ (***************************************************************************** *)
2+ (* *)
3+ (* *)
4+ (* Proof of Hermite's identity *)
5+ (* *)
6+ (* `⌊x⌋ : floor function *)
7+ (* `⌈x⌋ : nearest-int function with `⌈ n + 1/2 ⌋ = n + 1 *)
8+ (* *)
9+ (* hermite's identity : `⌊nx⌋ = \sum_(k < n) `⌊x + k / n⌋ *)
10+ (* *)
11+ (* special case when n = 2 : `⌊2x⌋ - `⌊x⌋ = `⌈x⌋ *)
12+ (***************************************************************************** *)
13+
14+ From mathcomp Require Import all_boot all_order all_algebra.
15+
16+ Local Open Scope ring_scope.
17+
18+ Import GRing.Theory Num.Theory Order.TTheory.
19+
20+ Section Hermite.
21+
22+ Variable R : archiRealFieldType.
23+
24+ Local Notation " `⌊ x ⌋ " := ((Num.floor x)%:~R) (format "`⌊ x ⌋" ).
25+
26+ Definition frac_part (x : R) := x - `⌊ x ⌋.
27+
28+ Local Notation " `{ x } " := (frac_part x) (format "`{ x }" ).
29+
30+ Lemma fracE (x : R) : x = `⌊x⌋ + `{x}.
31+ Proof . by rewrite /frac addrC subrK. Qed .
32+
33+ Lemma frac_le (x : R) : 0 <= `{x} < 1.
34+ Proof . by rewrite subr_ge0 ltrBlDl floor_le -(intrD _ _ 1) floorD1_gt. Qed .
35+
36+ Definition half_up (x : R) : R := `⌊x + 2^-1⌋.
37+
38+ Local Notation " `⌈ x ⌋ " := (half_up x) (format "`⌈ x ⌋" ).
39+
40+ Lemma half_up_le x : `⌊x⌋ <= `⌈x⌋.
41+ Proof .
42+ rewrite ler_int; apply: le_floor.
43+ by rewrite -[X in X <= _]addr0 lerD2l invr_ge0 (ler_nat _ 0 2).
44+ Qed .
45+
46+ Lemma half_up_gt x : `⌈x⌋ <= `⌊x⌋ + 1.
47+ Proof .
48+ rewrite -(intrD _ _ 1) -(floor1 R) -floorDrz // ler_int; apply: le_floor.
49+ by rewrite lerD2l invf_le1 // (ler_nat _ 1 2).
50+ Qed .
51+
52+ Inductive half_up_build (x : R) : R -> Prop :=
53+ half_up_build_floor : x < `⌊x⌋ + 2^-1 -> half_up_build x `⌊x⌋
54+ | half_up_build_ceil : `⌊x⌋ + 2^-1 <= x -> half_up_build x (`⌊x⌋ + 1)%R.
55+
56+ Lemma half_upP x : half_up_build x `⌈x⌋.
57+ Proof .
58+ have [xLx2|x2Lx] := leP (`⌊x⌋ + 2^-1) x; last first.
59+ suff -> : `⌈x⌋ = `⌊x⌋ by apply/half_up_build_floor.
60+ suff x2E : Num.floor (x + 2^-1) = Num.floor x.
61+ by congr (_%:~R); apply/sym_equal/eqP; rewrite floor_eq x2E floor_itv.
62+ apply/floor_def.
63+ rewrite intrD (le_trans (floor_le _) _) //=; last first.
64+ by rewrite lerDl invr_ge0 (ler_nat _ 0 2).
65+ by rewrite [1%:~R]splitr mul1r addrA ltrD2r.
66+ suff -> : `⌈x⌋ = `⌊x⌋ + 1 by apply/half_up_build_ceil.
67+ suff x2E : Num.floor (x + 2^-1) = Num.floor x + 1
68+ by rewrite /half_up x2E intrD.
69+ apply/floor_def.
70+ rewrite 2!intrD [1%:~R]splitr mul1r addrA lerD2r xLx2 /= addrA ltrD2r.
71+ by rewrite (lt_le_trans (floorD1_gt _)) // lerDl invr_ge0 (ler_nat _ 0 2).
72+ Qed .
73+
74+ Lemma half_up_half : `⌈2^-1⌋ = 1.
75+ Proof .
76+ by have := splitr (1 : R); rewrite mul1r /half_up => <-; rewrite floorK.
77+ Qed .
78+
79+ Lemma half_up_nearest (x : R) (y : int ): `|x - `⌈x⌋| <= `|x - y%:~R|.
80+ Proof .
81+ have [yLx|xLy] := leP y (Num.floor x).
82+ suff F : `|x - `⌈x⌋| <= `|x - `⌊x⌋|.
83+ apply: le_trans F _.
84+ rewrite !ger0_norm ?subr_ge0 ?floor_le //; first by rewrite lerB ?ler_int.
85+ by rewrite (le_trans _ (floor_le _)) // ler_int.
86+ have [//|xLx2] := half_upP.
87+ rewrite [X in _ <= X]ger0_norm; last by rewrite subr_ge0 floor_le.
88+ rewrite ler0_norm; last first.
89+ by rewrite subr_le0; have /ltW := floorD1_gt x; rewrite intrD.
90+ rewrite opprB.
91+ apply: le_trans (_ : 2^-1 <= _); last by rewrite lerBrDl.
92+ rewrite addrAC [X in _ + X <= _]splitr -[X in _ <= X]add0r mul1r addrA.
93+ by rewrite lerD2r addrAC lerBlDl addr0.
94+ rewrite -lezD1 in xLy.
95+ rewrite [X in _ <= X]ler0_norm ?opprB; last first.
96+ by rewrite subr_le0 (le_trans (ltW (floorD1_gt _))) // ler_int.
97+ suff F : `|x - `⌈x⌋| <= `|x - `⌊x + 1⌋|.
98+ apply: le_trans F _.
99+ rewrite ler0_norm ?opprB; last first.
100+ by rewrite subr_le0 floorDrz // floor1 (ltW (floorD1_gt _)).
101+ by rewrite lerD2r floorDrz // floor1 ler_int.
102+ have [xLx2|x2Lx] := half_upP; last by rewrite floorDrz // floor1 intrD.
103+ rewrite [X in _ <= X]ler0_norm ?opprB; last first.
104+ by rewrite subr_le0 floorDrz // floor1 (ltW (floorD1_gt _)).
105+ have xLx2' := ltW xLx2.
106+ rewrite ger0_norm; last by rewrite subr_ge0 floor_le.
107+ apply: le_trans (_ : 2^-1 <= _); first by rewrite lerBlDl.
108+ rewrite floorDrz // floor1 intrD addrAC.
109+ rewrite [X in _ <= _ + X]splitr -[X in X <= _]add0r mul1r addrA lerD2r.
110+ by rewrite addrAC subr_ge0.
111+ Qed .
112+
113+ Lemma hermite_id (n : nat) x :
114+ `⌊n%:R * x⌋ = \sum_(k < n) (`⌊x + k%:R / (n%:R:R)⌋ : R).
115+ Proof .
116+ have [//|n_gt0|->] := ltngtP n 0; last by rewrite big_ord0 mul0r floor0.
117+ have n_neq0 : n%:R != 0 :> R by rewrite (eqr_nat _ _ 0); case: (n) n_gt0.
118+ have nr_nt0 : (0 : R) < n%:R by rewrite (ltr_nat _ 0).
119+ pose g (k : nat) : R := `⌊x + k%:R / (n%:R : R)⌋.
120+ rewrite -(@big_mkord _ _ _ _ xpredT g) {}/g.
121+ rewrite (fracE x) mulrDr addrC -(intrM _ (Posz n)) floorDrz // intrD.
122+ rewrite [X in _ + X = _]floorK // intrM.
123+ under eq_bigr do rewrite -addrA addrC floorDrz // intrD.
124+ rewrite big_split /=.
125+ rewrite sumr_const_nat subn0.
126+ rewrite [in X in _ = _ + X]floorK // [X in _ + X = _]mulr_natl.
127+ suff <- : `⌊n%:R * `{ x}⌋ = (\sum_(0 <= i < n) `⌊`{ x} + i%:R / n%:R⌋ : R).
128+ by [].
129+ have /andP[x_ge0 x_lt1] := frac_le x.
130+ pose fnx := Num.floor (n%:R * `{x}).
131+ have fnx_pos : 0 <= fnx by rewrite floor_ge0 mulr_ge0.
132+ have fnxLn : (`|fnx| <= n)%N.
133+ rewrite -lez_nat intOrdered.gez0_norm //.
134+ rewrite -(ler_int R) (le_trans (floor_le _)) //.
135+ by rewrite -[X in _ <= X]mulr1 ler_pM // ltW.
136+ pose t := (n - `|fnx|)%N.
137+ pose cnx := Num.ceil (n%:R * (1 - `{x})).
138+ have cnx_pos : 0 <= cnx.
139+ by rewrite ceil_ge0 (lt_le_trans (ltrN10 R)) // mulr_ge0 // subr_ge0 ltW.
140+ have nLcnx : (`|cnx| <= n)%N.
141+ rewrite -(ler_nat R) natr_absz ger0_norm //.
142+ have /le_ceil : n%:R * (1 - `{x}) <= n%:R.
143+ by rewrite mulrBr mulr1 gerBl mulr_ge0.
144+ rewrite -/cnx -(ler_int R) //.
145+ suff /eqP->// : (Num.Def.ceil (n%:R : R))%:~R == (n%:R : R) by [].
146+ by rewrite -intrEceil.
147+ have tE : t = (`|cnx| : nat).
148+ rewrite /cnx mulrBr mulr1 addrC ceilDrz // ceilNfloor opprK addrC.
149+ have -> : Num.Def.ceil (n%:R : R) = (n : int).
150+ by apply/eqP; rewrite -(eqr_int R) -intrEceil.
151+ by rewrite -[LHS]distnEl ?intOrdered.gez0_norm.
152+ rewrite (big_cat_nat_idem _ (_ : 0 <= t)%N) //=; last 2 first.
153+ - by rewrite add0r.
154+ - by rewrite leq_subr.
155+ rewrite big_nat_cond /= big1 ?add0r => [|i iLt]; last first.
156+ rewrite andbT tE in iLt.
157+ have iLt' : (i%:~R < n%:R * (1 - `{x})).
158+ rewrite -real_ceil_gt_int; last by rewrite !realE mulr_ge0 // subr_ge0 ltW.
159+ by rewrite -ltz_nat // intOrdered.gez0_norm in iLt.
160+ have -> : 0 = 0%:~R :>R by [].
161+ congr (_%:~R); apply: floor_def.
162+ rewrite add0r addr_ge0 //=; last by rewrite divr_ge0.
163+ rewrite -[`{x}](mulfK n_neq0) -mulrDl ltr_pdivrMr // mul1r.
164+ by rewrite -ltrBrDl -[X in _ < X - _]mul1r -mulrBl mulrC.
165+ rewrite big_nat_cond (eq_bigr (fun _ => 1%R)).
166+ rewrite -big_nat_cond sumr_const_nat natrB ?tE //.
167+ rewrite -tE natrB ?opprB //.
168+ by rewrite addrC subrK natr_absz ger0_norm.
169+ move=> i; rewrite andbT => /andP[tLi iLn].
170+ rewrite tE in tLi.
171+ rewrite -[RHS]/(1%:~R).
172+ congr (_%:~R); apply: floor_def; apply/andP; split.
173+ rewrite -[`{x}](mulfK n_neq0) -mulrDl ler_pdivlMr // mul1r.
174+ rewrite -lerBlDl -[X in X - _ <= _]mul1r -mulrBl mulrC.
175+ rewrite (le_trans (ceil_ge _)) -/cnx //.
176+ by rewrite -(ler_nat R) natr_absz ger0_norm in tLi.
177+ rewrite intrD (le_lt_trans (_ : _ <= `{x} + 1)) //.
178+ by rewrite lerD // ler_pdivrMr // mul1r ler_nat ltnW.
179+ by rewrite ltr_leD.
180+ Qed .
181+
182+ Lemma hermite_id2 x : `⌊2 * x⌋ - `⌊x⌋ = `⌈x⌋.
183+ Proof .
184+ rewrite hermite_id big_ord_recr /= big_ord1 mul0r addr0.
185+ by rewrite mul1r /half_up addrAC subrr add0r.
186+ Qed .
187+
188+ End Hermite.
0 commit comments