(************************************************************************)
(*         *   The Coq Proof Assistant / The Coq Development Team       *)
(*  v      *   INRIA, CNRS and contributors - Copyright 1999-2018       *)
(* <O___,, *       (see CREDITS file for the list of authors)           *)
(*   \VV/  **************************************************************)
(*    //   *    This file is distributed under the terms of the         *)
(*         *     GNU Lesser General Public License Version 2.1          *)
(*         *     (see LICENSE file for the text of the license)         *)
(************************************************************************)
Require Export Rlimit.
Require Export Rderiv.
Local Open Scope R_scope.
Implicit Type f : R -> R.
(****************************************************)
(** *         Basic operations on functions         *)
(****************************************************)
Definition plus_fct f1 f2 (x:R) : R := f1 x + f2 x.
Definition opp_fct f (x:R) : R := - f x.
Definition mult_fct f1 f2 (x:R) : R := f1 x * f2 x.
Definition mult_real_fct (a:R) f (x:R) : R := a * f x.
Definition minus_fct f1 f2 (x:R) : R := f1 x - f2 x.
Definition div_fct f1 f2 (x:R) : R := f1 x / f2 x.
Definition div_real_fct (a:R) f (x:R) : R := a / f x.
Definition comp f1 f2 (x:R) : R := f1 (f2 x).
Definition inv_fct f (x:R) : R := / f x.
Declare Scope Rfun_scope.
Delimit Scope Rfun_scope with F.
Arguments plus_fct (f1 f2)%F x%R.
Arguments mult_fct (f1 f2)%F x%R.
Arguments minus_fct (f1 f2)%F x%R.
Arguments div_fct (f1 f2)%F x%R.
Arguments inv_fct f%F x%R.
Arguments opp_fct f%F x%R.
Arguments mult_real_fct a%R f%F x%R.
Arguments div_real_fct a%R f%F x%R.
Arguments comp (f1 f2)%F x%R.
Infix "+" := plus_fct : Rfun_scope.
Notation "- x" := (opp_fct x) : Rfun_scope.
Infix "*" := mult_fct : Rfun_scope.
Infix "-" := minus_fct : Rfun_scope.
Infix "/" := div_fct : Rfun_scope.
Local Notation "f1 'o' f2" := (comp f1 f2)
(at level 20, right associativity) : Rfun_scope.
Notation "/ x" := (inv_fct x) : Rfun_scope.
Definition fct_cte (a x:R) : R := a.
Definition id (x:R) := x.
(****************************************************)
(** *          Variations of functions              *)
(****************************************************)
Definition increasing f : Prop := forall x y:R, x <= y -> f x <= f y.
Definition decreasing f : Prop := forall x y:R, x <= y -> f y <= f x.
Definition strict_increasing f : Prop := forall x y:R, x < y -> f x < f y.
Definition strict_decreasing f : Prop := forall x y:R, x < y -> f y < f x.
Definition constant f : Prop := forall x y:R, f x = f y.
(**********)
Definition no_cond (x:R) : Prop := True.
(**********)
Definition constant_D_eq f (D:R -> Prop) (c:R) : Prop :=
forall x:R, D x -> f x = c.
(***************************************************)
(** *    Definition of continuity as a limit       *)
(***************************************************)
(**********)
Definition continuity_pt f (x0:R) : Prop := continue_in f no_cond x0.
Definition continuity f : Prop := forall x:R, continuity_pt f x.
Arguments continuity_pt f%F x0%R.
Arguments continuity f%F.
intros f g a x a0 q cf eps ep.
destruct (cf eps ep) as [a' [a'p Pa']].
exists (Rmin a a'); split.
unfold Rmin; destruct (Rle_dec a a').
assumption.
assumption.
intros y cy; rewrite <- !q.
apply Pa'.
split;[| apply Rlt_le_trans with (Rmin a a');[ | apply Rmin_r]];tauto.
rewrite R_dist_eq; assumption.
apply Rlt_le_trans with (Rmin a a');[ | apply Rmin_l]; tauto.
Qed.
(*****************************************************)
(** * Derivative's definition using Landau's kernel  *)
(*****************************************************)
Definition derivable_pt_lim f (x l:R) : Prop :=
forall eps:R,
0 < eps ->
exists delta : posreal,
(forall h:R,
h <> 0 -> Rabs h < delta -> Rabs ((f (x + h) - f x) / h - l) < eps).
Definition derivable_pt_abs f (x l:R) : Prop := derivable_pt_lim f x l.
Definition derivable_pt f (x:R) := { l:R | derivable_pt_abs f x l }.
Definition derivable f := forall x:R, derivable_pt f x.
Definition derive_pt f (x:R) (pr:derivable_pt f x) := proj1_sig pr.
Definition derive f (pr:derivable f) (x:R) := derive_pt f x (pr x).
Arguments derivable_pt_lim f%F x%R l.
Arguments derivable_pt_abs f%F (x l)%R.
Arguments derivable_pt f%F x%R.
Arguments derivable f%F.
Arguments derive_pt f%F x%R pr.
Arguments derive f%F pr x.
Definition antiderivative f (g:R -> R) (a b:R) : Prop :=
(forall x:R,
a <= x <= b ->  exists pr : derivable_pt g x, f x = derive_pt g x pr) /\
a <= b.
(**************************************)
(** * Class of differential functions *)
(**************************************)
Record Differential : Type := mkDifferential
{d1 :> R -> R; cond_diff : derivable d1}.
Record Differential_D2 : Type := mkDifferential_D2
{d2 :> R -> R;
cond_D1 : derivable d2;
cond_D2 : derivable (derive d2 cond_D1)}.
(* Extensionally equal functions have the same derivative. *)
intros f g x l fg df e ep; destruct (df e ep) as [d pd]; exists d; intros h;
rewrite <- !fg; apply pd.
Qed.
(* extensionally equal functions have the same derivative, locally. *)
intros f g x a b l axb fg df e ep.
destruct (df e ep) as [d pd].
assert (d'h : 0 < Rmin d (Rmin (b - x) (x - a))).
apply Rmin_pos;[apply cond_pos | apply Rmin_pos; apply Rlt_Rminus; tauto].
exists (mkposreal _ d'h); simpl; intros h hn0 cmp.
rewrite <- !fg;[ |assumption | ].
apply pd;[assumption |].
apply Rlt_le_trans with (1 := cmp), Rmin_l.
assert (-h < x - a).
apply Rle_lt_trans with (1 := Rle_abs _).
rewrite Rabs_Ropp; apply Rlt_le_trans with (1 := cmp).
rewrite Rmin_assoc; apply Rmin_r.
assert (h < b - x).
apply Rle_lt_trans with (1 := Rle_abs _).
apply Rlt_le_trans with (1 := cmp).
rewrite Rmin_comm, <- Rmin_assoc; apply Rmin_l.
split.
apply (Rplus_lt_reg_l (- h)).
replace ((-h) + (x + h)) with x by ring.
apply (Rplus_lt_reg_r (- a)).
replace (((-h) + a) + - a) with (-h) by ring.
assumption.
apply (Rplus_lt_reg_r (- x)).
replace (x + h + - x) with h by ring.
assumption.
Qed.
(****************************************************************)
(** *                    Main rules                             *)
(****************************************************************)
intros.
apply uniqueness_step3.
assert (H1 := uniqueness_step2 _ _ _ H).
assert (H2 := uniqueness_step2 _ _ _ H0).
unfold plus_fct.
cut
(forall h:R,
(f1 (x + h) + f2 (x + h) - (f1 x + f2 x)) / h =
(f1 (x + h) - f1 x) / h + (f2 (x + h) - f2 x) / h).
intro.
generalize
(limit_plus (fun h':R => (f1 (x + h') - f1 x) / h')
(fun h':R => (f2 (x + h') - f2 x) / h') (fun h:R => h <> 0) l1 l2 0 H1 H2).
unfold limit1_in; unfold limit_in; unfold dist;
simpl; unfold R_dist; intros.
elim (H4 eps H5); intros.
exists x0.
elim H6; intros.
split.
assumption.
intros; rewrite H3; apply H8; assumption.
intro; unfold Rdiv; ring.
Qed.
intros f x l a df;
apply (derivable_pt_lim_ext (fun y => /a * f y)).
intros z; rewrite Rmult_comm; reflexivity.
unfold Rdiv; rewrite Rmult_comm; apply derivable_pt_lim_scal; assumption.
Qed.
intros f x l a df;
apply (derivable_pt_lim_ext (fun y => a * f y)).
intros z; rewrite Rmult_comm; reflexivity.
unfold Rdiv; rewrite Rmult_comm; apply derivable_pt_lim_scal; assumption.
Qed.

Lemma derive_pt_mult :
forall f1 f2 (x:R) (pr1:derivable_pt f1 x) (pr2:derivable_pt f2 x),
derive_pt (f1 * f2) x (derivable_pt_mult _ _ _ pr1 pr2) =
derive_pt f1 x pr1 * f2 x + f1 x * derive_pt f2 x pr2.