Skip to content

Conversation

@IshiguroYoshihiro
Copy link
Contributor

Motivation for this change

Add a part of generalized version of integration by parts for unbound intervals `[a, +oo[.
This PR is over #1656 and #1662.
I don't sure that I should add 4 more lemmas and complete all variation of integration by parts for unbound intervals.
I think that 8 similar lemmas would be a mess. So, I'd like to somehow make them up into one or two lemmas, but I don't have an idea.

Checklist
  • added corresponding entries in CHANGELOG_UNRELEASED.md
  • added corresponding documentation in the headers

Reference: How to document

Merge policy

As a rule of thumb:

  • PRs with several commits that make sense individually and that
    all compile are preferentially merged into master.
  • PRs with disorganized commits are very likely to be squash-rebased.
Reminder to reviewers

@Tragicus
Copy link
Collaborator

Are not all 4 versions the same, the only difference being whether the minus is inside or outside the integral?

@IshiguroYoshihiro
Copy link
Contributor Author

Are not all 4 versions the same, the only difference being whether the minus is inside or outside the integral?

If you said that these lemmas can be proved with one of them, I think it is no.
As you can see, the version of le0_ge0 and le0_le0 can be proved with ge0_ge0 or ge0_le0, but ge0_le0 can not proved from ge0_ge0.
Because that integration by substitusion using a transformation F -> F \o -%R change the unbounded side of the interval from `[a, +oo[ to `[-oo, - a[, I may have to set 4 more variations of this lemma for `[-oo, -a[.
It will makes messy for the use to set 8 variation of the lemma. So I will consider some good way.

@affeldt-aist affeldt-aist force-pushed the integration_by_partsy_20250704 branch from 949b179 to 0802b9c Compare October 30, 2025 07:07
@affeldt-aist affeldt-aist marked this pull request as ready for review October 30, 2025 09:32
@affeldt-aist
Copy link
Member

Are not all 4 versions the same, the only difference being whether the minus is inside or outside the integral?

Indeed le0_le0 is the same as ge0_ge0 (and it is proved as such).
Similarly, for ge0_le0 vs. le0_ge0.
I don't think we can have more sharing.
Do you think that we should work towards a general version? A single lemma encompassing them all?

@affeldt-aist
Copy link
Member

Are not all 4 versions the same, the only difference being whether the minus is inside or outside the integral?

Indeed le0_le0 is the same as ge0_ge0 (and it is proved as such). Similarly, for ge0_le0 vs. le0_ge0. I don't think we can have more sharing. Do you think that we should work towards a general version? A single lemma encompassing them all?

To give a bit of context, these lemmas have been written this way after having been tested to formalize the Gamma function. Maybe their apparent specialization is the result of practical considerations? @IshiguroYoshihiro can you confirm? (Or am I remembering wrong?)

Copy link
Collaborator

@Tragicus Tragicus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I am back.
One way to factorize would be to ask for the relevant functions to have constant sign. I was also wondering whether we want to generalize over the interval, instead of [a, +oo[. We would require that the relevant functions are derivable on the interior of the interval and have limits at the boundaries.
@affeldt-aist Some of the following suggestions are quite ugly but save a lot of time, what do you think?

theories/ftc.v Outdated
Comment on lines 1105 to 1111
rewrite (@integration_by_partsy_le0_ge0 R (- F)%R G (- f)%R g a (- FGoo))//.
- rewrite oppeD; last exact: fin_num_adde_defr.
rewrite -EFinN opprD 2!opprK mulNr.
by under eq_integral do rewrite mulNr EFinN oppeK.
- by move=> ?; apply: cvgN; exact: cf.
- exact: derivable_oy_continuous_bndN.
- by move=> ? ?; rewrite fctE derive1N ?Ff//; move: Foy => [+ _]; apply.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
rewrite (@integration_by_partsy_le0_ge0 R (- F)%R G (- f)%R g a (- FGoo))//.
- rewrite oppeD; last exact: fin_num_adde_defr.
rewrite -EFinN opprD 2!opprK mulNr.
by under eq_integral do rewrite mulNr EFinN oppeK.
- by move=> ?; apply: cvgN; exact: cf.
- exact: derivable_oy_continuous_bndN.
- by move=> ? ?; rewrite fctE derive1N ?Ff//; move: Foy => [+ _]; apply.
rewrite (@integration_by_partsy_le0_ge0 R (- F)%R G (- f)%R g a (- FGoo))//.
- rewrite oppeD; last exact: fin_num_adde_defr.
rewrite -EFinN opprD 2!opprK mulNr.
by under eq_integral do rewrite mulNr EFinN oppeK.
- by move=> ?; apply: cvgN; exact: cf.
- exact: derivable_oy_continuous_bndN.
- by move=> ? ?; rewrite fctE derive1N ?Ff => [//|//|]; apply: Foy.1.

.6s faster

@affeldt-aist affeldt-aist added this to the 1.15.0 milestone Nov 4, 2025
@affeldt-aist affeldt-aist added the enhancement ✨ This issue/PR is about adding new features enhancing the library label Nov 4, 2025
affeldt-aist and others added 18 commits November 18, 2025 11:01
Co-authored-by: Quentin VERMANDE <quentin.vermande@orange.fr>
Co-authored-by: Quentin VERMANDE <quentin.vermande@orange.fr>
Co-authored-by: Quentin VERMANDE <quentin.vermande@orange.fr>
Co-authored-by: Quentin VERMANDE <quentin.vermande@orange.fr>
Co-authored-by: Quentin VERMANDE <quentin.vermande@orange.fr>
Co-authored-by: Quentin VERMANDE <quentin.vermande@orange.fr>
Co-authored-by: Quentin VERMANDE <quentin.vermande@orange.fr>
Co-authored-by: Quentin VERMANDE <quentin.vermande@orange.fr>
Co-authored-by: Quentin VERMANDE <quentin.vermande@orange.fr>
Co-authored-by: Quentin VERMANDE <quentin.vermande@orange.fr>
Co-authored-by: Quentin VERMANDE <quentin.vermande@orange.fr>
Co-authored-by: Quentin VERMANDE <quentin.vermande@orange.fr>
Co-authored-by: Quentin VERMANDE <quentin.vermande@orange.fr>
Co-authored-by: Quentin VERMANDE <quentin.vermande@orange.fr>
Co-authored-by: Quentin VERMANDE <quentin.vermande@orange.fr>
Co-authored-by: Quentin VERMANDE <quentin.vermande@orange.fr>
Co-authored-by: Quentin VERMANDE <quentin.vermande@orange.fr>
Co-authored-by: Quentin VERMANDE <quentin.vermande@orange.fr>
Co-authored-by: Quentin VERMANDE <quentin.vermande@orange.fr>
@IshiguroYoshihiro IshiguroYoshihiro mentioned this pull request Nov 18, 2025
2 tasks
@affeldt-aist
Copy link
Member

To give a bit of context, these lemmas have been written this way after having been tested to formalize the Gamma function.

FYI, here is the PR that formalizes the Gamma function:
#1762

One way to factorize would be to ask for the relevant functions to have constant sign. I was also wondering whether we want to generalize over the interval, instead of [a, +oo[. We would require that the relevant functions are derivable on the interior of the interval and have limits at the boundaries.

This has not been tested yet (by lack of time). :-(

Some of the following suggestions are quite ugly but save a lot of time, what do you think?

We have merged all of them. Thanks for identifying the performance issues, that helps.

@t6s
Copy link
Member

t6s commented Dec 11, 2025

I suggest keeping 4 lemmas as is, and additionally, provide a unified interface lemma that use the constant_sign predicate

@affeldt-aist affeldt-aist force-pushed the integration_by_partsy_20250704 branch from 5036126 to 34697b2 Compare January 13, 2026 07:34
@t6s
Copy link
Member

t6s commented Jan 13, 2026

looking at the code for a while, I noticed there can be some helper lemmas added:

Lemma seqDU0 : forall {T : Type} (F : (set T)^nat), seqDU F 0%N = F 0%N.
Proof. by move=> ? ?; rewrite /seqDU/= big_ord0 setD0. Qed.

Lemma seqDU1_itv : forall {R : realDomainType} (r : R) b1 b2,
  seqDU (fun n => [set` Interval (BSide b1 r) (BSide b2 (r + n%:R))]) 1 =
  [set` Interval (BSide (b1 && b2) r) (BSide b2 (r + 1%:R))].
Proof.
move=> ? r b1 b2.
rewrite /seqDU big_ord1/= addr0 setDE.
case: b1; case: b2; rewrite (set_itvco0,set_itv1,set_itvoo0,set_itvoc0) ?setC0 ?setIT//.
by rewrite -setDE setDitv1l.
Qed.

Lemma seqDUSn_itv_notoo : forall {R : realDomainType} n (r : R) b1 b2,
  (b1 == true) || (b2 == false) -> (* not a seqDU of open intervals *)
  seqDU (fun n => [set` Interval (BSide b1 r) (BSide b2 (r + n%:R))]) n.+1 =
  [set` Interval (BSide b2 (r + n%:R)) (BSide b2 (r + n.+1%:R))].
Proof.
move=> ? n r b1 b2 b12.
rewrite seqDU_seqD; last first.
  apply/nondecreasing_seqP => k; apply/subsetPset/subset_itvl.
  by rewrite bnd_simp lerD2l ler_nat.
rewrite eqEsubset; split => x /= /[!in_itv] /=.
  move=> [] /andP[-> ->] /[!andbT] /= /negP.
  clear b12.
  by case: b1; case: b2; rewrite /= -?ltNge -?leNgt.
move=> /andP[rnx ->]; rewrite andbT; split.
  move: b12.
  case: b1 => /=.
    by move=> _; have/lteifW/(le_trans _) := rnx; apply; rewrite lerDl.
  by move: rnx; case: b2 => //= + _  => /(le_lt_trans _); apply; rewrite lerDl.
by apply/negP; rewrite negb_and [X in _ || X]lteifN ?negbK// orbT.
Qed.

Lemma seqDUSSn_itv : forall {R : realDomainType} n (r : R) b1 b2,
  seqDU (fun n => [set` Interval (BSide b1 r) (BSide b2 (r + n%:R))]) n.+2 =
  [set` Interval (BSide b2 (r + n.+1%:R)) (BSide b2 (r + n.+2%:R))].
Proof.
move=> ? n r b1 b2.
case/boolP: ((b1 == true) || (b2 == false)); first by move/seqDUSn_itv_notoo.
case: b1; case: b2 => // _.
rewrite seqDU_seqD; last first.
  apply/nondecreasing_seqP => k; apply/subsetPset/subset_itvl.
  by rewrite bnd_simp lerD2l ler_nat.
rewrite eqEsubset; split => x /= /[!in_itv] /=.
  by move=> [] /andP[-> ->] /[!andbT] /= /negP; rewrite -leNgt.
move=> /andP[rnx ->].
rewrite andbT; split; first by rewrite (lt_le_trans _ rnx)// ltrDl.
by apply/negP; rewrite negb_and -!leNgt rnx orbT.
Qed.

Lemma set_itv_Sset1 :
  forall [disp : Order.disp_t] [T : porderType disp] (x : T) b1 b2 ,
    [set` Interval (BSide b1 x) (BSide b2 x)] `<=` [set x].
Proof.
move=> ? ? ? b1 b2.
by case: b1; case: b2; rewrite (set_itv1,set_itvoo0,set_itvxx).
Qed.

Lemma seqDUn_sSet_itvcc : forall {R : realDomainType} n (r : R) b1 b2,
  seqDU (fun n => [set` Interval (BSide b1 r) (BSide b2 (r + n%:R))]) n `<=`
    `[r + n.-1%:R, r + n%:R].
Proof.
move=> ? n r b1 b2.
case: n => [|n /=].
  by rewrite seqDU0 addr0; apply: subset_itvScc; rewrite bnd_simp.
case: n => [|n /=].
  by rewrite seqDU1_itv addr0; apply: subset_itvScc; rewrite bnd_simp.
by rewrite seqDUSSn_itv; apply: subset_itvScc; rewrite bnd_simp.
Qed.

(* generalizations of lemmas of the same names *)
Lemma integral_itv_obnd_cbnd :
  forall {R : realType} [r : R] [b : itv_bound R] [f : R -> R] lr,
    measurable_fun [set` Interval (BRight r) b] f ->
    \int[mu]_(x in [set` Interval (BSide lr r) b]) (f x)%:E =
    \int[mu]_(x in [set` Interval (BLeft r) b]) (f x)%:E.
Proof. by move=> ? ? ? ?; case; [by []|exact: integral_itv_obnd_cbnd]. Qed.

Lemma integral_itv_bndo_bndc :
  forall {R : realType} [a : itv_bound R] [r : R] [f : R -> R] lr,
    measurable_fun [set` Interval a (BLeft r)] f ->
    \int[mu]_(x in [set` Interval a (BSide lr r)]) (f x)%:E =
    \int[mu]_(x in [set` Interval a (BRight r)]) (f x)%:E.
Proof. by move=> ? ? ? ?; case; [exact: integral_itv_bndo_bndc|by []]. Qed.

Lemma measurable_fun_itv_bnd :
  forall [R : realType] [x y : R] [b1 b2 b3 b4 : bool] [f : R -> R],
  measurable_fun [set` Interval (BSide b1 x) (BSide b2 y)] f ->
  measurable_fun [set` Interval (BSide b3 x) (BSide b4 y)] f.
Proof.
move=> ? x y ? ? ? ? ? f_measurable.
apply: (measurable_funS `[x, y]) => //.
  by apply: subset_itvScc; rewrite bnd_simp.
exact: (measurable_fun_itv_cc f_measurable).
Qed.

Lemma integral_itv_bnd :
  forall {R : realType} [x y : R] [f : R -> R] (b1 b2 b3 b4 : bool),
  measurable_fun `]x, y[ f ->
  \int[mu]_(z in [set` Interval (BSide b1 x) (BSide b2 y)]) (f z)%:E =
  \int[mu]_(z in [set` Interval (BSide b3 x) (BSide b4 y)]) (f z)%:E.
Proof.
move=> ? x y ? ? ? ? ? f_measurable.
do 2 (rewrite integral_itv_bndo_bndc; last exact: (measurable_fun_itv_bnd f_measurable)).
do 2 (rewrite integral_itv_obnd_cbnd; last exact: (measurable_fun_itv_bnd f_measurable)).
by [].
Qed.

Lemma integral_itv_bndcc :
  forall {R : realType} [x y : R] [f : R -> R] (b1 b2: bool),
  measurable_fun `]x, y[ f ->
  \int[mu]_(z in [set` Interval (BSide b1 x) (BSide b2 y)]) (f z)%:E =
  \int[mu]_(z in `[x, y]) (f z)%:E.
Proof. move=> *; exact: integral_itv_bnd. Qed.

@t6s
Copy link
Member

t6s commented Jan 13, 2026

Section integralN.
Local Open Scope order_scope.

Lemma lef0_integralN
  {d : measure_display} {T : measurableType d} {R : realType} {mu : measure T R}
  (D : set T) (f : T -> \bar R) :
  d.-measurable D ->
  {in D, forall x, f x <= 0} ->
  (\int[mu]_(x in D) - f x)%E = (- (\int[mu]_(x in D) f x))%E.
Proof.
move=> mD lef0; rewrite integralN// fin_num_adde_defr//.
under eq_integral => ? ?.
  by rewrite (le0_funeposE lef0); first over; rewrite inE.
by rewrite integral_cst// mul0e.
Qed.

Lemma le0f_integralN
  {d : measure_display} {T : measurableType d} {R : realType} {mu : measure T R}
  (D : set T) (f : T -> \bar R) :
  d.-measurable D ->
  {in D, forall x, 0%E <= f x} ->
  (\int[mu]_(x in D) - f x)%E = (- (\int[mu]_(x in D) f x))%E.
Proof.
move=> mD le0f; rewrite integralN// fin_num_adde_defl//.
under eq_integral => ? ?.
  by rewrite (ge0_funenegE le0f); first over; rewrite inE.
by rewrite integral_cst// mul0e.
Qed.

End integralN.

@t6s
Copy link
Member

t6s commented Jan 13, 2026

leading to generalization of sum_integral_limn:

Let sumN_Nsum_fG n b1 b2 :
  (b1 == true) || (b2 == false) ->
  \sum_(0 <= i < n)
    (- (\int[mu]_(x in seqDU (fun k => [set` Interval (BSide b1 a) (BSide b2 (a + k%:R))]) i)
         (f x * G x)%:E))%E =
  - (\sum_(0 <= i < n)
      (\int[mu]_(x in seqDU (fun k => [set` Interval (BSide b1 a) (BSide b2 (a + k%:R))]) i)
        (f x * G x)%:E)%E).
Proof.
move=> b12.
rewrite big_nat_cond fin_num_sumeN -?big_nat_cond// => m _.
case: m => [|m].
  by rewrite seqDU0 addr0 (integral_Sset1 a)//; exact: set_itv_Sset1.
rewrite seqDUSn_itv_notoo//.
rewrite integral_itv_bndcc; last first.
  apply: (measurable_funS `[a, +oo[) => //.
  by apply/subset_itv => //; rewrite bnd_simp// lerDl.
apply: integrable_fin_num => //=.
apply: continuous_compact_integrable; first exact: segment_compact.
apply: continuous_subspaceW cfG.
by apply: subset_itv; rewrite // bnd_simp// lerDl.
Qed.

Let sum_integral_limn b1 b2 :
  (b1 == true) || (b2 == false) ->
  \sum_(0 <= i <oo)
    \int[mu]_(x in seqDU (fun k => [set` Interval (BSide b1 a) (BSide b2 (a + k%:R))]) i) (F x * g x)%:E
  = limn (fun n => (F (a + n.-1%:R) * G (a + n.-1%:R) - F a * G a)%:E
                    + \sum_(0 <= i < n)
                    - \int[mu]_(x in seqDU (fun k => [set` Interval (BSide b1 a) (BSide b2 (a + k%:R))]) i)
                        (f x * G x)%:E).
Proof.
move=> b12.
apply/congr_lim/funext; case.
  by rewrite big_nat_cond [in RHS]big_nat_cond 2?big_pred0//= 2!addr0 subrr.
case=> [|n].
  rewrite 2!big_nat1 seqDU0 -pred_Sn addr0 subrr add0r.
  rewrite !(integral_Sset1 a) ?oppe0//; exact: set_itv_Sset1.
rewrite big_nat_recl// [in RHS]big_nat_recl//=.
rewrite seqDU0 addr0 !(integral_Sset1 a); [|exact: set_itv_Sset1|exact: set_itv_Sset1].
rewrite oppe0 2!add0r.
under eq_bigr => i _.
  rewrite seqDUSn_itv_notoo//= (integral_itv_bndcc b2 b2); last first.
    apply: (measurable_funS `[a, +oo[) => //.
    by apply/subset_itv => //; rewrite bnd_simp lerDl.
  rewrite (integration_by_parts _ _ _ (@Ffai i) _ _ (@Ggai i)); last 5 first.
  - by rewrite ltrD2l ltr_nat.
  - apply: continuous_subspaceW cf.
    by apply/subset_itv => //; rewrite bnd_simp lerDl.
  - apply: derivable_oy_continuousWoo Foy.
    + by rewrite ltrD2l ltr_nat.
    + by rewrite lerDl.
  - apply: continuous_subspaceW cg.
    by apply/subset_itv => //; rewrite bnd_simp lerDl.
  - apply: derivable_oy_continuousWoo Goy.
    + by rewrite ltrD2l ltr_nat.
    + by rewrite lerDl.
  over.
rewrite big_split/=.
under eq_bigr do rewrite EFinB.
rewrite telescope_sume => [|//|//]; rewrite addr0; congr +%E.
apply: eq_bigr => k _; rewrite seqDUSn_itv_notoo; last by [].
rewrite [in RHS]integral_itv_bndcc; first by [].
apply: measurable_funS mfG => //.
by apply/subset_itv => //; rewrite bnd_simp lerDl.
Qed.

@affeldt-aist
Copy link
Member

looking at the code for a while, I noticed there can be some helper lemmas added:
...

on our side, we were trying to get rid of seqDU that does not seem to be here for good reasons :-/

@t6s
Copy link
Member

t6s commented Jan 13, 2026

looking at the code for a while, I noticed there can be some helper lemmas added:
...

on our side, we were trying to get rid of seqDU that does not seem to be here for good reasons :-/

that sounds better

@t6s
Copy link
Member

t6s commented Jan 13, 2026

I suggest keeping 4 lemmas as is, and additionally, provide a unified interface lemma that use the constant_sign predicate

I have changed my mind to endorse constant_sign, as this notion can be handily expressed
by (f <= 0) || (0 <= f) using FunOrder.lef, and moreover, it contradicts Num.sgr.

Copy link
Member

@t6s t6s left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main lemmas look good.
After trying to remove subset_itvoSo_cSc, this PR will be ready for merging.


End itv_realDomainType.

(* generalization of
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This lemma can be an instance of the monotonicity of the closure operator.


End integration_by_partsy_ge0.

Section integration_by_partsy_le0.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section appears to be sharing many things with the previous one.
Maybe merge the two?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement ✨ This issue/PR is about adding new features enhancing the library

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants