From 8636a89c1a9ddba1dcc6693c9eed8611adff9ae0 Mon Sep 17 00:00:00 2001
From: Sergei Bozhko <sbozhko@mpi-sws.org>
Date: Wed, 23 Oct 2019 15:07:37 +0200
Subject: [PATCH] Add notion of busy interval

---
 classic/util/minmax.v                         | 124 +--
 classic/util/nat.v                            |   7 -
 classic/util/sum.v                            |  44 +-
 .../analysis/definitions/busy_interval.v      |  94 +++
 .../analysis/definitions/no_carry_in.v        |  37 +
 .../analysis/definitions/priority_inversion.v |  86 +++
 .../analysis/facts/busy_interval_exists.v     | 703 ++++++++++++++++++
 .../analysis/facts/no_carry_in_exists.v       | 318 ++++++++
 util/all.v                                    |   1 +
 util/minmax.v                                 | 128 ++++
 util/nat.v                                    |   7 +
 util/sum.v                                    |  51 +-
 12 files changed, 1425 insertions(+), 175 deletions(-)
 create mode 100644 restructuring/analysis/definitions/busy_interval.v
 create mode 100644 restructuring/analysis/definitions/no_carry_in.v
 create mode 100644 restructuring/analysis/definitions/priority_inversion.v
 create mode 100644 restructuring/analysis/facts/busy_interval_exists.v
 create mode 100644 restructuring/analysis/facts/no_carry_in_exists.v
 create mode 100644 util/minmax.v

diff --git a/classic/util/minmax.v b/classic/util/minmax.v
index 60aaf18e2..a903797f0 100644
--- a/classic/util/minmax.v
+++ b/classic/util/minmax.v
@@ -1,3 +1,4 @@
+Require Export rt.util.minmax.
 Require Import rt.classic.util.tactics rt.classic.util.notation rt.classic.util.sorting rt.classic.util.nat rt.classic.util.list.
 From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq fintype bigop.
 
@@ -512,129 +513,6 @@ Section MinMaxSeq.
 
 End MinMaxSeq.
 
-(* Additional lemmas about max. *)
-Section ExtraLemmas.
-
-  Lemma leq_bigmax_cond_seq (T : eqType) (P : pred T) (r : seq T) F i0 :
-    i0 \in r -> P i0 -> F i0 <= \max_(i <- r | P i) F i.
-  Proof.
-    intros IN0 Pi0; by rewrite (big_rem i0) //= Pi0 leq_maxl.
-  Qed.
-
-  Lemma bigmax_sup_seq:
-    forall (T: eqType) (i: T) r (P: pred T) m F,
-      i \in r -> P i -> m <= F i -> m <= \max_(i <- r| P i) F i.
-  Proof.
-    intros.
-    induction r.
-    - by rewrite in_nil  in H.
-      move: H; rewrite in_cons; move => /orP [/eqP EQA | IN].
-      {
-        clear IHr; subst a.
-        rewrite (big_rem i) //=; last by rewrite in_cons; apply/orP; left.
-        apply leq_trans with (F i); first by done.
-          by rewrite H0 leq_maxl.
-      }
-      {
-        apply leq_trans with (\max_(i0 <- r | P i0) F i0); first by apply IHr.
-        rewrite [in X in _ <= X](big_rem a) //=; last by rewrite in_cons; apply/orP; left.
-
-        have Ob: a == a; first by done.
-          by rewrite Ob leq_maxr.
-      }
-  Qed.
-
-  Lemma bigmax_leq_seqP (T : eqType) (P : pred T) (r : seq T) F m :
-    reflect (forall i, i \in r -> P i -> F i <= m)
-            (\max_(i <- r | P i) F i <= m).
-  Proof.
-    apply: (iffP idP) => leFm => [i IINR Pi|];
-      first by apply: leq_trans leFm; apply leq_bigmax_cond_seq.
-    rewrite big_seq_cond; elim/big_ind: _ => // m1 m2.
-      by intros; rewrite geq_max; apply/andP; split. 
-      by move: m2 => /andP [M1IN Pm1]; apply: leFm.
-  Qed.
-
-  Lemma leq_big_max (T : eqType) (P : pred T) (r : seq T) F1 F2 :
-    (forall i, i \in r -> P i -> F1 i <= F2 i) ->
-    \max_(i <- r | P i) F1 i <= \max_(i <- r | P i) F2 i.
-  Proof.
-    intros; apply /bigmax_leq_seqP; intros.
-    specialize (H i); feed_n 2 H; try(done).
-    rewrite (big_rem i) //=; rewrite H1.
-      by apply leq_trans with (F2 i); [ | rewrite leq_maxl].
-  Qed.
-
-  Lemma bigmax_ord_ltn_identity n :
-    n > 0 ->
-    \max_(i < n) i < n.
-  Proof.
-    intros LT.
-    destruct n; first by rewrite ltn0 in LT.
-    clear LT.
-    induction n; first by rewrite big_ord_recr /= big_ord0 maxn0.
-    rewrite big_ord_recr /=.
-    unfold maxn at 1; desf.
-    by apply leq_trans with (n := n.+1).
-  Qed.
-    
-  Lemma bigmax_ltn_ord n (P : pred nat) (i0: 'I_n) :
-    P i0 ->
-    \max_(i < n | P i) i < n.
-  Proof.
-    intros LT.
-    destruct n; first by destruct i0 as [i0 P0]; move: (P0) => P0'; rewrite ltn0 in P0'.
-    rewrite big_mkcond.
-    apply leq_ltn_trans with (n := \max_(i < n.+1) i).
-    {
-      apply/bigmax_leqP; ins.
-      destruct (P i); last by done.
-      by apply leq_bigmax_cond.
-    }
-    by apply bigmax_ord_ltn_identity.
-  Qed.
-
-  Lemma bigmax_pred n (P : pred nat) (i0: 'I_n) :
-    P (i0) ->
-    P (\max_(i < n | P i) i).
-  Proof.
-    intros PRED.
-    induction n.
-    {
-      destruct i0 as [i0 P0].
-      by move: (P0) => P1; rewrite ltn0 in P1. 
-    }
-    rewrite big_mkcond big_ord_recr /=; desf.
-    {
-      destruct n; first by rewrite big_ord0 maxn0.
-      unfold maxn at 1; desf.
-      exfalso.
-      apply negbT in Heq0; move: Heq0 => /negP BUG.
-      apply BUG. 
-      apply leq_ltn_trans with (n := \max_(i < n.+1) i).
-      {
-        apply/bigmax_leqP; ins.
-        destruct (P i); last by done.
-        by apply leq_bigmax_cond.
-      }
-      by apply bigmax_ord_ltn_identity.
-    }
-    {
-      rewrite maxn0.
-      rewrite -big_mkcond /=.
-      have LT: i0 < n.
-      {
-        rewrite ltn_neqAle; apply/andP; split;
-          last by rewrite -ltnS; apply ltn_ord.
-        apply/negP; move => /eqP BUG.
-        by rewrite -BUG PRED in Heq.
-      }
-      by rewrite (IHn (Ordinal LT)).
-    }
-  Qed.
-    
-End ExtraLemmas.
-
 Section Kmin.
 
     Context {T1 T2: eqType}.
diff --git a/classic/util/nat.v b/classic/util/nat.v
index fc464ef57..8359327ee 100644
--- a/classic/util/nat.v
+++ b/classic/util/nat.v
@@ -11,13 +11,6 @@ Section NatLemmas.
     by destruct b1,b2;
     rewrite ?addn0 ?add0n ?addn1 ?orTb ?orbT ?orbF ?orFb.
   Qed.
-
-  Lemma subh2 :
-    forall m1 m2 n1 n2,
-      m1 >= m2 ->
-      n1 >= n2 ->
-      (m1 + n1) - (m2 + n2) = m1 - m2 + (n1 - n2).
-  Proof. by ins; ssromega. Qed.
   
   Lemma subh4:
     forall m n p,
diff --git a/classic/util/sum.v b/classic/util/sum.v
index dc7a061b1..1a6c0e29f 100644
--- a/classic/util/sum.v
+++ b/classic/util/sum.v
@@ -120,51 +120,9 @@ Section ExtraLemmas.
   
 End ExtraLemmas.
 
+
 (* Lemmas about arithmetic with sums. *)
 Section SumArithmetic.
-
-  Lemma sum_seq_diff:
-    forall (T:eqType) (rs: seq T) (F G : T -> nat),
-      (forall i : T, i \in rs -> G i <= F i) ->
-      \sum_(i <- rs) (F i - G i) = \sum_(i <- rs) F i - \sum_(i <- rs) G i.
-  Proof.
-    intros.
-    induction rs; first by rewrite !big_nil subn0. 
-    rewrite !big_cons subh2.
-    - apply/eqP; rewrite eqn_add2l; apply/eqP; apply IHrs.
-        by intros; apply H; rewrite in_cons; apply/orP; right.
-    - by apply H; rewrite in_cons; apply/orP; left.
-    - rewrite big_seq_cond [in X in _ <= X]big_seq_cond.
-      rewrite leq_sum //; move => i /andP [IN _].
-        by apply H; rewrite in_cons; apply/orP; right.
-  Qed.
-  
-  Lemma sum_diff:
-    forall n F G,
-      (forall i (LT: i < n), F i >= G i) ->
-      \sum_(0 <= i < n) (F i - G i) =
-      (\sum_(0 <= i < n) (F i)) - (\sum_(0 <= i < n) (G i)).       
-  Proof.
-    intros n F G ALL.
-    rewrite sum_seq_diff; first by done.
-    move => i; rewrite mem_index_iota; move => /andP [_ LT].
-      by apply ALL.
-  Qed.
-
-  Lemma sum_pred_diff:
-    forall (T: eqType) (rs: seq T) (P: T -> bool) (F: T -> nat),
-      \sum_(r <- rs | P r) F r =
-      \sum_(r <- rs) F r - \sum_(r <- rs | ~~ P r) F r.
-  Proof.
-    clear; intros.
-    induction rs; first by rewrite !big_nil subn0.
-    rewrite !big_cons !IHrs; clear IHrs.
-    case (P a); simpl; last by rewrite subnDl.
-    rewrite addnBA; first by done.
-    rewrite big_mkcond leq_sum //.
-    intros t _.
-      by case (P t).
-  Qed.
   
   Lemma telescoping_sum :
     forall (T: Type) (F: T->nat) r (x0: T),
diff --git a/restructuring/analysis/definitions/busy_interval.v b/restructuring/analysis/definitions/busy_interval.v
new file mode 100644
index 000000000..52900be7e
--- /dev/null
+++ b/restructuring/analysis/definitions/busy_interval.v
@@ -0,0 +1,94 @@
+From rt.util Require Export all.
+From rt.restructuring.behavior Require Export all.
+From rt.restructuring.analysis.basic_facts Require Export all.
+From rt.restructuring.model Require Export job task.
+From rt.restructuring.model.schedule Require Export work_conserving.
+
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq fintype bigop.
+
+(** * Busy Interval for JLFP-models *)
+(** In this file we define the notion of busy intervals for uniprocessor for JLFP schedulers. *)
+Section BusyIntervalJLFP.
+  
+  (** Consider any type of jobs. *)
+  Context {Job : JobType}.
+  Context `{JobArrival Job}.
+  Context `{JobCost Job}.    
+
+  (** Consider any arrival sequence with consistent arrivals. *)
+  Variable arr_seq : arrival_sequence Job.
+  Hypothesis H_arrival_times_are_consistent : consistent_arrival_times arr_seq.
+  
+  (** Next, consider any ideal uniprocessor schedule of this arrival sequence. *)
+  Variable sched : schedule (ideal.processor_state Job).
+  
+  (** Assume a given JLFP policy. *)
+  Variable higher_eq_priority : JLFP_policy Job. 
+
+  (** In this section, we define the notion of a busy interval. *)
+  Section BusyInterval.
+    
+    (** Consider any job j. *)
+    Variable j : Job.
+    Hypothesis H_from_arrival_sequence : arrives_in arr_seq j.
+    
+    (** We say that t is a quiet time for j iff every higher-priority job from
+         the arrival sequence that arrived before t has completed by that time. *)
+    Definition quiet_time (t : instant) :=
+      forall (j_hp : Job),
+        arrives_in arr_seq j_hp ->
+        higher_eq_priority j_hp j ->
+        arrived_before j_hp t ->
+        completed_by sched j_hp t.
+    
+    (** Based on the definition of quiet time, we say that interval
+         [t1, t_busy) is a (potentially unbounded) busy-interval prefix
+         iff the interval starts with a quiet time where a higher or equal 
+         priority job is released and remains non-quiet. We also require
+         job j to be released in the interval. *)    
+    Definition busy_interval_prefix (t1 t_busy : instant) :=
+      t1 < t_busy /\
+      quiet_time t1 /\
+      (forall t, t1 < t < t_busy -> ~ quiet_time t) /\
+      t1 <= job_arrival j < t_busy.
+
+    (** Next, we say that an interval [t1, t2) is a busy interval iff
+         [t1, t2) is a busy-interval prefix and t2 is a quiet time. *)
+    Definition busy_interval (t1 t2 : instant) :=
+      busy_interval_prefix t1 t2 /\
+      quiet_time t2.
+
+  End BusyInterval.
+
+  (** In this section we define the computational
+       version of the notion of quiet time. *)
+  Section DecidableQuietTime.
+
+    (** We say that t is a quiet time for j iff every higher-priority job from
+         the arrival sequence that arrived before t has completed by that time. *)
+    Definition quiet_time_dec (j : Job) (t : instant) :=
+      all
+        (fun j_hp => higher_eq_priority j_hp j ==> (completed_by sched j_hp t))
+        (arrivals_before arr_seq t).
+
+    (** We also show that the computational and propositional definitions are equivalent. *)
+    Lemma quiet_time_P :
+      forall j t, reflect (quiet_time j t) (quiet_time_dec j t).
+    Proof.
+      intros; apply/introP.
+      - intros QT s ARRs HPs BEFs.
+        move: QT => /allP QT.
+        specialize (QT s); feed QT.
+        eapply arrived_between_implies_in_arrivals; eauto 2.
+          by move: QT => /implyP Q; apply Q in HPs.
+      - move => /negP DEC; intros QT; apply: DEC.
+        apply/allP; intros s ARRs.
+        apply/implyP; intros HPs.
+        apply QT; try done.
+        + by apply in_arrivals_implies_arrived in ARRs.
+        + by eapply in_arrivals_implies_arrived_between in ARRs; eauto 2.
+    Qed.
+
+  End DecidableQuietTime.
+
+End BusyIntervalJLFP.
\ No newline at end of file
diff --git a/restructuring/analysis/definitions/no_carry_in.v b/restructuring/analysis/definitions/no_carry_in.v
new file mode 100644
index 000000000..6fc03c7c6
--- /dev/null
+++ b/restructuring/analysis/definitions/no_carry_in.v
@@ -0,0 +1,37 @@
+From rt.util Require Export all.
+From rt.restructuring.behavior Require Export all.
+From rt.restructuring.analysis.basic_facts Require Export all.
+From rt.restructuring Require Export model.job model.task.
+
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq fintype bigop.
+
+(** * No Carry-In *)
+(** In this module we define the notion of no carry-in time for uniprocessor schedulers. *)
+Section NoCarryIn.
+  
+  (** Consider any type of tasks ... *)
+  Context {Task : TaskType}.
+  Context `{TaskCost Task}.
+
+  (**  ... and any type of jobs associated with these tasks. *)
+  Context {Job : JobType}.
+  Context `{JobTask Job Task}.
+  Context `{JobArrival Job}.
+  Context `{JobCost Job}.    
+
+  (** Consider any arrival sequence with consistent arrivals. *)
+  Variable arr_seq : arrival_sequence Job.
+  Hypothesis H_arrival_times_are_consistent : consistent_arrival_times arr_seq.
+  
+  (** Next, consider any ideal uniprocessor schedule of this arrival sequence. *)
+  Variable sched : schedule (ideal.processor_state Job).
+
+  (** The processor has no carry-in at time t iff every job (regardless of priority) 
+      from the arrival sequence released before t has completed by that time. *)
+  Definition no_carry_in (t : instant) :=
+    forall j_o,
+      arrives_in arr_seq j_o ->
+      arrived_before j_o t ->
+      completed_by sched j_o t.
+
+End NoCarryIn.
diff --git a/restructuring/analysis/definitions/priority_inversion.v b/restructuring/analysis/definitions/priority_inversion.v
new file mode 100644
index 000000000..67fd9f214
--- /dev/null
+++ b/restructuring/analysis/definitions/priority_inversion.v
@@ -0,0 +1,86 @@
+From rt.util Require Export all.
+From rt.restructuring.behavior Require Export all.
+From rt.restructuring.analysis.basic_facts Require Export all.
+From rt.restructuring Require Export model.job model.task.
+From rt.restructuring.model.schedule Require Export work_conserving priority_based.priorities.
+From rt.restructuring.analysis.definitions Require Export busy_interval.
+
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq fintype bigop.
+
+(** * Cumulative Priority Inversion for JLFP-models *)
+(** In this module we define the notion of cumulative priority inversion for uniprocessor for JLFP schedulers. *)
+Section CumulativePriorityInversion.
+  
+  (** Consider any type of tasks ... *)
+  Context {Task : TaskType}.
+  Context `{TaskCost Task}.
+
+  (**  ... and any type of jobs associated with these tasks. *)
+  Context {Job : JobType}.
+  Context `{JobTask Job Task}.
+  Context `{JobArrival Job}.
+  Context `{JobCost Job}.    
+
+  (** Consider any arrival sequence with consistent arrivals. *)
+  Variable arr_seq : arrival_sequence Job.
+  Hypothesis H_arrival_times_are_consistent : consistent_arrival_times arr_seq.
+  
+  (** Next, consider any ideal uniprocessor schedule of this arrival sequence. *)
+  Variable sched : schedule (ideal.processor_state Job).
+
+  (** Assume a given JLFP policy. *)
+  Variable higher_eq_priority : JLFP_policy Job. 
+
+  (** In this section, we define a notion of bounded priority inversion experienced by a job. *)
+  Section JobPriorityInversionBound.
+
+    (** Consider an arbitrary task [tsk]. *)
+    Variable tsk : Task.
+
+    (** Consider any job j of tsk. *)
+    Variable j : Job.
+    Hypothesis H_from_arrival_sequence : arrives_in arr_seq j.
+    Hypothesis H_job_task : job_of_task tsk j. 
+
+    (** We say that the job incurs priority inversion if it has higher
+        priority than the scheduled job. Note that this definition
+        implicitly assumes that the scheduler is
+        work-conserving. Therefore, it cannot be applied to models
+        with jitter or self-suspensions. *)
+    Definition is_priority_inversion (t : instant) :=
+      if sched t is Some jlp then
+        ~~ higher_eq_priority jlp j
+      else false.
+    
+    (** Then we compute the cumulative priority inversion incurred by
+         a job within some time interval [t1, t2). *)
+    Definition cumulative_priority_inversion (t1 t2 : instant) :=
+      \sum_(t1 <= t < t2) is_priority_inversion t.
+
+    (** We say that priority inversion of job j is bounded by a constant B iff cumulative 
+         priority inversion within any busy inverval prefix is bounded by B. *)
+    Definition priority_inversion_of_job_is_bounded_by (B : duration) :=
+      forall (t1 t2 : instant),
+        busy_interval_prefix arr_seq sched higher_eq_priority j t1 t2 ->
+        cumulative_priority_inversion t1 t2 <= B.
+
+  End JobPriorityInversionBound.
+
+  (** In this section, we define a notion of the bounded priority inversion for task. *)
+  Section TaskPriorityInversionBound.
+
+    (** Consider an arbitrary task tsk. *)
+    Variable tsk : Task.
+
+    (** We say that task tsk has bounded priority inversion if all 
+         its jobs have bounded cumulative priority inversion. *)
+    Definition priority_inversion_is_bounded_by (B : duration) :=
+      forall (j : Job),
+        arrives_in arr_seq j ->
+        job_task j = tsk ->
+        job_cost j > 0 -> 
+        priority_inversion_of_job_is_bounded_by j B.
+
+  End TaskPriorityInversionBound.
+
+End CumulativePriorityInversion.
diff --git a/restructuring/analysis/facts/busy_interval_exists.v b/restructuring/analysis/facts/busy_interval_exists.v
new file mode 100644
index 000000000..2c1a46ae9
--- /dev/null
+++ b/restructuring/analysis/facts/busy_interval_exists.v
@@ -0,0 +1,703 @@
+From rt.util Require Export all.
+From rt.restructuring.behavior Require Export all.
+From rt.restructuring.analysis.basic_facts Require Export all.
+From rt.restructuring.model Require Export job task.
+From rt.restructuring.model.schedule Require Export work_conserving priority_based.priorities.
+From rt.restructuring.analysis.definitions Require Export busy_interval priority_inversion.
+
+(** Throughout the file we assume for the classic Liu & Layland model
+   of readiness without jitter and no self-suspensions, where prending
+   jobs are always ready. *)
+From rt.restructuring.model Require Import readiness.basic.
+
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq fintype bigop.
+
+(** * Existence of Busy Interval for JLFP-models *)
+(** In this module we derive a sufficient condition for existence of
+    busy intervals for uniprocessor for JLFP schedulers. *)
+Section ExistsBusyIntervalJLFP.
+  
+  (** Consider any type of tasks ... *)
+  Context {Task : TaskType}.
+  Context `{TaskCost Task}.
+
+  (**  ... and any type of jobs associated with these tasks. *)
+  Context {Job : JobType}.
+  Context `{JobTask Job Task}.
+  Context `{JobArrival Job}.
+  Context `{JobCost Job}.    
+
+  (** Consider any arrival sequence with consistent arrivals. *)
+  Variable arr_seq : arrival_sequence Job.
+  Hypothesis H_arrival_times_are_consistent : consistent_arrival_times arr_seq.
+  
+  (** Next, consider any ideal uniprocessor schedule of this arrival sequence ... *)
+  Variable sched : schedule (ideal.processor_state Job).
+  Hypothesis H_jobs_come_from_arrival_sequence:
+    jobs_come_from_arrival_sequence sched arr_seq.
+  
+  (** ... where jobs do not execute before their arrival or after completion. *)
+  Hypothesis H_jobs_must_arrive_to_execute : jobs_must_arrive_to_execute sched.
+  Hypothesis H_completed_jobs_dont_execute : completed_jobs_dont_execute sched.
+
+  (** Assume a given JLFP policy. *)
+  Variable higher_eq_priority : JLFP_policy Job. 
+  
+  (** For simplicity, let's define some local names. *)
+  Let job_pending_at := pending sched.
+  Let job_completed_by := completed_by sched.
+  Let arrivals_between := arrivals_between arr_seq.
+  
+  (** Consider an arbitrary task [tsk]. *)
+  Variable tsk : Task.
+
+  (** Consider an arbitrary job [j]. *)
+  Variable j : Job.
+  Hypothesis H_from_arrival_sequence : arrives_in arr_seq j.
+  Hypothesis H_job_task : job_of_task tsk j.
+  Hypothesis H_job_cost_positive : job_cost_positive j.
+  
+  (** Recall the list of jobs that arrive in any interval. *)
+  Let quiet_time t1 := quiet_time arr_seq sched higher_eq_priority j t1.
+  Let quiet_time_dec t1 := quiet_time_dec arr_seq sched higher_eq_priority j t1.
+  Let busy_interval_prefix t1 t2 := busy_interval_prefix arr_seq sched higher_eq_priority j t1 t2.
+  Let busy_interval t1 t2 := busy_interval arr_seq sched higher_eq_priority j t1 t2.
+  Let is_priority_inversion_bounded_by K := priority_inversion_of_job_is_bounded_by arr_seq sched higher_eq_priority j K.
+  
+  (** We begin by proving a basic lemma about completion of the job within its busy interval. *)
+  Section BasicLemma.
+
+    (** Assume that the priority relation is reflexive. *)
+    Hypothesis H_priority_is_reflexive : reflexive_priorities.
+
+    (** Consider any busy interval [t1, t2) of job [j]. *)
+    Variable t1 t2 : instant.
+    Hypothesis H_busy_interval : busy_interval t1 t2.
+    
+    (** We prove that job j completes by the end of the busy interval. *)
+    Lemma job_completes_within_busy_interval: 
+      job_completed_by j t2.
+    Proof.
+      rename H_priority_is_reflexive into REFL, H_busy_interval into BUSY.
+      move: BUSY => [[_ [_ [_ /andP [_ ARR]]]] QUIET].
+      apply QUIET; try done.
+      apply (REFL 0).
+    Qed.
+
+  End BasicLemma.
+  
+  (** In this section, we prove that during a busy interval there
+         always exists a pending job. *)
+  Section ExistsPendingJob.
+    
+    (** Let [[t1, t2]] be any interval where time t1 is quiet and time t2 is not quiet. *)
+    Variable t1 t2 : instant.
+    Hypothesis H_interval : t1 <= t2.
+    Hypothesis H_quiet : quiet_time t1.
+    Hypothesis H_not_quiet : ~ quiet_time t2.
+    
+    (** Then, we prove that there is a job pending at time t2
+         that has higher or equal priority (with respect of tsk). *)
+    Lemma not_quiet_implies_exists_pending_job:
+      exists j_hp,
+        arrives_in arr_seq j_hp /\
+        arrived_between j_hp t1 t2 /\
+        higher_eq_priority j_hp j /\
+        ~ job_completed_by j_hp t2. 
+    Proof.
+      rename H_quiet into QUIET, H_not_quiet into NOTQUIET.
+      destruct (has (fun j_hp => (~~ job_completed_by j_hp t2) && higher_eq_priority j_hp j)
+                    (arrivals_between t1 t2)) eqn:COMP.
+      { move: COMP => /hasP [j_hp ARR /andP [NOTCOMP HP]].
+        move: (ARR) => INarr.
+        apply in_arrivals_implies_arrived_between in ARR; last by done.
+        apply in_arrivals_implies_arrived in INarr.
+          by exists j_hp; repeat split; last by apply/negP.
+      }
+      {
+        apply negbT in COMP; rewrite -all_predC in COMP.
+        move: COMP => /allP COMP.
+        exfalso; apply NOTQUIET; intros j_hp IN HP ARR.
+        destruct (ltnP (job_arrival j_hp) t1) as [BEFORE | AFTER];
+          first by specialize (QUIET j_hp IN HP BEFORE); apply completion_monotonic with (t := t1).
+        feed (COMP j_hp).
+          by eapply arrived_between_implies_in_arrivals; eauto 1; apply/andP; split.
+            by rewrite /= HP andbT negbK in COMP.
+      }
+    Qed.
+
+  End ExistsPendingJob.
+  
+  (** In this section, we prove that during a busy interval the
+         processor is never idle. *)
+  Section ProcessorAlwaysBusy.
+
+    (** Assume that the schedule is work-conserving ... *)
+    Hypothesis H_work_conserving : work_conserving arr_seq sched.
+
+    (** ... and the priority relation is reflexive and transitive. *)
+    Hypothesis H_priority_is_reflexive : reflexive_priorities. 
+    Hypothesis H_priority_is_transitive : transitive_priorities.
+    
+    (** Consider any busy interval prefix [t1, t2). *)
+    Variable t1 t2 : instant.
+    Hypothesis H_busy_interval_prefix : busy_interval_prefix t1 t2.
+
+    (** We prove that if the processot is idle at a time instant t, then 
+           the next time instant [t+1] will be a quiet time. *)
+    Lemma idle_time_implies_quiet_time_at_the_next_time_instant:
+      forall (t : instant),
+        is_idle sched t ->
+        quiet_time t.+1.
+    Proof.
+      intros t IDLE jhp ARR HP AB.
+      apply negbNE; apply/negP; intros NCOMP.
+      rewrite /arrived_before ltnS in AB.
+      move:(H_work_conserving _ t ARR) => WC.
+      feed WC.
+      { apply/andP. split.
+        - apply/negPn/negP; rewrite negb_and; intros COMP.
+          move: COMP => /orP; rewrite Bool.negb_involutive; move => [/negP CON|COM]; auto.
+          move: NCOMP => /negP NCOMP; apply: NCOMP.
+            by apply completion_monotonic with t.
+        - by move: IDLE => /eqP IDLE; rewrite /scheduled_at scheduled_in_def IDLE. 
+      }
+      move: IDLE WC => /eqP IDLE [jo SCHED].
+        by rewrite scheduled_at_def IDLE in SCHED.
+    Qed.
+
+    (** Next, we prove that at any time instant t within the busy interval there exists a job 
+           [jhp] such that (1) job [jhp] is pending at time [t] and (2) job [jhp] has higher-or-equal
+           priority than task [tsk]. *)
+    Lemma pending_hp_job_exists:
+      forall t,
+        t1 <= t < t2 ->
+        exists jhp,
+          arrives_in arr_seq jhp /\
+          job_pending_at jhp t /\
+          higher_eq_priority jhp j.
+    Proof.
+      move => t /andP [GE LT]; move: (H_busy_interval_prefix) => [_ [QTt [NQT REL]]].
+      move: (ltngtP t1.+1 t2) => [GT|CONTR|EQ]; first last.
+      - subst t2; rewrite ltnS in LT.
+        have EQ: t1 = t by apply/eqP; rewrite eqn_leq; apply/andP; split.
+        subst t1; clear GE LT.
+        exists j; repeat split; try done.
+        + move: REL; rewrite ltnS -eqn_leq eq_sym; move => /eqP REL.
+            by rewrite -REL; eapply job_pending_at_arrival; eauto 2.
+        + by apply (H_priority_is_reflexive 0).
+      - by exfalso; move_neq_down CONTR; eapply leq_ltn_trans; eauto 2.
+      - have EX: exists hp__seq: seq Job,
+        forall j__hp, j__hp \in hp__seq <-> arrives_in arr_seq j__hp /\ job_pending_at j__hp t /\ higher_eq_priority j__hp j.
+        { exists (filter (fun jo => (job_pending_at jo t) && (higher_eq_priority jo j)) (arrivals_between 0 t.+1)).
+          intros; split; intros T.
+          - move: T; rewrite mem_filter; move => /andP [/andP [PEN HP] IN].
+            repeat split; eauto using in_arrivals_implies_arrived.
+          - move: T => [ARR [PEN HP]].
+            rewrite mem_filter; apply/andP; split; first (apply/andP; split); try done.
+            eapply arrived_between_implies_in_arrivals; try done.
+              by apply/andP; split; last rewrite ltnS; move: PEN => /andP [T _].
+        } move: EX => [hp__seq SE]; case FL: (hp__seq) => [ | jhp jhps].
+        + subst hp__seq; exfalso.
+          move: GE; rewrite leq_eqVlt; move => /orP [/eqP EQ| GE].
+          * subst t.
+            apply NQT with t1.+1; first by apply/andP; split.
+            intros jhp ARR HP ARRB; apply negbNE; apply/negP; intros NCOMP.
+            move: (SE jhp) => [_ SE2].
+            rewrite in_nil in SE2; feed SE2; [clear SE2 | by done].
+            repeat split; try done; first apply/andP; split; try done.
+            apply/negP; intros COMLP.
+            move: NCOMP => /negP NCOMP; apply: NCOMP.
+              by apply completion_monotonic with t1.
+          * apply NQT with t; first by apply/andP; split.
+            intros jhp ARR HP ARRB; apply negbNE; apply/negP; intros NCOMP.
+            move: (SE jhp) => [_ SE2].
+            rewrite in_nil in SE2; feed SE2; [clear SE2 | by done].
+              by repeat split; auto; apply/andP; split; first apply ltnW.
+        + move: (SE jhp)=> [SE1 _]; subst; clear SE.
+            by exists jhp; apply SE1; rewrite in_cons; apply/orP; left.
+    Qed.
+    
+    (** We prove that at any time instant [t] within [t1, t2) the processor is not idle. *)
+    Lemma not_quiet_implies_not_idle:
+      forall t,
+        t1 <= t < t2 ->
+        ~ is_idle sched t.
+    Proof.
+      intros t NEQ IDLE.
+      move: (pending_hp_job_exists _ NEQ) => [jhp [ARR [PEND HP]]].
+      unfold work_conserving in *.
+      feed (H_work_conserving _ t ARR).
+      apply/andP; split; first by done.
+      move: IDLE => /eqP IDLE; rewrite scheduled_at_def IDLE; by done.
+      move: (H_work_conserving) => [jo SCHED].
+      move: IDLE SCHED => /eqP IDLE SCHED.
+        by rewrite scheduled_at_def IDLE in SCHED.
+    Qed.
+    
+  End ProcessorAlwaysBusy.
+
+  (** In section we prove a few auxiliary lemmas about quiet time and service.  *)
+  Section QuietTimeAndServiceOfJobs.
+
+    (** Assume that the schedule is work-conserving ... *)
+    Hypothesis H_work_conserving : work_conserving arr_seq sched.
+
+    (** ... and there are no duplicate job arrivals. *)
+    Hypothesis H_arrival_sequence_is_a_set:
+      arrival_sequence_uniq arr_seq.
+
+    (** Let [t1] be a quiet time. *)
+    Variable t1 : instant.
+    Hypothesis H_quiet_time : quiet_time t1.
+    
+    (** Assume that there is no quiet time in the interval (t1, t1 + Δ]. *)
+    Variable Δ : duration.
+    Hypothesis H_no_quiet_time : forall t, t1 < t <= t1 + Δ -> ~ quiet_time t.
+
+    (** For clarity, we introduce a notion of the total service of jobs released in 
+           time interval [t_beg, t_end) during the time interval [t1, t1 + Δ). *)
+    Let service_received_by_hep_jobs_released_during t_beg t_end :=
+      service_of_higher_or_equal_priority_jobs
+        sched higher_eq_priority (arrivals_between t_beg t_end) j t1 (t1 + Δ).
+
+    (** We prove that jobs with higher-than-or-equal priority that
+           released before time instant t1 receive no service after 
+           time instant t1. *)
+    Lemma hep_jobs_receive_no_service_before_quiet_time:
+      service_received_by_hep_jobs_released_during t1 (t1 + Δ) =
+      service_received_by_hep_jobs_released_during 0 (t1 + Δ).
+    Proof.
+      intros.
+      rewrite /service_received_by_hep_jobs_released_during
+              /service_of_higher_or_equal_priority_jobs
+              /service_of_jobs /arrivals_between.
+      rewrite [in X in _ = X](arrivals_between_cat _ _ t1);
+        [ | | rewrite leq_addr]; try done.
+      rewrite big_cat //=.
+      rewrite -{1}[\sum_(j <- arrivals_between _ (t1 + Δ) | _)
+                    service_during sched j t1 (t1 + Δ)]add0n.
+      apply/eqP. rewrite eqn_add2r eq_sym exchange_big //=.
+      rewrite big1_seq //.
+      move => t' /andP [_ NEQ]; rewrite mem_iota in NEQ.
+      rewrite big1_seq //.
+      move => jhp /andP [HP ARR].
+      apply/eqP; rewrite eqb0. rewrite -scheduled_at_def.
+      apply (completed_implies_not_scheduled _ _ H_completed_jobs_dont_execute).
+      apply completion_monotonic with t1; [ move: NEQ => /andP [T1 _] | ]; try done.
+      apply H_quiet_time; try done.
+      - by eapply in_arrivals_implies_arrived; eauto 2.
+      - by eapply in_arrivals_implies_arrived_before; eauto 2.
+    Qed.
+    
+    (** Next we prove that the total service within a "non-quiet" 
+        time interval [t1, t1 + Δ) is exactly Δ. *)
+    Lemma no_idle_time_within_non_quiet_time_interval:
+      service_of_jobs sched predT (arrivals_between 0 (t1 + Δ)) t1 (t1 + Δ) = Δ.
+    Proof.
+      intros; unfold service_of_jobs, service_of_higher_or_equal_priority_jobs.
+      rewrite -{3}[Δ](sum_of_ones t1) exchange_big //=.
+      apply/eqP; rewrite eqn_leq; apply/andP; split.
+      { rewrite leq_sum //.
+        move => t' _.
+        have SCH := service_of_jobs_le_1 sched predT (arrivals_between 0 (t1 + Δ)) _ t'. 
+          by eauto using arrivals_uniq.
+      }
+      { rewrite [in X in X <= _]big_nat_cond [in X in _ <= X]big_nat_cond //=; rewrite leq_sum //.
+        move => t' /andP [/andP [LT GT] _].
+        apply/sum_seq_gt0P.
+        ideal_proc_model_sched_case_analysis_eq sched t' jo.
+        { exfalso; move: LT; rewrite leq_eqVlt; move => /orP [/eqP EQ|LT].
+          { subst t'.
+            feed (H_no_quiet_time t1.+1); first by apply/andP; split.
+            apply: H_no_quiet_time.
+              by apply idle_time_implies_quiet_time_at_the_next_time_instant.
+          }
+          { feed (H_no_quiet_time t'); first by apply/andP; split; last rewrite ltnW.
+            apply: H_no_quiet_time; intros j_hp IN HP ARR.
+            apply contraT; intros NOTCOMP.
+            destruct (scheduled_at sched j_hp t') eqn:SCHEDhp;
+              first by rewrite scheduled_at_def EqIdle in SCHEDhp.
+            apply negbT in SCHEDhp.
+            feed (H_work_conserving j_hp t' IN);
+              first by repeat (apply/andP; split); first by apply ltnW.
+            move: H_work_conserving => [j_other SCHEDother].
+              by rewrite scheduled_at_def EqIdle in SCHEDother.
+          }              
+        }
+        { exists jo; split.
+          - apply arrived_between_implies_in_arrivals; try done.
+            apply H_jobs_come_from_arrival_sequence with t'; try done.
+            apply/andP; split; first by done.
+            apply H_jobs_must_arrive_to_execute in Sched_jo.
+              by apply leq_ltn_trans with t'. 
+          - by rewrite lt0b -scheduled_at_def. 
+        }
+      }
+    Qed.
+    
+  End QuietTimeAndServiceOfJobs.
+
+  (** In this section, we show that the length of any busy interval
+      is bounded, as long as there is enough supply to accomodate
+      the workload of tasks with higher or equal priority. *)
+  Section BoundingBusyInterval.
+
+    (** Assume that the schedule is work-conserving, ... *)
+    Hypothesis H_work_conserving : work_conserving arr_seq sched.
+
+    (** ... and there are no duplicate job arrivals, ... *)
+    Hypothesis H_arrival_sequence_is_a_set:
+      arrival_sequence_uniq arr_seq.        
+
+    (** ... and the priority relation is reflexive and transitive. *)
+    Hypothesis H_priority_is_reflexive: reflexive_priorities.
+    Hypothesis H_priority_is_transitive: transitive_priorities.
+    
+    (** Next, we recall the notion of workload of all jobs released in a given interval
+           [t1, t2) that have higher-or-equal priority w.r.t the job j being analyzed. *)
+    Let hp_workload t1 t2 :=
+      workload_of_higher_or_equal_priority_jobs
+        higher_eq_priority j (arrivals_between t1 t2).
+
+    (** With regard to the jobs with higher-or-equal priority that are released
+           in a given interval [t1, t2), we also recall the service received by these
+           jobs in the same interval [t1, t2). *)
+    Let hp_service t1 t2 :=
+      service_of_higher_or_equal_priority_jobs
+        sched higher_eq_priority (arrivals_between t1 t2) j t1 t2.
+
+    (** Now we begin the proof. First, we show that the busy interval is bounded. *)
+    Section BoundingBusyInterval.
+
+      (** Suppose that job j is pending at time t_busy. *)
+      Variable t_busy : instant.
+      Hypothesis H_j_is_pending : job_pending_at j t_busy.
+      
+      (** First, we show that there must exist a busy interval prefix. *)
+      Section LowerBound.
+
+        (** Since job j is pending, there is a (potentially unbounded)
+               busy interval that starts no later than with the arrival of j. *)
+        Lemma exists_busy_interval_prefix:
+          exists t1,
+            busy_interval_prefix t1 t_busy.+1 /\
+            t1 <= job_arrival j <= t_busy.
+        Proof.
+          rename H_j_is_pending into PEND, H_work_conserving into WORK.
+          destruct ([exists t:'I_t_busy.+1, quiet_time_dec t]) eqn:EX.
+          - set last0 := \max_(t < t_busy.+1 | quiet_time_dec t) t.
+            move: EX => /existsP [t EX].
+            have PRED: quiet_time_dec last0 by apply (bigmax_pred t_busy.+1 (quiet_time_dec) t).
+            have QUIET: quiet_time last0.
+            { intros j_hp IN HP ARR; move: PRED => /allP PRED; feed (PRED j_hp).
+              - by eapply arrived_between_implies_in_arrivals; eauto.
+              - by rewrite HP implyTb in PRED.
+            } 
+            exists last0.
+            have JAIN: last0 <= job_arrival j <= t_busy.
+            { apply/andP; split; last by move: PEND => /andP [ARR _].
+              move_neq_up BEFORE.
+              move: PEND => /andP [_ NOTCOMP].
+              feed (QUIET j H_from_arrival_sequence); first by apply (H_priority_is_reflexive 0).
+              specialize (QUIET BEFORE).
+              apply completion_monotonic with (t' := t_busy) in QUIET; first by rewrite QUIET in NOTCOMP. 
+                by apply bigmax_ltn_ord with (i0 := t).
+            }
+            repeat split; try done.
+            + by apply bigmax_ltn_ord with (i0 := t).
+            + move => t0 /andP [GTlast LTbusy] QUIET0.
+              have PRED0: quiet_time_dec t0.
+              apply/allP; intros j_hp ARR; apply/implyP; intros HP.
+              apply QUIET0; eauto 2 using in_arrivals_implies_arrived, in_arrivals_implies_arrived_before.
+              move_neq_down GTlast.
+                by eapply (@leq_bigmax_cond _ (fun (x: 'I_t_busy.+1) => quiet_time_dec x) (fun x => x) (Ordinal LTbusy)).
+          -  apply negbT in EX; rewrite negb_exists in EX; move: EX => /forallP ALL.
+             exists 0; split; last by apply/andP; split; last by move: PEND => /andP [ARR _].
+             repeat split; first by intros j_hp _ _ ARR; rewrite /arrived_before ltn0 in ARR.
+             move => t /andP [GE LT].
+             specialize (ALL (Ordinal LT)); move: ALL => /negP ALL.
+             intros QUIET; apply ALL; simpl.
+             apply/allP; intros j_hp ARR; apply/implyP; intros HP.
+             apply QUIET; eauto 2 using in_arrivals_implies_arrived, in_arrivals_implies_arrived_before.
+             apply/andP; split; first by done.
+               by move: PEND => /andP [ARR _].
+        Qed.             
+
+      End LowerBound.
+      
+      (** Next we prove that, if there is a point where the requested workload
+             is upper-bounded by the supply, then the busy interval eventually ends. *)
+      Section UpperBound.
+
+        (** Consider any busy interval prefix of job j. *)
+        Variable t1 : instant.
+        Hypothesis H_is_busy_prefix : busy_interval_prefix t1 t_busy.+1.
+        
+        (** Let priority_inversion_bound be a constant which bounds
+             length of a priority inversion. *)
+        Variable priority_inversion_bound: instant.
+        Hypothesis H_priority_inversion_is_bounded:
+          is_priority_inversion_bounded_by priority_inversion_bound.
+        
+        (** Next, assume that for some positive delta, the sum of requested workload
+               at time [t1 + delta] and constant priority_inversion_bound is bounded by 
+               delta (i.e., the supply). *)
+        Variable delta : duration.
+        Hypothesis H_delta_positive : delta > 0.
+        Hypothesis H_workload_is_bounded :
+          priority_inversion_bound + hp_workload t1 (t1 + delta) <= delta.
+
+        (** If there is a quiet time by time (t1 + delta), it trivially follows that
+               the busy interval is bounded.
+               Thus, let's consider first the harder case where there is no quiet time,
+               which turns out to be impossible. *)
+        Section CannotBeBusyForSoLong.
+          
+          (** Assume that there is no quiet time in the interval (t1, t1 + delta]. *)
+          Hypothesis H_no_quiet_time:
+            forall t, t1 < t <= t1 + delta -> ~ quiet_time t.                
+
+          (** Since the interval is always non-quiet, the processor is always busy
+                 with tasks of higher-or-equal priority or some lower priority job which was scheduled,
+                 i.e., the sum of service done by jobs with actual arrival time in [t1, t1 + delta) 
+                 and priority inversion equals delta. *)
+          Lemma busy_interval_has_uninterrupted_service: 
+            delta <= priority_inversion_bound + hp_service t1 (t1 + delta).
+          Proof. 
+            move: H_is_busy_prefix => [H_strictly_larger [H_quiet [_ EXj]]].
+            destruct (delta <= priority_inversion_bound) eqn:KLEΔ.
+            { by apply leq_trans with priority_inversion_bound; last rewrite leq_addr. }
+            apply negbT in KLEΔ; rewrite -ltnNge in KLEΔ. 
+            apply leq_trans with (cumulative_priority_inversion sched higher_eq_priority j t1 (t1 + delta) + hp_service t1 (t1 + delta)).
+            { rewrite /hp_service hep_jobs_receive_no_service_before_quiet_time //.
+              rewrite /service_of_higher_or_equal_priority_jobs /service_of_jobs sum_pred_diff. 
+              rewrite addnBA; last first.
+              { by rewrite big_mkcond //= leq_sum //; intros j' _; case (higher_eq_priority j' j). } 
+              rewrite addnC -addnBA.
+              { intros. have TT := no_idle_time_within_non_quiet_time_interval.
+                  by unfold service_of_jobs in TT; rewrite TT // leq_addr.
+              } 
+              { rewrite /cumulative_priority_inversion /is_priority_inversion exchange_big //=.
+                apply leq_sum_seq; move => t II _.
+                rewrite mem_index_iota in II; move: II => /andP [GEi LEt].
+                case SCHED: (sched t) => [j1 | ]; simpl; first last.
+                { rewrite leqn0 big1_seq //. }
+                { case PRIO1: (higher_eq_priority j1 j); simpl; first last.
+                  - rewrite <- SCHED.
+                    have SCH := service_of_jobs_le_1 sched _ _ _ t; eauto using arrivals_uniq. 
+                  - rewrite leqn0 big1_seq; first by done.
+                    move => j2 /andP [PRIO2 ARRj2].
+                    case EQ: (j1 == j2).
+                    + by move: EQ => /eqP EQ; subst j2; rewrite PRIO1 in PRIO2.
+                    + apply/eqP; rewrite eqb0; apply/negP; intros CONTR; move: CONTR => /eqP CONTR.
+                        by inversion CONTR; clear CONTR; subst j2; rewrite PRIO1 in PRIO2. } } }
+            { rewrite leq_add2r.
+              destruct (t1 + delta <= t_busy.+1) eqn:NEQ; [ | apply negbT in NEQ; rewrite -ltnNge in NEQ].
+              - apply leq_trans with (cumulative_priority_inversion  sched higher_eq_priority j t1 t_busy.+1); last eauto 2.
+                  by rewrite [X in _ <= X](@big_cat_nat _ _ _ (t1 + delta)) //=; rewrite leq_addr.
+              -  apply H_priority_inversion_is_bounded; repeat split; try done.
+                 + by rewrite -addn1 leq_add2l.
+                 + move => t' /andP [LT GT]; apply H_no_quiet_time.
+                     by apply/andP; split; [ | rewrite ltnW ].
+                 + move: EXj => /andP [T1 T2].
+                     by apply/andP; split; [done | apply ltn_trans with (t_busy.+1)].
+            }
+          Qed.
+          
+          (** Moreover, the fact that the interval is not quiet also implies
+                 that there's more workload requested than service received. *)
+          Lemma busy_interval_too_much_workload:
+            hp_workload t1 (t1 + delta) > hp_service t1 (t1 + delta).
+          Proof.
+            have PEND := not_quiet_implies_exists_pending_job.
+            rename H_no_quiet_time into NOTQUIET, 
+            H_is_busy_prefix into PREFIX.
+            set l := arrivals_between t1 (t1 + delta).
+            set hep := higher_eq_priority.
+            unfold hp_service, service_of_higher_or_equal_priority_jobs, service_of_jobs,
+            hp_workload, workload_of_higher_or_equal_priority_jobs, workload_of_jobs.
+            fold arrivals_between l hep.
+            move: (PREFIX) => [_ [QUIET _]].
+            move: (NOTQUIET) => NOTQUIET'.
+            feed (NOTQUIET' (t1 + delta)).
+            { by apply/andP; split; first
+                by rewrite -addn1 leq_add2l.
+            }
+            feed (PEND t1 (t1 + delta)); first by apply leq_addr.
+            specialize (PEND QUIET NOTQUIET').
+            move: PEND => [j0 [ARR0 [/andP [GE0 LT0] [HP0 NOTCOMP0]]]].
+            have IN0: j0 \in l.
+            { by eapply arrived_between_implies_in_arrivals; eauto 1; apply/andP; split. }
+            have UNIQ: uniq l by eapply arrivals_uniq; eauto 1.
+            rewrite big_mkcond [\sum_(_ <- _ | _ _ _)_]big_mkcond //=.
+            rewrite (bigD1_seq j0); [simpl | by done | by done].
+            rewrite (bigD1_seq j0); [simpl | by done | by done].
+            rewrite /hep HP0.
+            rewrite -add1n addnA [1 + _]addnC addn1.
+            apply leq_add; last first.
+            {
+              apply leq_sum; intros j1 NEQ.
+              destruct (higher_eq_priority j1 j); last by done.
+                by apply cumulative_service_le_job_cost, ideal_proc_model_provides_unit_service.
+            }
+            rewrite ignore_service_before_arrival; rewrite //; [| by apply ltnW].
+            rewrite <- ignore_service_before_arrival with (t2:=0); rewrite //; [|by apply ltnW].
+              by rewrite ltnNge; apply/negP.
+          Qed.               
+          
+          (** Using the two lemmas above, we infer that the workload is larger than the
+                 interval length. However, this contradicts the assumption H_workload_is_bounded. *)
+          Corollary busy_interval_workload_larger_than_interval:
+            priority_inversion_bound + hp_workload t1 (t1 + delta)  > delta.
+          Proof.
+            apply leq_ltn_trans with (priority_inversion_bound + hp_service t1 (t1 + delta)).
+            apply busy_interval_has_uninterrupted_service.
+            rewrite ltn_add2l.
+            apply busy_interval_too_much_workload.
+          Qed.
+          
+        End CannotBeBusyForSoLong.  
+
+        (** Since the interval cannot remain busy for so long, we prove that
+               the busy interval finishes at some point t2 <= t1 + delta. *)
+        Lemma busy_interval_is_bounded:
+          exists t2,
+            t2 <= t1 + delta /\
+            busy_interval t1 t2.
+        Proof. 
+          move: H_is_busy_prefix => [LT [QT [NQ NEQ]]].
+          destruct ([exists t2:'I_(t1 + delta).+1, (t2 > t1) && quiet_time_dec t2]) eqn:EX.
+          - have EX': exists (t2 : instant), ((t1 < t2 <= t1 + delta) && quiet_time_dec t2).
+            { move: EX => /existsP [t2 /andP [LE QUIET]].
+              exists t2; apply/andP; split; last by done.
+                by apply/andP; split; last (rewrite -ltnS; apply ltn_ord). }
+            move: (ex_minnP EX') => [t2 /andP [/andP [GT LE] QUIET] MIN]; clear EX EX'.
+            exists t2; split; [ | split; [repeat split | ]]; try done.
+            + move => t /andP [GT1 LT2] BUG. 
+              feed (MIN t); first (apply/andP; split).
+              * by apply/andP; split; last by apply leq_trans with (n := t2); eauto using ltnW. 
+              * apply/allP; intros j_hp ARR; apply/implyP; intro HP.
+                apply BUG; eauto 2 using in_arrivals_implies_arrived, ARR, in_arrivals_implies_arrived_before.
+                  by apply leq_ltn_trans with (p := t2) in MIN; first by rewrite ltnn in MIN.
+            + move: NEQ => /andP [IN1 IN2].
+              apply/andP; split; first by done.
+              apply leq_ltn_trans with t_busy; eauto 2.
+              rewrite ltnNge; apply/negP; intros CONTR.
+              apply NQ with t2.
+              * by apply/andP; split; last rewrite ltnS.
+              * intros jhp ARR HP AB. 
+                move: QUIET => /allP QUIET; feed (QUIET jhp).
+                eapply arrived_between_implies_in_arrivals; eauto 2.
+                  by move: QUIET => /implyP QUIET; apply QUIET.
+            + intros j_hp IN HP ARR.
+              move: QUIET => /allP QUIET; feed (QUIET j_hp).
+              * by eapply arrived_between_implies_in_arrivals; last apply ARR.
+              * by move: QUIET => /implyP QUIET; apply QUIET.
+          - apply negbT in EX; rewrite negb_exists in EX; move: EX => /forallP ALL'.
+            have ALL: forall t, t1 < t <= t1 + delta -> ~ quiet_time t.
+            { move => t /andP [GTt LEt] QUIET; rewrite -ltnS in LEt.
+              specialize (ALL' (Ordinal LEt)); rewrite negb_and /= GTt orFb in ALL'. 
+              move: ALL' => /negP ALL'; apply ALL'; clear ALL'.
+              apply/allP; intros j_hp ARR; apply/implyP; intro HP.
+              apply QUIET; eauto 2 using in_arrivals_implies_arrived, ARR, in_arrivals_implies_arrived_before.
+            } clear ALL'; exfalso.
+            have TOOMUCH := busy_interval_workload_larger_than_interval.
+            have BOUNDED := H_workload_is_bounded.
+              by move: (leq_trans (TOOMUCH ALL) BOUNDED); rewrite ltnn.                  
+        Qed.
+        
+      End UpperBound.
+
+    End BoundingBusyInterval.
+
+    (** In this section, we show that from a workload bound we can infer
+           the existence of a busy interval. *)
+    Section BusyIntervalFromWorkloadBound.
+
+      (** Let priority_inversion_bound be a constant that bounds the length of a priority inversion. *)
+      Variable priority_inversion_bound: duration.
+      Hypothesis H_priority_inversion_is_bounded:
+        is_priority_inversion_bounded_by priority_inversion_bound.
+
+      (** Assume that for some positive delta, the sum of requested workload at
+             time (t1 + delta) and priority inversion is bounded by delta (i.e., the supply). *)
+      Variable delta: duration.
+      Hypothesis H_delta_positive: delta > 0.
+      Hypothesis H_workload_is_bounded:
+        forall t, priority_inversion_bound + hp_workload t (t + delta) <= delta.
+
+      (** Next, we assume that job j has positive cost, from which we can
+             infer that there is a time in which j is pending. *)
+      Hypothesis H_positive_cost: job_cost j > 0.
+
+      (** Therefore there must exists a busy interval [t1, t2) that
+             contains the arrival time of j. *)
+      Corollary exists_busy_interval:
+        exists t1 t2, 
+          t1 <= job_arrival j < t2 /\
+          t2 <= t1 + delta /\
+          busy_interval t1 t2.
+      Proof. 
+        have PREFIX := exists_busy_interval_prefix.
+        move: (H_workload_is_bounded) => WORK.
+        feed (PREFIX (job_arrival j)).
+        { apply/andP; split; first by apply leqnn.
+          rewrite /completed_by /service.
+          rewrite ignore_service_before_arrival // /service_during.
+          rewrite big_geq; last by apply leqnn.
+            by rewrite -ltnNge.
+        }
+        move: PREFIX => [t1 [PREFIX /andP [GE1 GEarr]]].
+        have BOUNDED := busy_interval_is_bounded
+                          (job_arrival j) t1  PREFIX priority_inversion_bound _ delta
+                          H_delta_positive.            
+        feed_n 2 BOUNDED; try done.
+        move: BOUNDED => [t2 [GE2 BUSY]].
+        exists t1, t2; split.
+        { apply/andP; split; first by done.
+          apply contraT; rewrite -leqNgt; intro BUG.
+          move: BUSY PREFIX => [[LE12 _] QUIET] [_ [_ [NOTQUIET _]]].
+          feed (NOTQUIET t2); first by apply/andP; split.
+            by exfalso; apply NOTQUIET.
+        }
+          by split. 
+      Qed.
+      
+    End BusyIntervalFromWorkloadBound.
+
+    (** If we know that the workload is bounded, we can also use the
+           busy interval to infer a response-time bound. *)
+    Section ResponseTimeBoundFromBusyInterval.
+
+      (** Let priority_inversion_bound be a constant that bounds the length of a priority inversion. *)
+      Variable priority_inversion_bound: duration.
+      Hypothesis H_priority_inversion_is_bounded:
+        is_priority_inversion_bounded_by priority_inversion_bound.
+
+      (** Assume that for some positive delta, the sum of requested workload at
+             time (t1 + delta) and priority inversion is bounded by delta (i.e., the supply). *)
+      Variable delta: duration.
+      Hypothesis H_delta_positive: delta > 0.
+      Hypothesis H_workload_is_bounded:
+        forall t, priority_inversion_bound + hp_workload t (t + delta) <= delta.
+
+      (** Then, job j must complete by (job_arrival j + delta). *)
+      Lemma busy_interval_bounds_response_time:
+        job_completed_by j (job_arrival j + delta).
+      Proof.
+        have BUSY := exists_busy_interval priority_inversion_bound _ delta.
+        move: (posnP (@job_cost _ H2 j)) => [ZERO|POS].
+        { by rewrite /job_completed_by /completed_by ZERO. }
+        feed_n 4 BUSY; try by done.
+        move: BUSY => [t1 [t2 [/andP [GE1 LT2] [GE2 BUSY]]]].
+        apply completion_monotonic with (t := t2); try (by done);
+          first by apply leq_trans with (n := t1 + delta); [| by rewrite leq_add2r].
+        apply job_completes_within_busy_interval with (t1 := t1); try by done.
+      Qed.
+
+    End ResponseTimeBoundFromBusyInterval.
+
+  End BoundingBusyInterval.
+
+End ExistsBusyIntervalJLFP.
diff --git a/restructuring/analysis/facts/no_carry_in_exists.v b/restructuring/analysis/facts/no_carry_in_exists.v
new file mode 100644
index 000000000..e5d53fbc9
--- /dev/null
+++ b/restructuring/analysis/facts/no_carry_in_exists.v
@@ -0,0 +1,318 @@
+From rt.util Require Export all.
+From rt.restructuring.behavior Require Export all.
+From rt.restructuring.analysis.basic_facts Require Export all.
+From rt.restructuring Require Export model.job model.task.
+From rt.restructuring.model.schedule Require Export work_conserving priority_based.priorities.
+From rt.restructuring.analysis.definitions Require Export no_carry_in busy_interval priority_inversion.
+From rt.restructuring.analysis.facts Require Export busy_interval_exists.
+
+(** Throughout the file we assume for the classic Liu & Layland model
+   of readiness without jitter and no self-suspensions, where prending
+   jobs are always ready. *)
+From rt.restructuring.model Require Import readiness.basic.
+
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq fintype bigop.
+
+(** * Existence of No Carry-In Instant *)
+
+(** In this section, we derive an alternative condition for the existence of 
+       a busy interval. The new condition requires the total workload (instead 
+       of the high-priority workload) generated by the task set to be bounded. *)
+
+(** Next, we derive a sufficient condition for existence of
+    no carry-in instant for uniprocessor for JLFP schedulers *)
+Section ExistsNoCarryIn.
+  
+  (** Consider any type of tasks ... *)
+  Context {Task : TaskType}.
+  Context `{TaskCost Task}.
+
+  (**  ... and any type of jobs associated with these tasks. *)
+  Context {Job : JobType}.
+  Context `{JobTask Job Task}.
+  Context `{JobArrival Job}.
+  Context `{JobCost Job}.    
+
+  (** Consider any arrival sequence with consistent arrivals. *)
+  Variable arr_seq : arrival_sequence Job.
+  Hypothesis H_arrival_times_are_consistent : consistent_arrival_times arr_seq.
+  
+  (** Next, consider any ideal uniprocessor schedule of this arrival sequence ... *)
+  Variable sched : schedule (ideal.processor_state Job).
+  Hypothesis H_jobs_come_from_arrival_sequence:
+    jobs_come_from_arrival_sequence sched arr_seq.
+  
+  (** ... where jobs do not execute before their arrival or after completion. *)
+  Hypothesis H_jobs_must_arrive_to_execute : jobs_must_arrive_to_execute sched.
+  Hypothesis H_completed_jobs_dont_execute : completed_jobs_dont_execute sched.
+
+  (** Assume a given JLFP policy. *)
+  Variable higher_eq_priority : JLFP_policy Job. 
+  
+  (** For simplicity, let's define some local names. *)
+  Let job_pending_at := pending sched.
+  Let job_completed_by := completed_by sched.
+  Let arrivals_between := arrivals_between arr_seq.
+  Let no_carry_in := no_carry_in arr_seq sched.
+  Let quiet_time := quiet_time arr_seq sched higher_eq_priority.
+
+  (** The fact that there is no carry-in at time instant t
+         trivially implies that t is a quiet time. *)
+  Lemma no_carry_in_implies_quiet_time :
+    forall j t,
+      no_carry_in t ->
+      quiet_time j t.
+  Proof.
+      by intros j t FQT j_hp ARR HP BEF; apply FQT.
+  Qed.
+
+  (** Assume that the schedule is work-conserving, ... *)
+  Hypothesis H_work_conserving : work_conserving arr_seq sched.
+
+  (** ... and there are no duplicate job arrivals. *)
+  Hypothesis H_arrival_sequence_is_a_set:
+    arrival_sequence_uniq arr_seq.
+  
+  (** We show that an idle time implies no carry in at this time instant. *)
+  Lemma idle_instant_implies_no_carry_in_at_t :
+    forall t,
+      is_idle sched t ->
+      no_carry_in t.
+  Proof.
+    intros ? IDLE j ARR HA.
+    apply/negPn/negP; intros NCOMPL.
+    move: IDLE => /eqP IDLE.
+    move: (H_work_conserving j t ARR) => NIDLE. 
+    feed NIDLE.
+    { apply/andP; split; last first.
+      { by rewrite scheduled_at_def IDLE. }
+      { by apply/andP; split; [apply ltnW | done]. }
+    }
+    move: NIDLE => [j' SCHED].
+      by rewrite scheduled_at_def IDLE in SCHED.
+  Qed.
+  
+  (** Moreover, an idle time implies no carry in at the next time instant. *)
+  Lemma idle_instant_implies_no_carry_in_at_t_pl_1 :
+    forall t,
+      is_idle sched t ->
+      no_carry_in t.+1.
+  Proof.
+    intros ? IDLE j ARR HA.
+    apply/negPn/negP; intros NCOMPL.
+    move: IDLE => /eqP IDLE.
+    move: (H_work_conserving j t ARR) => NIDLE. 
+    feed NIDLE.
+    { apply/andP; split; last first.
+      { by rewrite scheduled_at_def IDLE. }
+      { apply/andP; split; first by done.
+        move: NCOMPL => /negP NC1; apply/negP; intros NC2; apply: NC1.
+          by apply completion_monotonic with t. 
+      }  
+    }
+    move: NIDLE => [j' SCHED].
+      by rewrite scheduled_at_def IDLE in SCHED.
+  Qed.
+  
+  (** Let the priority relation be reflexive. *)
+  Hypothesis H_priority_is_reflexive: reflexive_priorities.
+  
+  (** Recall the notion of workload of all jobs released in a given interval [t1, t2)... *)
+  Let total_workload t1 t2 :=
+    workload_of_jobs predT (arrivals_between t1 t2).
+
+  (** ... and total service of jobs within some time interval [t1, t2). *)
+  Let total_service t1 t2 :=
+    service_of_jobs sched predT (arrivals_between 0 t2) t1 t2.
+  
+  (** Assume that for some positive Δ, the sum of requested workload 
+         at time (t + Δ) is bounded by delta (i.e., the supply). 
+         Note that this assumption bounds the total workload of
+         jobs released in a time interval [t, t + Δ) regardless of 
+         their priorities. *)
+  Variable Δ: duration.
+  Hypothesis H_delta_positive: Δ > 0.
+  Hypothesis H_workload_is_bounded: forall t, total_workload t (t + Δ) <= Δ.
+
+  (** Next we prove that since for any time instant t there is a point where 
+         the total workload is upper-bounded by the supply the processor encounters 
+         no carry-in instants at least every Δ time units. *)
+  Section ProcessorIsNotTooBusy.
+
+    (** We start by proving that the processor has no carry-in at 
+           the beginning (i.e., has no carry-in at time instant 0). *)
+    Lemma no_carry_in_at_the_beginning :
+      no_carry_in 0.
+    Proof.
+      intros s ARR AB; exfalso.
+        by rewrite /arrived_before ltn0 in AB.
+    Qed.
+
+    (** In this section, we prove that for any time instant t there
+           exists another time instant t' ∈ (t, t + Δ] such that the 
+           processor has no carry-in at time t'. *)
+    Section ProcessorIsNotTooBusyInduction. 
+
+      (** Consider an arbitrary time instant t... *)
+      Variable t: duration.
+      
+      (** ...such that the processor has no carry-in at time t. *)
+      Hypothesis H_no_carry_in: no_carry_in t.
+
+      (** First, recall that the total service is bounded by the total workload. Therefore
+             the total service of jobs in the interval [t, t + Δ) is bounded by Δ. *)
+      Lemma total_service_is_bounded_by_Δ :
+        total_service t (t + Δ) <= Δ.
+      Proof.
+        unfold total_service. 
+        rewrite -{3}[Δ]addn0 -{2}(subnn t) addnBA // [in X in _ <= X]addnC.
+        apply service_of_jobs_le_length_of_interval'.
+          by eapply arrivals_uniq; eauto 2.
+      Qed.
+
+      (** Next we consider two cases: 
+             (1) The case when the total service is strictly less than Δ, 
+             (2) And when the total service is equal to Δ. *)
+
+      (** In the first case, we use the pigeonhole principle to conclude 
+             that there is an idle time instant; which in turn implies existence
+             of a time instant with no carry-in. *)
+      Lemma low_total_service_implies_existence_of_time_with_no_carry_in :
+        total_service t (t + Δ) < Δ ->
+        exists δ, δ < Δ /\ no_carry_in (t.+1 + δ).
+      Proof.
+        unfold total_service; intros LT.
+        rewrite -{3}[Δ]addn0 -{2}(subnn t) addnBA // [Δ + t]addnC in LT.
+        eapply low_service_implies_existence_of_idle_time in LT; eauto. 
+        move: LT => [t_idle [/andP [LEt GTe] IDLE]].
+        move: LEt; rewrite leq_eqVlt; move => /orP [/eqP EQ|LT].
+        { exists 0; split; first done.
+          rewrite addn0; subst t_idle.
+          intros s ARR BEF.
+          apply idle_instant_implies_no_carry_in_at_t_pl_1 in IDLE; try done.
+            by apply IDLE.
+        }
+        have EX: exists γ, t_idle = t + γ.
+        { by exists (t_idle - t); rewrite subnKC // ltnW. }
+        move: EX => [γ EQ]; subst t_idle; rewrite ltn_add2l in GTe.
+        rewrite -{1}[t]addn0 ltn_add2l in LT.
+        exists (γ.-1); split. 
+        - apply leq_trans with γ. by rewrite prednK. by rewrite ltnW.
+        - rewrite -subn1 -addn1 -addnA subnKC //.
+          intros s ARR BEF.
+            by apply idle_instant_implies_no_carry_in_at_t.
+      Qed.
+      
+      (** In the second case, the total service within the time interval [t, t + Δ) is equal to Δ. 
+             On the other hand, we know that the total workload is lower-bounded by the total service
+             and upper-bounded by Δ. Therefore, the total workload is equal to total service this
+             implies completion of all jobs by time [t + Δ] and hence no carry-in at time [t + Δ]. *)
+      Lemma completion_of_all_jobs_implies_no_carry_in :
+        total_service t (t + Δ) = Δ ->
+        no_carry_in (t + Δ).
+      Proof.
+        unfold total_service; intros EQserv.
+        move: (H_workload_is_bounded t); move => WORK.
+        have EQ: total_workload 0 (t + Δ) = service_of_jobs sched predT (arrivals_between 0 (t + Δ)) 0 (t + Δ).
+        { intros.
+          have COMPL := all_jobs_have_completed_impl_workload_eq_service
+                          arr_seq H_arrival_times_are_consistent sched
+                          H_jobs_must_arrive_to_execute
+                          H_completed_jobs_dont_execute
+                          predT 0 t t.
+          feed COMPL; try done.
+          { intros j A B; apply H_no_carry_in.
+            - eapply in_arrivals_implies_arrived; eauto 2.
+            - eapply in_arrivals_implies_arrived_between in A; eauto 2.
+          }
+          apply/eqP; rewrite eqn_leq; apply/andP; split;
+            last by apply service_of_jobs_le_workload;
+            auto using ideal_proc_model_provides_unit_service.
+          rewrite /total_workload (workload_of_jobs_cat arr_seq t); last first.
+          apply/andP; split; [by done | by rewrite leq_addr].
+          rewrite (service_of_jobs_cat_scheduling_interval _ _ _ _ _ _ _ t); try done; first last.
+          { by apply/andP; split; [by done | by rewrite leq_addr]. }
+          rewrite COMPL -addnA leq_add2l. 
+          rewrite -service_of_jobs_cat_arrival_interval; last first.
+          apply/andP; split; [by done| by rewrite leq_addr].
+          rewrite EQserv.
+            by apply H_workload_is_bounded.
+        }  
+        intros s ARR BEF.
+        eapply workload_eq_service_impl_all_jobs_have_completed; eauto 2; try done.
+          by eapply arrived_between_implies_in_arrivals; eauto 2.
+      Qed.
+
+    End ProcessorIsNotTooBusyInduction.
+
+    (** Finally, we show that any interval of length Δ contains a time instant with no carry-in. *)
+    Lemma processor_is_not_too_busy :
+      forall t, exists δ, δ < Δ /\ no_carry_in (t + δ).
+    Proof.
+      induction t.
+      { by exists 0; split; [ | rewrite addn0; apply no_carry_in_at_the_beginning]. }
+      { move: IHt => [δ [LE FQT]].
+        move: (posnP δ) => [Z|POS]; last first.
+        { exists (δ.-1); split.
+          - by apply leq_trans with δ; [rewrite prednK | apply ltnW]. 
+          - by rewrite -subn1 -addn1 -addnA subnKC //.
+        } subst δ; rewrite addn0 in FQT; clear LE.
+        move: (total_service_is_bounded_by_Δ t); rewrite leq_eqVlt; move => /orP [/eqP EQ | LT].
+        - exists (Δ.-1); split.
+          + by rewrite prednK. 
+          + by rewrite addSn -subn1 -addn1 -addnA subnK; first apply completion_of_all_jobs_implies_no_carry_in.
+        - by apply low_total_service_implies_existence_of_time_with_no_carry_in. 
+      }
+    Qed.
+    
+  End ProcessorIsNotTooBusy.
+  
+  (** Consider an arbitrary job j with positive cost. *)
+  Variable j : Job.
+  Hypothesis H_from_arrival_sequence : arrives_in arr_seq j.
+  Hypothesis H_job_cost_positive : job_cost_positive j.    
+
+  (** We show that there must exist a busy interval [t1, t2) that
+         contains the arrival time of j. *)
+  Corollary exists_busy_interval_from_total_workload_bound :
+    exists t1 t2, 
+      t1 <= job_arrival j < t2 /\
+      t2 <= t1 + Δ /\
+      busy_interval arr_seq sched higher_eq_priority j t1 t2.
+  Proof.
+    rename H_from_arrival_sequence into ARR, H_job_cost_positive into POS.
+    edestruct (exists_busy_interval_prefix
+                 arr_seq H_arrival_times_are_consistent sched higher_eq_priority j ARR H_priority_is_reflexive (job_arrival j))
+      as [t1 [PREFIX GE]].
+    apply job_pending_at_arrival; auto. 
+    move: GE => /andP [GE1 _].
+    exists t1; move: (processor_is_not_too_busy t1.+1) => [δ [LE QT]].
+    apply no_carry_in_implies_quiet_time with (j := j) in QT.
+    have EX: exists t2, ((t1 < t2 <= t1.+1 + δ) && quiet_time_dec arr_seq sched higher_eq_priority j t2).
+    { exists (t1.+1 + δ); apply/andP; split.
+      - by apply/andP; split; first rewrite addSn ltnS leq_addr. 
+      - by apply/quiet_time_P. }
+    move: (ex_minnP EX) => [t2 /andP [/andP [GTt2 LEt2] QUIET] MIN]; clear EX.
+    have NEQ: t1 <= job_arrival j < t2.
+    { apply/andP; split; first by done. 
+      rewrite ltnNge; apply/negP; intros CONTR.
+      move: (PREFIX) => [_ [_ [NQT _]]].
+      move: (NQT t2); clear NQT; move  => NQT.
+      feed NQT; first by (apply/andP; split; [|rewrite ltnS]). 
+        by apply: NQT; apply/quiet_time_P.
+    }
+    exists t2; split; last split; first by done. 
+    { apply leq_trans with (t1.+1 + δ); [by done | by rewrite addSn ltn_add2l]. }
+    { move: PREFIX => [_ [QTt1 [NQT _]]]; repeat split; try done.
+      - move => t /andP [GEt LTt] QTt.
+        feed (MIN t).
+        { apply/andP; split.
+          + by apply/andP; split; last (apply leq_trans with t2; [apply ltnW | ]).
+          + by apply/quiet_time_P.
+        }
+          by move: LTt; rewrite ltnNge; move => /negP LTt; apply: LTt.
+      - by apply/quiet_time_P. 
+    }
+  Qed.
+   
+End ExistsNoCarryIn.
diff --git a/util/all.v b/util/all.v
index 01211d396..507076a4a 100644
--- a/util/all.v
+++ b/util/all.v
@@ -12,5 +12,6 @@ Require Export rt.util.step_function.
 Require Export rt.util.epsilon.
 Require Export rt.util.search_arg.
 Require Export rt.util.rel.
+Require Export rt.util.minmax.
 Require Export rt.util.nondecreasing.
 Require Export rt.util.rewrite_facilities.
diff --git a/util/minmax.v b/util/minmax.v
new file mode 100644
index 000000000..59f77314b
--- /dev/null
+++ b/util/minmax.v
@@ -0,0 +1,128 @@
+Require Import rt.util.tactics rt.util.notation rt.util.nat rt.util.list.
+From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq fintype bigop.
+
+(* Additional lemmas about max. *)
+Section ExtraLemmas.
+
+  Lemma leq_bigmax_cond_seq (T : eqType) (P : pred T) (r : seq T) F i0 :
+    i0 \in r -> P i0 -> F i0 <= \max_(i <- r | P i) F i.
+  Proof.
+    intros IN0 Pi0; by rewrite (big_rem i0) //= Pi0 leq_maxl.
+  Qed.
+
+  Lemma bigmax_sup_seq:
+    forall (T: eqType) (i: T) r (P: pred T) m F,
+      i \in r -> P i -> m <= F i -> m <= \max_(i <- r| P i) F i.
+  Proof.
+    intros.
+    induction r.
+    - by rewrite in_nil  in H.
+      move: H; rewrite in_cons; move => /orP [/eqP EQA | IN].
+      {
+        clear IHr; subst a.
+        rewrite (big_rem i) //=; last by rewrite in_cons; apply/orP; left.
+        apply leq_trans with (F i); first by done.
+          by rewrite H0 leq_maxl.
+      }
+      {
+        apply leq_trans with (\max_(i0 <- r | P i0) F i0); first by apply IHr.
+        rewrite [in X in _ <= X](big_rem a) //=; last by rewrite in_cons; apply/orP; left.
+
+        have Ob: a == a; first by done.
+          by rewrite Ob leq_maxr.
+      }
+  Qed.
+
+  Lemma bigmax_leq_seqP (T : eqType) (P : pred T) (r : seq T) F m :
+    reflect (forall i, i \in r -> P i -> F i <= m)
+            (\max_(i <- r | P i) F i <= m).
+  Proof.
+    apply: (iffP idP) => leFm => [i IINR Pi|];
+      first by apply: leq_trans leFm; apply leq_bigmax_cond_seq.
+    rewrite big_seq_cond; elim/big_ind: _ => // m1 m2.
+      by intros; rewrite geq_max; apply/andP; split. 
+      by move: m2 => /andP [M1IN Pm1]; apply: leFm.
+  Qed.
+
+  Lemma leq_big_max (T : eqType) (P : pred T) (r : seq T) F1 F2 :
+    (forall i, i \in r -> P i -> F1 i <= F2 i) ->
+    \max_(i <- r | P i) F1 i <= \max_(i <- r | P i) F2 i.
+  Proof.
+    intros; apply /bigmax_leq_seqP; intros.
+    specialize (H i); feed_n 2 H; try(done).
+    rewrite (big_rem i) //=; rewrite H1.
+      by apply leq_trans with (F2 i); [ | rewrite leq_maxl].
+  Qed.
+
+  Lemma bigmax_ord_ltn_identity n :
+    n > 0 ->
+    \max_(i < n) i < n.
+  Proof.
+    intros LT.
+    destruct n; first by rewrite ltn0 in LT.
+    clear LT.
+    induction n; first by rewrite big_ord_recr /= big_ord0 maxn0.
+    rewrite big_ord_recr /=.
+      by unfold maxn at 1; rewrite IHn.
+  Qed.
+    
+  Lemma bigmax_ltn_ord n (P : pred nat) (i0: 'I_n) :
+    P i0 ->
+    \max_(i < n | P i) i < n.
+  Proof.
+    intros LT.
+    destruct n; first by destruct i0 as [i0 P0]; move: (P0) => P0'; rewrite ltn0 in P0'.
+    rewrite big_mkcond.
+    apply leq_ltn_trans with (n := \max_(i < n.+1) i).
+    {
+      apply/bigmax_leqP; ins.
+      destruct (P i); last by done.
+      by apply leq_bigmax_cond.
+    }
+    by apply bigmax_ord_ltn_identity.
+  Qed.
+
+  Lemma bigmax_pred n (P : pred nat) (i0: 'I_n) :
+    P (i0) ->
+    P (\max_(i < n | P i) i).
+  Proof.
+    intros PRED.
+    induction n.
+    {
+      destruct i0 as [i0 P0].
+      by move: (P0) => P1; rewrite ltn0 in P1. 
+    }
+    rewrite big_mkcond big_ord_recr /=. destruct (P n) eqn:Pn.
+    {
+      destruct n; first by rewrite big_ord0 maxn0.
+      unfold maxn at 1.
+      destruct (\max_(i < n.+1) (match P (@nat_of_ord (S n) i) return nat with
+                    | true => @nat_of_ord (S n) i
+                    | false => O
+                                 end) < n.+1) eqn:Pi; first by rewrite Pi.
+      exfalso.
+      apply negbT in Pi; move: Pi => /negP BUG.
+      apply BUG. 
+      apply leq_ltn_trans with (n := \max_(i < n.+1) i).
+      {
+        apply/bigmax_leqP; ins.
+        destruct (P i); last by done.
+        by apply leq_bigmax_cond.
+      }
+      by apply bigmax_ord_ltn_identity.
+    }
+    {
+      rewrite maxn0.
+      rewrite -big_mkcond /=.
+      have LT: i0 < n.
+      {
+        rewrite ltn_neqAle; apply/andP; split;
+          last by rewrite -ltnS; apply ltn_ord.
+        apply/negP; move => /eqP BUG.
+        by rewrite -BUG PRED in Pn.
+      }
+      by rewrite (IHn (Ordinal LT)).
+    }
+  Qed.
+    
+End ExtraLemmas.
\ No newline at end of file
diff --git a/util/nat.v b/util/nat.v
index ef6f23620..213aded67 100644
--- a/util/nat.v
+++ b/util/nat.v
@@ -9,6 +9,13 @@ Section NatLemmas.
       m >= n ->
       m - n + p = m + p - n.
   Proof. by ins; ssromega. Qed.
+
+  Lemma subh2 :
+    forall m1 m2 n1 n2,
+      m1 >= m2 ->
+      n1 >= n2 ->
+      (m1 + n1) - (m2 + n2) = m1 - m2 + (n1 - n2).
+  Proof. by ins; ssromega. Qed.
   
   Lemma subh3:
     forall m n p,
diff --git a/util/sum.v b/util/sum.v
index e6c4f7e98..b1a2563a1 100644
--- a/util/sum.v
+++ b/util/sum.v
@@ -1,4 +1,4 @@
-From rt.util Require Import tactics notation nat ssromega.
+From rt.util Require Import tactics notation nat ssromega. 
 From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq fintype bigop path.
 
 (* Lemmas about sum. *)
@@ -196,6 +196,53 @@ Section ExtraLemmas.
         by rewrite ltnS ltnW.
     }
   Qed.
-
   
 End ExtraLemmas.
+
+(* Lemmas about arithmetic with sums. *)
+Section SumArithmetic.
+
+  Lemma sum_seq_diff:
+    forall (T:eqType) (rs: seq T) (F G : T -> nat),
+      (forall i : T, i \in rs -> G i <= F i) ->
+      \sum_(i <- rs) (F i - G i) = \sum_(i <- rs) F i - \sum_(i <- rs) G i.
+  Proof.
+    intros.
+    induction rs; first by rewrite !big_nil subn0. 
+    rewrite !big_cons subh2.
+    - apply/eqP; rewrite eqn_add2l; apply/eqP; apply IHrs.
+        by intros; apply H; rewrite in_cons; apply/orP; right.
+    - by apply H; rewrite in_cons; apply/orP; left.
+    - rewrite big_seq_cond [in X in _ <= X]big_seq_cond.
+      rewrite leq_sum //; move => i /andP [IN _].
+        by apply H; rewrite in_cons; apply/orP; right.
+  Qed.
+  
+  Lemma sum_diff:
+    forall n F G,
+      (forall i (LT: i < n), F i >= G i) ->
+      \sum_(0 <= i < n) (F i - G i) =
+      (\sum_(0 <= i < n) (F i)) - (\sum_(0 <= i < n) (G i)).       
+  Proof.
+    intros n F G ALL.
+    rewrite sum_seq_diff; first by done.
+    move => i; rewrite mem_index_iota; move => /andP [_ LT].
+      by apply ALL.
+  Qed.
+
+  Lemma sum_pred_diff:
+    forall (T: eqType) (rs: seq T) (P: T -> bool) (F: T -> nat),
+      \sum_(r <- rs | P r) F r =
+      \sum_(r <- rs) F r - \sum_(r <- rs | ~~ P r) F r.
+  Proof.
+    clear; intros.
+    induction rs; first by rewrite !big_nil subn0.
+    rewrite !big_cons !IHrs; clear IHrs.
+    case (P a); simpl; last by rewrite subnDl.
+    rewrite addnBA; first by done.
+    rewrite big_mkcond leq_sum //.
+    intros t _.
+      by case (P t).
+  Qed.
+  
+End SumArithmetic.
\ No newline at end of file
-- 
GitLab