From febf2ef8004127ef0ba3b40c70aabf4164c8f003 Mon Sep 17 00:00:00 2001
From: Felipe Cerqueira <felipec@mpi-sws.org>
Date: Tue, 10 Nov 2015 09:01:11 +0100
Subject: [PATCH] Start Guan analysis

---
 GuanDefs.v | 629 ++++++++++++++++++++++++++++++++++++++++++++
 GuanFP.v   | 753 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 Vbase.v    |   4 +-
 helper.v   |  35 ++-
 4 files changed, 1408 insertions(+), 13 deletions(-)
 create mode 100644 GuanDefs.v
 create mode 100644 GuanFP.v

diff --git a/GuanDefs.v b/GuanDefs.v
new file mode 100644
index 000000000..80655854c
--- /dev/null
+++ b/GuanDefs.v
@@ -0,0 +1,629 @@
+Require Import Vbase TaskDefs JobDefs TaskArrivalDefs ScheduleDefs
+               PlatformDefs WorkloadDefs BertognaResponseTimeDefs SchedulabilityDefs PriorityDefs
+               ResponseTimeDefs divround helper
+               ssreflect ssrbool eqtype ssrnat seq fintype bigop div path tuple.
+
+Module ResponseTimeAnalysisGuan.
+
+  Import Job SporadicTaskset ScheduleOfTaskWithJitter Schedulability ResponseTime Priority SporadicTaskArrival.
+  Export Workload ResponseTimeAnalysis.
+
+  Section InterferenceBoundGuan.
+
+    Context {sporadic_task: eqType}.
+    Variable task_cost: sporadic_task -> nat.
+    Variable task_period: sporadic_task -> nat.
+    Variable task_deadline: sporadic_task -> nat.
+
+    Variable num_cpus: nat.
+    Variable higher_eq_priority: fp_policy sporadic_task.
+    
+    (* Let tsk be the task to be analyzed. *)
+    Variable tsk: sporadic_task.
+
+    Let task_with_response_time := (sporadic_task * time)%type.
+    
+    (* Assume a known response-time bound for each interfering task ... *)
+    Variable R_prev: seq task_with_response_time.
+
+    (* ... and an interval length delta. *)
+    Variable delta: time.
+
+    Section TasksetPartition.
+
+      (* Let's filter the list of task and response-times so that it only has interfering tasks. *)
+      Let interfering_tasks :=
+        [seq (tsk_other, R) <- R_prev | is_interfering_task_fp tsk higher_eq_priority tsk_other].
+
+      (* After that, we list all possible pairs of subsets of that list:
+           [(subset0, subset1), (subset0, subset2), ...]*)
+      Let all_combinations :=
+        zip (powerset interfering_tasks) (powerset interfering_tasks).
+
+      (* Finally, we let (NC, CI) be all the pairs of subsets that are partitions
+         and such that the number of carried-in tasks is at most num_cpus - 1. *)
+      Definition valid_NC_CI_partitions :=
+        [seq (NC, CI) <- all_combinations | no_intersection NC CI &&
+                                            (size CI <= num_cpus - 1)].
+    End TasksetPartition.
+
+    (* Based on Bertogna and Cirinei's interference bound, ... *)
+    Let I := interference_bound task_cost task_period tsk delta.
+
+    (* Guan et al.'s analysis defines an interference bound based on the maximum interference
+       across all partitions of (NC, CI), i.e., non-carried-in and carried-in tasks.
+       For the sake of simplicity, we compute the maximum by enumeration, instead of using
+       a linear-time algorithm. *)
+    Definition guan_interference_bound :=
+      \max_((NC, CI) <- valid_NC_CI_partitions)
+       (\sum_((tsk_other, R) <- NC) I (tsk_other,R) +
+         \sum_((tsk_other, R) <- CI) I (tsk_other,R)).
+
+  End InterferenceBoundGuan.
+
+  Section ResponseTimeBoundGuan.
+
+    Context {sporadic_task: eqType}.
+    Variable task_cost: sporadic_task -> nat.
+    Variable task_period: sporadic_task -> nat.
+    Variable task_deadline: sporadic_task -> nat.
+    
+    Context {Job: eqType}.
+    Variable job_cost: Job -> nat.
+    Variable job_deadline: Job -> nat.
+    Variable job_task: Job -> sporadic_task.
+    
+    (* Assume any job arrival sequence... *)
+    Context {arr_seq: arrival_sequence Job}.
+
+    (* ... in which jobs arrive sporadically and have valid parameters. *)
+    Hypothesis H_sporadic_tasks:
+      sporadic_task_model task_period arr_seq job_task.
+    Hypothesis H_valid_job_parameters:
+      forall (j: JobIn arr_seq),
+        valid_sporadic_job task_cost task_deadline job_cost job_deadline job_task j.
+
+    (* Consider any schedule such that...*)
+    Variable num_cpus: nat.
+    Variable rate: Job -> processor num_cpus -> nat.
+    Variable sched: schedule num_cpus arr_seq.
+
+    (* ...jobs do not execute before their arrival times nor longer
+       than their execution costs. *)
+    Hypothesis H_jobs_execute_after_jitter:
+      jobs_must_arrive_to_execute sched.
+    Hypothesis H_completed_jobs_dont_execute:
+      completed_jobs_dont_execute job_cost rate sched.
+
+    (* Also assume that jobs do not execute in parallel, processors have
+       unit speed, and that there exists at least one processor. *)
+    Hypothesis H_no_parallelism:
+      jobs_dont_execute_in_parallel sched.
+    Hypothesis H_rate_equals_one :
+      forall j cpu, rate j cpu = 1.
+    Hypothesis H_at_least_one_cpu :
+      num_cpus > 0.
+
+    (* Assume that we have a task set where all tasks have valid
+       parameters and restricted deadlines. *)
+    Variable ts: taskset_of sporadic_task.
+    Hypothesis H_valid_task_parameters:
+      valid_sporadic_taskset task_cost task_period task_deadline ts.
+    Hypothesis H_restricted_deadlines:
+      forall tsk, tsk \in ts -> task_deadline tsk <= task_period tsk.
+
+    (* Next, consider a task tsk that is to be analyzed. *)
+    Variable tsk: sporadic_task.
+    Hypothesis task_in_ts: tsk \in ts.
+
+    Let no_deadline_is_missed_by_tsk (tsk: sporadic_task) :=
+      task_misses_no_deadline job_cost job_deadline job_task rate sched tsk.
+    Let is_response_time_bound (tsk: sporadic_task) :=
+      is_response_time_bound_of_task job_cost job_task tsk rate sched.
+
+    (* Assume a known response-time bound for any interfering task *)
+    Let task_with_response_time := (sporadic_task * time)%type.
+    Variable hp_bounds: seq task_with_response_time.
+    
+    (* We derive the response-time bounds for FP and EDF scheduling
+       separately. *)
+    Section UnderFPScheduling.
+
+      (* For FP scheduling, assume there exists a fixed task priority. *)
+      Variable higher_eq_priority: fp_policy sporadic_task.
+
+      Let interferes_with_tsk := is_interfering_task_fp tsk higher_eq_priority.
+      
+      (* Assume that for any interfering task, a response-time
+         bound R_other is known. *)
+      Hypothesis H_all_interfering_tasks_in_hp_bounds:
+        [seq tsk_hp <- ts | interferes_with_tsk tsk_hp] = unzip1 hp_bounds.
+
+      Lemma exists_R :
+        forall hp_tsk,
+          hp_tsk \in ts ->
+          interferes_with_tsk hp_tsk ->
+          exists R,
+            (hp_tsk, R) \in hp_bounds.
+      Proof.
+        intros hp_tsk IN INTERF.
+        rewrite -[hp_bounds]zip_unzip; apply exists_unzip2.
+        by rewrite zip_unzip -H_all_interfering_tasks_in_hp_bounds mem_filter; apply/andP.
+      Qed.      
+
+      Hypothesis H_response_time_of_interfering_tasks_is_known2:
+        forall hp_tsk R,
+          (hp_tsk, R) \in hp_bounds ->
+          is_response_time_bound_of_task job_cost job_task hp_tsk rate sched R.
+      
+      (* Assume that the response-time bounds are larger than task costs. *)
+      Hypothesis H_response_time_bounds_ge_cost:
+        forall hp_tsk R,
+          (hp_tsk, R) \in hp_bounds -> R >= task_cost hp_tsk.
+      
+      (* Assume that no deadline is missed by any interfering task, i.e.,
+         response-time bound R_other <= deadline. *)
+      Hypothesis H_interfering_tasks_miss_no_deadlines:
+        forall hp_tsk R,
+          (hp_tsk, R) \in hp_bounds -> R <= task_deadline hp_tsk.
+
+      (* Assume that the schedule satisfies the global scheduling
+         invariant, i.e., if any job of tsk is backlogged, all
+         the processors must be busy with jobs of equal or higher
+         priority. *)
+      Hypothesis H_global_scheduling_invariant:
+        forall (j: JobIn arr_seq) (t: time),
+          job_task j = tsk ->
+          backlogged job_cost rate sched j t ->
+          count
+            (fun tsk_other : sporadic_task =>
+               is_interfering_task_fp tsk higher_eq_priority tsk_other &&
+               task_is_scheduled job_task sched tsk_other t) ts = num_cpus.
+
+      (* Next, we define Bertogna and Cirinei's response-time bound recurrence *)
+      
+      (* Let R be any time. *)
+      Variable R: time.
+      
+      (* Bertogna and Cirinei's response-time analysis states that
+         if R is a fixed-point of the following recurrence, ... *)
+      Let I := total_interference_bound_fp task_cost task_period
+                             tsk hp_bounds R higher_eq_priority.
+      Hypothesis H_response_time_recurrence_holds :
+        R = task_cost tsk + (div_floor I num_cpus).
+
+      (*..., and R is no larger than the deadline of tsk, ...*)
+      Hypothesis H_response_time_no_larger_than_deadline:
+        R <= task_deadline tsk.
+
+      (* ..., then R bounds the response time of tsk. *)
+      Theorem bertogna_cirinei_response_time_bound_fp_with_jitter :
+        is_response_time_bound tsk R.
+      Proof.
+        unfold is_response_time_bound, is_response_time_bound_of_task,
+               job_has_completed_by, completed,
+               completed_jobs_dont_execute,
+               valid_sporadic_job_with_jitter,
+               valid_sporadic_job in *.
+        rename H_completed_jobs_dont_execute into COMP,
+               H_response_time_recurrence_holds into REC,
+               H_valid_job_parameters into PARAMS,
+               H_valid_task_parameters into TASK_PARAMS,
+               H_restricted_deadlines into RESTR,
+               H_response_time_of_interfering_tasks_is_known2 into RESP,
+               H_all_interfering_tasks_in_hp_bounds into FST,
+               H_interfering_tasks_miss_no_deadlines into NOMISS,
+               H_rate_equals_one into RATE,
+               H_global_scheduling_invariant into INVARIANT,
+               H_response_time_bounds_ge_cost into GE_COST.
+        intros j JOBtsk.
+        
+        (* For simplicity, let x denote per-task interference under FP
+           scheduling, and let X denote the total interference. *)
+        set x := fun hp_tsk =>
+          if (hp_tsk \in ts) && interferes_with_tsk hp_tsk then
+            task_interference job_cost job_task rate sched j
+                     (job_arrival j) (job_arrival j + R) hp_tsk
+          else 0.
+        set X := total_interference job_cost rate sched j (job_arrival j) (job_arrival j + R).
+
+        (* Let's recall the workload bound under FP scheduling. *)
+        set workload_bound := fun (tup: task_with_response_time) =>
+          let (tsk_k, R_k) := tup in
+            if interferes_with_tsk tsk_k then
+              W_jitter task_cost task_period task_jitter tsk_k R_k R
+            else 0.  
+        
+        (* Now we start the proof. Assume by contradiction that job j
+           is not complete at time (job_arrival j + R). *)
+        destruct (completed job_cost rate sched j (job_arrival j + R')) eqn:COMPLETED;
+          first by move: COMPLETED => /eqP COMPLETED; rewrite COMPLETED eq_refl.
+        apply negbT in COMPLETED; exfalso.
+
+        (* Note that j cannot have completed by job_arrival j + R either. *)
+        assert (COMPLETED': ~~ completed job_cost rate sched j (job_arrival j + R)).
+        {
+          apply/negP; unfold not; intro BUG.
+          apply completion_monotonic with (t' := job_arrival j + R') in BUG;
+            try (by ins);
+            [ by rewrite BUG in COMPLETED
+            | by unfold R'; rewrite addnA; apply leq_addr].
+        }
+        
+        (* Since j has not completed, recall the time when it is not
+           executing is the total interference. *)
+        exploit (complement_of_interf_equals_service job_cost rate sched j (job_arrival j)
+                                                     (job_arrival j + R));
+          last intro EQinterf; ins; unfold has_arrived;
+            first by apply leqnn.
+        rewrite {2}[_ + R]addnC -addnBA // subnn addn0 in EQinterf.
+
+        (* In order to derive a contradiction, we first show that
+           the interference x_k of any task is no larger than the
+           workload bound W_k. *)
+        assert (WORKLOAD: forall tsk_k,
+                            (tsk_k \in ts) && interferes_with_tsk tsk_k ->
+                            forall R_k, 
+                              (tsk_k, R_k) \in hp_bounds ->
+                              x tsk_k <= workload_bound (tsk_k, R_k)).   
+        {
+          move => tsk_k /andP [INk INTERk] R_k HPk.
+          unfold x, workload_bound; rewrite INk INTERk andbT.
+          exploit (exists_R tsk_k); [by ins | by ins | intro INhp; des].
+          apply leq_trans with (n := workload job_task rate sched tsk_k
+                                    (job_arrival j) (job_arrival j + R)).
+          {
+            unfold task_interference, workload.
+            apply leq_sum; intros t _.
+            rewrite -mulnb -[\sum_(_ < _) _]mul1n.
+            apply leq_mul; first by apply leq_b1.
+            destruct (task_is_scheduled job_task sched tsk_k t) eqn:SCHED; last by ins.
+            unfold task_is_scheduled in SCHED.
+            move: SCHED =>/exists_inP SCHED.
+            destruct SCHED as [cpu _ HAScpu].
+            rewrite -> bigD1 with (j := cpu); simpl; last by ins.
+            apply ltn_addr; unfold service_of_task, schedules_job_of_tsk in *.
+            by destruct (sched cpu t);[by rewrite HAScpu mul1n RATE|by ins].
+          }
+          {
+            apply workload_bounded_by_W_jitter with (task_deadline0 := task_deadline) (job_cost0 := job_cost) (job_deadline0 := job_deadline) (job_jitter0 := job_jitter); ins;
+              [ by rewrite RATE
+              | by apply TASK_PARAMS
+              | by apply RESTR
+              | by red; red; ins; apply (RESP tsk_k)  
+              | by apply GE_COST |].
+            red; red; move => j' /eqP JOBtsk' _;
+            unfold job_misses_no_deadline.
+            specialize (PARAMS j'); des.
+            rewrite PARAMS2 JOBtsk'.
+            apply completion_monotonic with (t := job_arrival j' + R0); ins;
+              [by rewrite leq_add2l; apply NOMISS | by apply (RESP tsk_k)].
+          }
+        }
+
+        (* In the remaining of the proof, we show that the workload bound
+           W_k is less than the task interference x (contradiction!).
+           For that, we require a few auxiliary lemmas: *)
+
+        (* 1) We show that the total interference X >= R - e_k + 1.
+              Otherwise, job j would have completed on time. *)
+        assert (INTERF: X >= R - task_cost tsk + 1).
+        {
+          unfold completed in COMPLETED'; rewrite addn1.
+          move: COMPLETED'; rewrite neq_ltn; move => /orP COMPLETED'; des;
+            last first.
+          {
+            apply (leq_ltn_trans (COMP j (job_arrival j + R))) in COMPLETED'.
+            by rewrite ltnn in COMPLETED'.
+          }
+          apply leq_trans with (n := R - service rate sched j (job_arrival j + R)); last first.
+          {
+            unfold service.
+            rewrite service_before_arrival_eq_service_during; ins;
+              last by apply arrival_before_jitter with (job_jitter0 := job_jitter).
+            rewrite EQinterf subKn; first by ins.
+            {
+              unfold total_interference.
+              rewrite -{1}[_ j]add0n big_addn addnC -addnBA // subnn addn0.
+              rewrite -{2}[R]subn0 -[R-_]mul1n -[1*_]addn0 -iter_addn.
+              by rewrite -big_const_nat leq_sum //; ins; apply leq_b1.
+            }
+          }
+          {
+            apply ltn_sub2l; last first.
+            {
+              apply leq_trans with (n := job_cost j); first by ins.
+              by rewrite -JOBtsk; specialize (PARAMS j); des; apply PARAMS1.
+            }
+            apply leq_trans with (n := job_cost j); first by ins.
+            apply leq_trans with (n := task_cost tsk);
+              first by rewrite -JOBtsk; specialize (PARAMS j); des; apply PARAMS1.
+            by rewrite REC; apply leq_addr.
+          }
+        }
+
+        (* 2) Then, we prove that the sum of the interference of each
+           task is equal to the total interference multiplied by the
+           number of processors. This holds because interference only
+           occurs when all processors are busy with some task. *)
+        assert(ALLBUSY: \sum_(tsk_k <- ts) x tsk_k = X * num_cpus).
+        {
+          unfold x, X, total_interference, task_interference.
+          rewrite -big_mkcond -exchange_big big_distrl /=.
+          apply eq_big_nat; move => t LTt.
+          destruct (backlogged job_cost rate sched j t) eqn:BACK;
+            last by rewrite (eq_bigr (fun i => 0));
+              [by rewrite big_const_seq iter_addn mul0n addn0 mul0n|by ins].
+          rewrite big_mkcond mul1n /=.
+          rewrite (eq_bigr (fun i =>
+                              (if (i \in ts) && interferes_with_tsk i &&
+                                             task_is_scheduled job_task sched i t then 1 else 0))); last first.
+          {
+            ins; destruct ((i \in ts) && interferes_with_tsk i) eqn:IN;
+              [by rewrite andTb | by rewrite andFb].
+          }
+          rewrite (eq_bigr (fun i => if (i \in ts) && true then (if interferes_with_tsk i && task_is_scheduled job_task sched i t then 1 else 0) else 0));
+            last by ins; destruct (i \in ts) eqn:IN; rewrite ?andTb ?andFb.
+          by rewrite -big_mkcond -big_seq_cond -big_mkcond sum1_count; apply (INVARIANT j).
+        }
+
+        (* 3) Next, we prove the auxiliary lemma from the paper. *)
+        assert (MINSERV: \sum_(tsk_k <- ts) x tsk_k >=
+                         (R - task_cost tsk + 1) * num_cpus ->
+               \sum_(tsk_k <- ts) minn (x tsk_k) (R - task_cost tsk + 1) >=
+               (R - task_cost tsk + 1) * num_cpus).
+        {
+          intro SUMLESS.
+          set more_interf := fun tsk_k => x tsk_k >= R - task_cost tsk + 1.
+          rewrite [\sum_(_ <- _) minn _ _](bigID more_interf) /=.
+          unfold more_interf, minn.
+          rewrite [\sum_(_ <- _ | R - _ + _ <= _)_](eq_bigr (fun i => R - task_cost tsk + 1));
+            last first.
+          {
+            intros i COND; rewrite leqNgt in COND.
+            destruct (R - task_cost tsk + 1 > x i); ins.
+          }
+          rewrite [\sum_(_ <- _ | ~~_)_](eq_big (fun i => x i < R - task_cost tsk + 1)
+                                                (fun i => x i));
+            [| by red; ins; rewrite ltnNge
+             | by intros i COND; rewrite -ltnNge in COND; rewrite COND].
+
+          (* Case 1 |A| = 0 *)
+          destruct (~~ has (fun i => R - task_cost tsk + 1 <= x i) ts) eqn:HASa.
+          {
+            rewrite [\sum_(_ <- _ | _ <= _) _]big_hasC; last by apply HASa.
+            rewrite big_seq_cond; move: HASa => /hasPn HASa.
+            rewrite add0n (eq_bigl (fun i => (i \in ts) && true));
+              last by red; intros tsk_k; destruct (tsk_k \in ts) eqn:INk;
+                [by rewrite andTb ltnNge; apply HASa | by rewrite andFb].
+            by rewrite -big_seq_cond.
+          } apply negbFE in HASa.
+          
+          set cardA := count (fun i => R - task_cost tsk + 1 <= x i) ts.
+          destruct (cardA >= num_cpus) eqn:CARD.
+          {
+            apply leq_trans with ((R - task_cost tsk + 1) * cardA);
+              first by rewrite leq_mul2l; apply/orP; right.
+            unfold cardA; rewrite -sum1_count big_distrr /=.
+            rewrite -[\sum_(_ <- _ | _) _]addn0.
+            by apply leq_add; [by apply leq_sum; ins; rewrite muln1|by ins].
+          } apply negbT in CARD; rewrite -ltnNge in CARD.
+
+          assert (GEsum: \sum_(i <- ts | x i < R - task_cost tsk + 1) x i >=
+                           (R - task_cost tsk + 1) * (num_cpus - cardA)).
+          {
+            set some_interference_A := fun t =>
+              backlogged job_cost rate sched j t &&
+              has (fun tsk_k => (interferes_with_tsk tsk_k &&
+                              ((x tsk_k) >= R - task_cost tsk + 1) &&
+                              task_is_scheduled job_task sched tsk_k t)) ts.      
+            set total_interference_B := fun t =>
+              backlogged job_cost rate sched j t *
+              count (fun tsk_k =>
+                interferes_with_tsk tsk_k &&
+                ((x tsk_k) < R - task_cost tsk + 1) &&
+                task_is_scheduled job_task sched tsk_k t) ts.
+
+            apply leq_trans with ((\sum_(job_arrival j <= t < job_arrival j + R)
+                                      some_interference_A t) * (num_cpus - cardA)).
+            {
+              rewrite leq_mul2r; apply/orP; right.
+              move: HASa => /hasP HASa; destruct HASa as [tsk_a INa LEa].
+              apply leq_trans with (n := x tsk_a); first by apply LEa.
+              unfold x, task_interference, some_interference_A.
+              destruct ((tsk_a \in ts) && interferes_with_tsk tsk_a) eqn:INTERFa;
+                last by ins.
+              move: INTERFa => /andP INTERFa; des.
+              apply leq_sum; ins.
+              destruct (backlogged job_cost rate sched j i);
+                [rewrite 2!andTb | by ins].
+              destruct (task_is_scheduled job_task sched tsk_a i) eqn:SCHEDa;
+                [apply eq_leq; symmetry | by ins].
+              apply/eqP; rewrite eqb1.
+              apply/hasP; exists tsk_a; first by ins.
+              apply/andP; split; last by ins.
+              by apply/andP; split; ins.
+            }
+            apply leq_trans with (\sum_(job_arrival j <= t < job_arrival j + R)
+                                     total_interference_B t).
+            {
+              rewrite big_distrl /=.
+              apply leq_sum; intros t _.
+              unfold some_interference_A, total_interference_B. 
+              destruct (backlogged job_cost rate sched j t) eqn:BACK;
+                [rewrite andTb mul1n | by ins].
+              destruct (has (fun tsk_k : sporadic_task_with_jitter =>
+                       interferes_with_tsk tsk_k &&
+                       (R - task_cost tsk + 1 <= x tsk_k) &&
+                       task_is_scheduled job_task sched tsk_k t) ts) eqn:HAS;
+                last by ins.
+              rewrite mul1n; move: HAS => /hasP HAS.
+              destruct HAS as [tsk_k INk H].
+              move: H => /andP [/andP [INTERFk LEk] SCHEDk].
+              
+              exploit INVARIANT;
+                [by apply JOBtsk | by apply BACK | intro COUNT].
+
+              unfold cardA.
+              set interfering_tasks_at_t :=
+                [seq tsk_k <- ts | interferes_with_tsk tsk_k &&
+                                  task_is_scheduled job_task sched tsk_k t].
+
+              rewrite -(count_filter (fun i => true)) in COUNT.
+              fold interfering_tasks_at_t in COUNT.
+              rewrite count_predT in COUNT.
+              apply leq_trans with (n := num_cpus -
+                                      count (fun i => interferes_with_tsk i &&
+                                                    (x i >= R -  task_cost tsk + 1) &&
+                                                    task_is_scheduled job_task sched i t) ts).
+              {
+                apply leq_sub2l.
+                rewrite -2!sum1_count big_mkcond /=.
+                rewrite [\sum_(_ <- _ | _ <= _)_]big_mkcond /=.
+                apply leq_sum; intros i _.
+                unfold x; destruct (interferes_with_tsk i);
+                  [rewrite andTb | by rewrite 2!andFb].
+                destruct (task_is_scheduled job_task sched i t);
+                  [by rewrite andbT | by rewrite andbF].
+              }
+
+              rewrite leq_subLR.
+              rewrite -count_predUI.
+              apply leq_trans with (n :=
+                count (predU (fun i : sporadic_task_with_jitter =>
+                                interferes_with_tsk i &&
+                                (R - task_cost tsk + 1 <= x i) &&
+                                task_is_scheduled job_task sched i t)
+                             (fun tsk_k0 : sporadic_task_with_jitter =>
+                                interferes_with_tsk tsk_k0 &&
+                                (x tsk_k0 < R - task_cost tsk + 1) &&
+                                task_is_scheduled job_task sched tsk_k0 t))
+                      ts); last by apply leq_addr.
+              apply leq_trans with (n := size interfering_tasks_at_t);
+                first by rewrite COUNT.
+              unfold interfering_tasks_at_t.
+              rewrite -count_predT count_filter.
+              rewrite leq_eqVlt; apply/orP; left; apply/eqP.
+              apply eq_count; red; simpl.
+              intros i.
+              destruct (interferes_with_tsk i),
+                       (task_is_scheduled job_task sched i t);
+                rewrite 3?andTb ?andFb ?andbF ?andbT /=; try ins.
+              by rewrite leqNgt orNb. 
+            }
+            {
+              unfold x at 2, task_interference.
+              rewrite [\sum_(i <- ts | _) _](eq_bigr
+                (fun i => \sum_(job_arrival j <= t < job_arrival j + R)
+                             (i \in ts) && interferes_with_tsk i &&
+                             backlogged job_cost rate sched j t &&
+                             task_is_scheduled job_task sched i t));
+                last first.
+              {
+                ins; destruct ((i \in ts) && interferes_with_tsk i) eqn:INTERi;
+                  first by move: INTERi => /andP [_ INTERi]; apply eq_bigr; ins; rewrite INTERi andTb.
+                by rewrite (eq_bigr (fun i => 0));
+                  [by rewrite big_const_nat iter_addn mul0n addn0 | by ins].
+              }
+              {
+                rewrite exchange_big /=; apply leq_sum; intros t _.
+                unfold total_interference_B.
+                destruct (backlogged job_cost rate sched j t); last by ins.
+                rewrite mul1n -sum1_count.
+                rewrite big_seq_cond big_mkcond [\sum_(i <- ts | _ < _) _]big_mkcond.
+                apply leq_sum; ins; destruct (x i<R - task_cost tsk + 1);
+                  [by rewrite 2!andbT andbA | by rewrite 2!andbF].
+              }
+            }
+          }
+          
+          rewrite big_const_seq iter_addn addn0; fold cardA.
+          apply leq_trans with (n := (R-task_cost tsk+1)*cardA +
+                                     (R-task_cost tsk+1)*(num_cpus-cardA));
+            last by rewrite leq_add2l.
+          by rewrite -mulnDr subnKC //; apply ltnW.
+        }
+
+        (* 4) Now, we prove that the Bertogna's interference bound
+              is not enough to cover the sum of the "minimum" term over
+              all tasks (artifact of the proof by contradiction). *)
+        assert (SUM: \sum_((tsk_k, R_k) <- hp_bounds)
+                       minn (x tsk_k) (R - task_cost tsk + 1) >
+                       I).
+        {
+          apply leq_trans with (n := \sum_(tsk_k <- ts) minn (x tsk_k) (R - task_cost tsk + 1));
+            last first.
+          {
+            rewrite (eq_bigr (fun i => minn (x (fst i)) (R - task_cost tsk + 1)));
+              last by ins; destruct i.
+            apply leq_trans with (n := \sum_(tsk_k <- ts | interferes_with_tsk tsk_k) minn (x tsk_k) (R - task_cost tsk + 1)).
+            {
+              rewrite [\sum_(_ <- _ | interferes_with_tsk _)_]big_mkcond eq_leq //.
+              apply eq_bigr; intros i _; unfold x.
+              by destruct (interferes_with_tsk i); rewrite ?andbT ?andbF ?min0n.
+            }
+            have MAP := big_map (fun x => fst x) (fun i => true) (fun i => minn (x i) (R - task_cost tsk + 1)).
+            by unfold unzip1 in *; rewrite -MAP -FST -big_filter.
+          }
+          apply ltn_div_trunc with (d := num_cpus);
+            first by apply H_at_least_one_cpu.
+          rewrite -(ltn_add2l (task_cost tsk)) -REC.
+          rewrite -addn1 -leq_subLR.
+          rewrite -[R + 1 - _]subh1; last by rewrite REC; apply leq_addr.
+          rewrite leq_divRL; last by apply H_at_least_one_cpu.
+          apply MINSERV.
+          apply leq_trans with (n := X * num_cpus); last by rewrite ALLBUSY.
+          by rewrite leq_mul2r; apply/orP; right; apply INTERF.
+        }
+
+        (* 5) This implies that there exists a tuple (tsk_k, R_k) such that
+              min (x_k, R - e_i + 1) > min (W_k, R - e_i + 1). *)        
+        assert (EX:  has (fun tup : task_with_response_time =>
+                            let (tsk_k, R_k) := tup in
+                              (tsk_k \in ts) &&
+                              interferes_with_tsk tsk_k &&        
+                              (minn (x tsk_k) (R - task_cost tsk + 1) >
+                              minn (workload_bound (tsk_k, snd tup)) (R - task_cost tsk + 1)))
+                         hp_bounds).
+        {
+          apply/negP; unfold not; intro NOTHAS.
+          move: NOTHAS => /negP /hasPn ALL.
+          rewrite -[_ < _]negbK in SUM.
+          move: SUM => /negP SUM; apply SUM; rewrite -leqNgt.
+          unfold I, total_interference_bound_fp_jitter.
+          rewrite [\sum_(i <- _ | let '(tsk_other, _) := i in _)_]big_mkcond.
+          rewrite big_seq_cond [\sum_(i <- _ | true) _]big_seq_cond.
+          apply leq_sum; move => tsk_k /andP [HPk _]; destruct tsk_k as [tsk_k R_k].
+          specialize (ALL (tsk_k, R_k) HPk).
+          unfold interference_bound, workload_bound, x in *.
+          fold (interferes_with_tsk); destruct (interferes_with_tsk tsk_k) eqn:INTERFk;
+            [rewrite andbT in ALL; rewrite andbT | by rewrite andbF min0n].
+          destruct (tsk_k \in ts) eqn:INk; last by rewrite min0n.
+          by rewrite andTb -leqNgt in ALL.
+        }
+        
+        (* For this particular task, we show that x_k > W_k.
+           This contradicts the previous claim. *)
+        move: EX => /hasP EX; destruct EX as [tup_k HPk LTmin].
+        destruct tup_k as [tsk_k R_k]; simpl in LTmin.
+        move: LTmin => /andP [INTERFk LTmin]; move: (INTERFk) => /andP [INk INTERFk'].
+        rewrite INTERFk' in LTmin; unfold minn at 1 in LTmin.
+        destruct (W_jitter task_cost task_period task_jitter tsk_k R_k R < R - task_cost tsk + 1); rewrite leq_min in LTmin;
+          last by move: LTmin => /andP [_ BUG]; rewrite ltnn in BUG.
+        move: LTmin => /andP [BUG _]; des.
+        specialize (WORKLOAD tsk_k INTERFk R_k HPk).
+        apply leq_ltn_trans with (p := x tsk_k) in WORKLOAD; first by rewrite ltnn in WORKLOAD.
+        by unfold workload_bound; rewrite INTERFk'; apply BUG.
+      Qed.
+
+    End UnderFPScheduling.
+
+    Section UnderJLFPScheduling.
+
+      (* to be completed... *)
+      
+    End UnderJLFPScheduling.
+    
+  End ResponseTimeBound.
+
+End ResponseTimeAnalysisJitter.
\ No newline at end of file
diff --git a/GuanFP.v b/GuanFP.v
new file mode 100644
index 000000000..d8de9d6da
--- /dev/null
+++ b/GuanFP.v
@@ -0,0 +1,753 @@
+Require Import Vbase JobDefs TaskDefs ScheduleDefs TaskArrivalDefs PriorityDefs WorkloadDefsJitter BertognaResponseTimeDefsJitter divround helper
+               ssreflect ssrbool eqtype ssrnat seq fintype bigop div path tuple.
+
+Module ResponseTimeIterationFPWithJitter.
+
+  Import Job ScheduleOfTaskWithJitter SporadicTaskset SporadicTaskArrival Priority WorkloadWithJitter ResponseTimeAnalysisJitter.
+
+  Section Analysis.
+    
+    Context {sporadic_task_with_jitter: eqType}.
+    Variable task_cost: sporadic_task_with_jitter -> nat.
+    Variable task_period: sporadic_task_with_jitter -> nat.
+    Variable task_deadline: sporadic_task_with_jitter -> nat.
+    Variable task_jitter: sporadic_task_with_jitter -> nat.
+    
+    Let task_with_response_time := (sporadic_task_with_jitter * nat)%type.
+    
+    Context {Job: eqType}.
+    Variable job_cost: Job -> nat.
+    Variable job_deadline: Job -> nat.
+    Variable job_task: Job -> sporadic_task_with_jitter.
+    Variable job_jitter: Job -> nat.
+
+    Variable num_cpus: nat.
+    Variable higher_eq_priority: fp_policy sporadic_task_with_jitter.
+
+    (* Next we define the fixed-point iteration for computing
+       Bertogna's response-time bound for any task in ts. *)
+
+    Let I (tsk: sporadic_task_with_jitter)
+          (R_prev: seq task_with_response_time) (delta: time) :=
+      total_interference_bound_fp_jitter task_cost task_period task_jitter
+                                       tsk R_prev delta higher_eq_priority.
+    
+    (* First, given a sequence of pairs R_prev = [..., (tsk_hp, R_hp)] of
+       response-time bounds for the higher-priority tasks, we compute
+       the response-time bound of tsk using the following iteration:
+
+       R_tsk <- f^step (R_tsk),
+         where f is the response-time recurrence,
+         step is the number of iterations,
+         and f^0 = task_cost tsk. *)    
+    Definition per_task_rta (tsk: sporadic_task_with_jitter)
+                      (R_prev: seq task_with_response_time) (step: nat) :=
+      iter step
+           (fun t => task_cost tsk +
+                     div_floor (I tsk R_prev t) num_cpus)
+           (task_cost tsk).
+
+    (* To ensure that the iteration converges, we will apply per_task_rta
+       a "sufficient" number of times: task_deadline tsk + 1.
+       Note that (deadline + 1) is a pessimistic bound on the number of
+       steps, but we don't care about precise runtime complexity here. *)
+    Let max_steps (tsk: sporadic_task_with_jitter) :=
+      task_deadline tsk + 1.
+    
+    (* Next we compute the response-time bounds for the entire task set.
+       Since high-priority tasks may not be schedulable, we allow the
+       computation to fail.
+       Thus, given the response-time bound of previous tasks, we either
+       (a) append the response-time bound (tsk, R) of the current task
+           to the list of pairs, or,
+       (b) return None if the response-time analysis failed. *)
+    Definition R_list_helper (hp_pairs: option (seq task_with_response_time))
+                             (tsk: sporadic_task_with_jitter) :=
+      if hp_pairs is Some rt_bounds then
+        let R := per_task_rta tsk rt_bounds (max_steps tsk) in
+          let R' := R + task_jitter tsk in
+            if R' <= task_deadline tsk then
+              Some (rcons rt_bounds (tsk, R'))
+            else None
+      else None.
+
+    (* To return the complete list of response-time bounds for any task set,
+       we just apply foldl (reduce) using the function above. *)
+    Definition R_list (ts: taskset_of sporadic_task_with_jitter) : option (seq task_with_response_time) :=
+      foldl R_list_helper (Some [::]) ts.
+
+    (* The schedulability test simply checks if we got a list of
+       response-time bounds (i.e., if the computation did not fail). *)
+    Definition fp_schedulable (ts: taskset_of sporadic_task_with_jitter) :=
+      R_list ts != None.
+    
+    Section AuxiliaryLemmas.
+
+      (* In this section, we prove several helper lemmas about the
+         list of response-time bounds, such as:
+         (1) Equality among tasks in R_list and in the task set.
+         (2) If (tsk, R) \in R_list, then R <= task_deadline tsk.
+         (3) If (tsk, R) \in R_list, then R >= task_cost tsk.
+         (4) If per_task_rta returns a bound <= deadline, then the
+             iteration reached a fixed-point. *)
+
+      Lemma R_list_rcons_prefix :
+        forall ts' hp_bounds tsk1 tsk2 R,
+          R_list (rcons ts' tsk1) = Some (rcons hp_bounds (tsk2, R)) ->
+            R_list ts' = Some hp_bounds.
+      Proof.
+        intros ts hp_bounds tsk1 tsk2 R SOME.
+        rewrite -cats1 in SOME.
+        unfold R_list in *.
+        rewrite foldl_cat in SOME.
+        simpl in SOME.
+        unfold R_list_helper in SOME.
+        desf; rewrite Heq; rename H0 into EQ.
+        move: EQ => /eqP EQ.
+        rewrite eqseq_rcons in EQ.
+        move: EQ => /andP [/eqP EQ _].
+        by f_equal.
+      Qed. 
+
+      Lemma R_list_rcons_task :
+        forall ts' hp_bounds tsk1 tsk2 R,
+          R_list (rcons ts' tsk1) = Some (rcons hp_bounds (tsk2, R)) ->
+            tsk1 = tsk2.
+      Proof.
+        intros ts hp_bounds tsk1 tsk2 R SOME.
+        rewrite -cats1 in SOME.
+        unfold R_list in *.
+        rewrite foldl_cat in SOME.
+        simpl in SOME.
+        unfold R_list_helper in SOME.
+        desf; rename H0 into EQ.
+        move: EQ => /eqP EQ.
+        rewrite eqseq_rcons in EQ.
+        move: EQ => /andP [_ /eqP EQ].
+        by inversion EQ.
+      Qed. 
+
+      Lemma R_list_rcons_response_time :
+        forall ts' hp_bounds tsk R,
+          R_list (rcons ts' tsk) = Some (rcons hp_bounds (tsk, R)) ->
+            R = per_task_rta tsk hp_bounds (max_steps tsk) + task_jitter tsk. 
+      Proof.
+        intros ts hp_bounds tsk R SOME.
+        rewrite -cats1 in SOME.
+        unfold R_list in SOME.
+        rewrite foldl_cat in SOME.
+        simpl in SOME.
+        unfold R_list_helper in SOME.
+        desf; rename H0 into EQ; move: EQ => /eqP EQ.
+        rewrite eqseq_rcons in EQ; move: EQ => /andP [/eqP EQ1 /eqP EQ2].
+        by inversion EQ2; rewrite EQ1.
+      Qed.
+
+      Lemma R_list_le_deadline :
+        forall ts' rt_bounds tsk R,
+          R_list ts' = Some rt_bounds ->
+          (tsk, R) \in rt_bounds ->
+          R <= task_deadline tsk.
+      Proof.
+        intros ts; induction ts as [| ts' tsk_lst] using last_ind.
+        {
+          intros rt_bounds tsk R SOME IN.
+          by inversion SOME; subst; rewrite in_nil in IN.
+        }
+        {
+          intros rt_bounds tsk_i R SOME IN.
+          destruct (lastP rt_bounds) as [|rt_bounds (tsk_lst', R_lst)];
+            first by rewrite in_nil in IN.
+          rewrite mem_rcons in_cons in IN; move: IN => /orP IN.
+          destruct IN as [LAST | FRONT].
+          {
+            move: LAST => /eqP LAST.
+            rewrite -cats1 in SOME.
+            unfold R_list in *.
+            rewrite foldl_cat in SOME.
+            simpl in SOME.
+            unfold R_list_helper in SOME.
+            desf; rename H0 into EQ.
+            move: EQ => /eqP EQ.
+            rewrite eqseq_rcons in EQ.
+            move: EQ => /andP [_ /eqP EQ].
+            inversion EQ; subst.
+            by apply Heq0.
+          }
+          {
+            apply IHts with (rt_bounds := rt_bounds); last by ins.
+            by apply R_list_rcons_prefix in SOME.
+          }
+        }
+      Qed.
+
+      Lemma R_list_ge_cost :
+        forall ts' rt_bounds tsk R,
+          R_list ts' = Some rt_bounds ->
+          (tsk, R) \in rt_bounds ->
+          R >= task_cost tsk.
+      Proof.
+        intros ts; induction ts as [| ts' tsk_lst] using last_ind.
+        {
+          intros rt_bounds tsk R SOME IN.
+          by inversion SOME; subst; rewrite in_nil in IN.
+        }
+        {
+          intros rt_bounds tsk_i R SOME IN.
+          destruct (lastP rt_bounds) as [|rt_bounds (tsk_lst', R_lst)];
+            first by rewrite in_nil in IN.
+          rewrite mem_rcons in_cons in IN; move: IN => /orP IN.
+          destruct IN as [LAST | FRONT].
+          {
+            move: LAST => /eqP LAST.
+            rewrite -cats1 in SOME.
+            unfold R_list in *.
+            rewrite foldl_cat in SOME.
+            simpl in SOME.
+            unfold R_list_helper in SOME.
+            desf; rename H0 into EQ.
+            move: EQ => /eqP EQ.
+            rewrite eqseq_rcons in EQ.
+            move: EQ => /andP [_ /eqP EQ].
+            inversion EQ; subst.
+            by destruct (max_steps tsk_lst');
+              [by apply leq_addr | by rewrite -addnA leq_addr].
+          }
+          {
+            apply IHts with (rt_bounds := rt_bounds); last by ins.
+            by apply R_list_rcons_prefix in SOME.
+          }
+        }
+      Qed.
+
+      Lemma R_list_non_empty :
+        forall ts' rt_bounds tsk,
+          R_list ts' = Some rt_bounds ->
+          (tsk \in ts' <->
+            exists R,
+              (tsk, R) \in rt_bounds).
+      Proof.
+        intros ts; induction ts as [| ts' tsk_lst] using last_ind.
+        {
+          intros rt_bounds tsk SOME.
+          inversion SOME; rewrite in_nil; split; first by ins.
+          by intro EX; des; rewrite in_nil in EX.
+        }
+        {
+          intros rt_bounds tsk_i SOME.
+          destruct (lastP rt_bounds) as [|rt_bounds (tsk_lst', R_lst)].
+          {
+            split; last first; intro EX; des; first by rewrite in_nil in EX.
+            unfold R_list in *.
+            rewrite -cats1 foldl_cat in SOME.
+            simpl in SOME.
+            unfold R_list_helper in *; desf; rename H0 into EQ.
+            destruct l; first by ins.
+            by rewrite rcons_cons in EQ; inversion EQ.
+          }
+          split.
+          {
+            intros IN; rewrite mem_rcons in_cons in IN; move: IN => /orP IN.
+            destruct IN as [LAST | FRONT].
+            {
+              move: LAST => /eqP LAST; subst tsk_i.
+              generalize SOME; apply R_list_rcons_task in SOME; subst tsk_lst'; intro SOME.
+              exists R_lst.
+              by rewrite mem_rcons in_cons; apply/orP; left.
+            }
+            {
+              apply R_list_rcons_prefix in SOME.
+              exploit (IHts rt_bounds tsk_i); [by ins | intro EX].
+              apply EX in FRONT; des.
+              by exists R; rewrite mem_rcons in_cons; apply/orP; right.
+            }
+          }
+          {
+            intro IN; des.
+            rewrite mem_rcons in_cons in IN; move: IN => /orP IN.
+            destruct IN as [LAST | FRONT].
+            {
+              move: LAST => /eqP LAST.
+              inversion LAST; subst tsk_i R; clear LAST.
+              apply R_list_rcons_task in SOME; subst.
+              by rewrite mem_rcons in_cons; apply/orP; left.
+            }
+            {
+              rewrite mem_rcons in_cons; apply/orP; right.
+              exploit (IHts rt_bounds tsk_i);
+                [by apply R_list_rcons_prefix in SOME | intro EX].
+              by apply EX; exists R.
+            }
+          }
+        }
+      Qed.
+
+      (*  To prove convergence of R, we first show convergence of rt_rec. *)      Lemma per_task_rta_converges:
+        forall ts' tsk rt_bounds,
+          valid_sporadic_taskset task_cost task_period task_deadline ts' ->
+          R_list ts' = Some rt_bounds ->
+          per_task_rta tsk rt_bounds (max_steps tsk) <= task_deadline tsk ->
+            per_task_rta tsk rt_bounds (max_steps tsk) =
+              per_task_rta tsk rt_bounds (max_steps tsk).+1.
+      Proof.
+        unfold valid_sporadic_taskset, is_valid_sporadic_task in *.
+        
+        (* To simplify, let's call the function f.*)
+        intros ts' tsk rt_bounds VALID SOME LE;
+          set (f := per_task_rta tsk rt_bounds); fold f in LE.
+
+        (* First prove that f is monotonic.*)
+        assert (MON: forall x1 x2, x1 <= x2 -> f x1 <= f x2).
+        {
+          intros x1 x2 LEx; unfold f, per_task_rta.
+          apply fun_mon_iter_mon; [by ins | by ins; apply leq_addr |].
+          clear LEx x1 x2; intros x1 x2 LEx.
+          
+          unfold div_floor, I, total_interference_bound_fp_jitter.
+          rewrite big_seq_cond [\sum_(i <- _ | let '(tsk_other, _) := i in
+                                   _ && (tsk_other != tsk))_]big_seq_cond.
+          rewrite leq_add2l leq_div2r // leq_sum //.
+
+          intros i; destruct (i \in rt_bounds) eqn:HP;
+            last by rewrite andFb.
+          destruct i as [i R]; intros _.
+          have GE_COST := (R_list_ge_cost ts' rt_bounds i R).
+          have INts := (R_list_non_empty ts' rt_bounds i SOME).
+          destruct INts as [_ EX]; exploit EX; [by exists R | intro IN].
+          unfold interference_bound_jitter; simpl.
+          rewrite leq_min; apply/andP; split.
+          {
+            apply leq_trans with (n := W_jitter task_cost task_period task_jitter i R x1); 
+              first by apply geq_minl.            
+            specialize (VALID i IN); des.
+            by apply W_jitter_monotonic; try (by ins); apply GE_COST.          
+          }
+          {
+            apply leq_trans with (n := x1 - task_cost tsk + 1);
+              first by apply geq_minr.
+            by rewrite leq_add2r leq_sub2r //.
+          }
+        }
+
+        (* Either f converges by the deadline or not. *)
+        unfold max_steps in *; rewrite -> addn1 in *.
+        destruct ([exists k in 'I_(task_deadline tsk).+1,
+                     f k == f k.+1]) eqn:EX.
+        {
+          move: EX => /exists_inP EX; destruct EX as [k _ ITERk].
+          move: ITERk => /eqP ITERk.
+          by apply iter_fix with (k := k);
+            [by ins | by apply ltnW, ltn_ord].
+        }
+        apply negbT in EX; rewrite negb_exists_in in EX.
+        move: EX => /forall_inP EX.
+        assert (GROWS: forall k: 'I_(task_deadline tsk).+1,
+                         f k < f k.+1).
+        {
+          intros k; rewrite ltn_neqAle; apply/andP; split; first by apply EX.
+          apply MON, leqnSn.
+        }
+
+        (* If it doesn't converge, then it becomes larger than the deadline.
+           But initialy we assumed otherwise. Contradiction! *)
+        assert (BY1: f (task_deadline tsk).+1 > task_deadline tsk).
+        {
+          clear MON LE EX.
+          induction (task_deadline tsk).+1; first by ins.
+          apply leq_ltn_trans with (n := f n);
+            last by apply (GROWS (Ordinal (ltnSn n))).
+          apply IHn; intros k.
+          by apply (GROWS (widen_ord (leqnSn n) k)).
+        }
+        by apply leq_ltn_trans with (m := f (task_deadline tsk).+1) in BY1;
+          [by rewrite ltnn in BY1 | by ins].
+      Qed.
+
+      Lemma per_task_rta_fold :
+        forall tsk rt_bounds,
+          task_cost tsk +
+           div_floor (I tsk rt_bounds (per_task_rta tsk rt_bounds (max_steps tsk))) num_cpus
+          = per_task_rta tsk rt_bounds (max_steps tsk).+1.
+      Proof.
+          by ins.
+      Qed.
+
+      Lemma R_list_unzip1 :
+        forall ts' tsk hp_bounds R,
+          transitive higher_eq_priority ->
+          uniq (rcons ts' tsk) ->
+          sorted higher_eq_priority (rcons ts' tsk) ->
+          R_list (rcons ts' tsk) = Some (rcons hp_bounds (tsk, R)) ->
+            [seq tsk_hp <- rcons ts' tsk | is_interfering_task_fp tsk higher_eq_priority tsk_hp] =
+            unzip1 hp_bounds.
+      Proof.
+        intros ts tsk hp_bounds R TRANS.
+        revert tsk hp_bounds R.
+        induction ts as [| ts' tsk_lst] using last_ind.
+        {
+          intros tsk hp_bounds R _ _ SOME; simpl in *.
+          unfold is_interfering_task_fp.
+          rewrite eq_refl andbF.
+          destruct hp_bounds; first by ins.
+          unfold R_list in SOME; inversion SOME; desf.
+          by destruct hp_bounds.
+        }
+        {
+          intros tsk hp_bounds R UNIQ SORTED SOME.
+          destruct (lastP hp_bounds) as [| hp_bounds (tsk_lst', R_lst)].
+          {
+            apply R_list_rcons_prefix in SOME.
+            unfold R_list in SOME.
+            rewrite -cats1 foldl_cat in SOME.
+            unfold R_list_helper in SOME.
+            inversion SOME; desf.
+            by destruct l.
+          }
+          generalize SOME; apply R_list_rcons_prefix, R_list_rcons_task in SOME; subst tsk_lst'; intro SOME.
+          specialize (IHts tsk_lst hp_bounds R_lst).
+          rewrite filter_rcons in IHts.
+          unfold is_interfering_task_fp in IHts.
+          rewrite eq_refl andbF in IHts.
+          assert (NOTHP: is_interfering_task_fp tsk higher_eq_priority tsk = false).
+          {
+            by unfold is_interfering_task_fp; rewrite eq_refl andbF.
+          } rewrite filter_rcons NOTHP; clear NOTHP.
+          assert (HP: is_interfering_task_fp tsk higher_eq_priority tsk_lst).
+          {
+            unfold is_interfering_task_fp; apply/andP; split.
+            {
+              apply order_sorted_rcons with (x := tsk_lst) in SORTED; try (by ins).
+              by rewrite mem_rcons in_cons; apply/orP; left.
+            }
+            {
+              rewrite 2!rcons_uniq mem_rcons in_cons negb_or in UNIQ.
+              move : UNIQ => /andP [/andP [UNIQ _] _].
+              by rewrite eq_sym in UNIQ.
+            }
+          } rewrite filter_rcons HP; clear HP.
+          unfold unzip1; rewrite map_rcons /=; f_equal.
+          assert (SHIFT: [seq tsk_hp <- ts' | is_interfering_task_fp tsk higher_eq_priority tsk_hp] = [seq tsk_hp <- ts'
+      | is_interfering_task_fp tsk_lst higher_eq_priority tsk_hp]).
+          {
+            apply eq_in_filter; red.
+            unfold is_interfering_task_fp; intros x INx.
+            rewrite 2!rcons_uniq mem_rcons in_cons negb_or in UNIQ.
+            move: UNIQ => /andP [/andP [NEQ NOTIN] /andP [NOTIN' UNIQ]].
+            destruct (x == tsk) eqn:EQtsk.
+            {
+              move: EQtsk => /eqP EQtsk; subst.
+              by rewrite INx in NOTIN.
+            }
+            destruct (x == tsk_lst) eqn:EQlst.
+            {
+              move: EQlst => /eqP EQlst; subst.
+              by rewrite INx in NOTIN'.
+            }
+            rewrite 2!andbT.
+            generalize SORTED; intro SORTED'.
+            have bla := order_sorted_rcons.
+            apply order_sorted_rcons with (x0 := x) in SORTED; try (by ins);
+              last by rewrite mem_rcons in_cons; apply/orP; right.
+            rewrite SORTED.
+            apply sorted_rcons_prefix in SORTED'.
+            by apply order_sorted_rcons with (x0 := x) in SORTED'.
+          } rewrite SHIFT; clear SHIFT.
+          apply IHts.
+            by rewrite rcons_uniq in UNIQ; move: UNIQ => /andP [_ UNIQ].
+            by apply sorted_rcons_prefix in SORTED.
+            by apply R_list_rcons_prefix in SOME.
+        }
+      Qed.
+      
+    End AuxiliaryLemmas.
+    
+    Section Proof.
+
+      (* Consider a task set ts. *)
+      Variable ts: taskset_of sporadic_task_with_jitter.
+      
+      (* Assume that higher_eq_priority is a total order.
+         Actually, it just needs to be total over the task set,
+         but to weaken the assumption, I have to re-prove many lemmas
+         about ordering in ssreflect. This can be done later. *)
+      Hypothesis H_valid_policy: valid_fp_policy higher_eq_priority.
+      Hypothesis H_unique_priorities: antisymmetric higher_eq_priority.
+
+      (* Assume the task set has no duplicates, ... *)
+      Hypothesis H_ts_is_a_set: uniq ts.
+
+      (* ...all tasks have valid parameters, ... *)
+      Hypothesis H_valid_task_parameters:
+        valid_sporadic_taskset task_cost task_period task_deadline ts.
+
+      (* ...restricted deadlines, ...*)
+      Hypothesis H_restricted_deadlines:
+        forall tsk, tsk \in ts -> task_deadline tsk <= task_period tsk.
+
+      (* ...and tasks are ordered by increasing priorities. *)
+      Hypothesis H_sorted_ts: sorted higher_eq_priority ts.
+
+      (* Next, consider any arrival sequence such that...*)
+      Context {arr_seq: arrival_sequence Job}.
+
+     (* ...all jobs come from task set ts, ...*)
+      Hypothesis H_all_jobs_from_taskset:
+        forall (j: JobIn arr_seq), job_task j \in ts.
+      
+      (* ...they have valid parameters,...*)
+      Hypothesis H_valid_job_parameters:
+        forall (j: JobIn arr_seq),
+          valid_sporadic_job_with_jitter task_cost task_deadline task_jitter job_cost job_deadline job_task job_jitter j.
+      
+      (* ... and satisfy the sporadic task model.*)
+      Hypothesis H_sporadic_tasks:
+        sporadic_task_model task_period arr_seq job_task.
+      
+      (* Then, consider any platform with at least one CPU and unit
+         unit execution rate, where...*)
+      Variable rate: Job -> processor num_cpus -> nat.
+      Variable sched: schedule num_cpus arr_seq.
+      Hypothesis H_at_least_one_cpu :
+        num_cpus > 0.
+      Hypothesis H_rate_equals_one :
+        forall j cpu, rate j cpu = 1.
+
+      (* ...jobs only execute after the jitter and no longer
+         than their execution costs,... *)
+      Hypothesis H_jobs_execute_after_jitter:
+        jobs_execute_after_jitter job_jitter sched.
+      Hypothesis H_completed_jobs_dont_execute:
+        completed_jobs_dont_execute job_cost rate sched.
+
+      (* ...and do not execute in parallel. *)
+      Hypothesis H_no_parallelism:
+        jobs_dont_execute_in_parallel sched.
+
+      (* Assume the platform satisfies the global scheduling invariant. *)
+      Hypothesis H_global_scheduling_invariant:
+        forall (tsk: sporadic_task_with_jitter) (j: JobIn arr_seq) (t: time),
+          tsk \in ts ->
+          job_task j = tsk ->
+          backlogged job_cost rate sched j t ->
+          count
+            (fun tsk_other : _ =>
+               is_interfering_task_fp tsk higher_eq_priority tsk_other &&
+               task_is_scheduled job_task sched tsk_other t) ts = num_cpus.
+
+      Definition no_deadline_missed_by_task (tsk: sporadic_task_with_jitter) :=
+        task_misses_no_deadline job_cost job_deadline job_task rate sched tsk.
+      Definition no_deadline_missed_by_job :=
+        job_misses_no_deadline job_cost job_deadline rate sched.
+
+      Section HelperLemma.
+        
+        (* The following lemma states that the response-time bounds
+           computed using R_list are valid. *)
+        Lemma R_list_has_response_time_bounds :
+          forall rt_bounds tsk R,
+            R_list ts = Some rt_bounds ->
+            (tsk, R) \in rt_bounds ->
+            forall j : JobIn arr_seq,
+              job_task j = tsk ->
+              completed job_cost rate sched j (job_arrival j + R).
+        Proof.
+          unfold valid_fp_policy, fp_is_transitive, fp_is_reflexive,
+                 fp_is_total in *.
+          rename H_valid_job_parameters into JOBPARAMS,
+                 H_valid_task_parameters into TASKPARAMS,
+                 H_restricted_deadlines into RESTR,
+                 H_completed_jobs_dont_execute into COMP,
+                 H_jobs_execute_after_jitter into MUSTARRIVE,
+                 H_global_scheduling_invariant into INVARIANT,
+                 H_sorted_ts into SORT,
+                 H_unique_priorities into UNIQ,
+                 H_all_jobs_from_taskset into ALLJOBS,
+                 H_ts_is_a_set into SET.
+          destruct H_valid_policy as [REFL [TRANS TOTAL]]; clear ALLJOBS.
+        
+          unfold fp_schedulable, R_list in *.
+          induction ts as [| ts' tsk_i IH] using last_ind.
+          {
+            intros rt_bounds tsk R SOME IN.
+            by inversion SOME; subst; rewrite in_nil in IN.
+          }
+          {
+           intros rt_bounds tsk R SOME IN j JOBj.
+             destruct (lastP rt_bounds) as [| hp_bounds (tsk_lst, R_lst)];
+              first by rewrite in_nil in IN.
+            rewrite mem_rcons in_cons in IN; move: IN => /orP IN.
+            destruct IN as [LAST | BEGINNING]; last first.
+            {
+              apply IH with (rt_bounds := hp_bounds) (tsk := tsk); try (by ins).
+              by rewrite rcons_uniq in SET; move: SET => /andP [_ SET].
+              by ins; red; ins; apply TASKPARAMS; rewrite mem_rcons in_cons; apply/orP; right.
+              by ins; apply RESTR; rewrite mem_rcons in_cons; apply/orP; right.
+              by apply sorted_rcons_prefix in SORT.
+              {
+                intros tsk0 j0 t IN0 JOB0 BACK0.
+                exploit (INVARIANT tsk0 j0 t); try (by ins);
+                  [by rewrite mem_rcons in_cons; apply/orP; right | intro INV].
+                rewrite -cats1 count_cat /= in INV.
+                unfold is_interfering_task_fp in INV.
+                generalize SOME; apply R_list_rcons_task in SOME; subst tsk_i; intro SOME.
+                assert (HP: higher_eq_priority tsk_lst tsk0 = false).
+                {
+                  apply order_sorted_rcons with (x := tsk0) in SORT; [|by ins | by ins].
+                  apply negbTE; apply/negP; unfold not; intro BUG.
+                  exploit UNIQ; [by apply/andP; split; [by apply SORT | by ins] | intro EQ].
+                  by rewrite rcons_uniq -EQ IN0 in SET.
+                }              
+                by rewrite HP 2!andFb 2!addn0 in INV.
+              }
+              by apply R_list_rcons_prefix in SOME.
+            }
+            {
+              move: LAST => /eqP LAST.
+              inversion LAST as [[EQ1 EQ2]].
+              rewrite -> EQ1 in *; rewrite -> EQ2 in *; clear EQ1 EQ2 LAST.
+              generalize SOME; apply R_list_rcons_task in SOME; subst tsk_i; intro SOME.
+              generalize SOME; apply R_list_rcons_prefix in SOME; intro SOME'.
+              generalize SOME'; apply R_list_rcons_response_time in SOME'; intro SOME''; rewrite SOME'.
+              have BOUND := bertogna_cirinei_response_time_bound_fp_with_jitter.
+              unfold is_response_time_bound_of_task, job_has_completed_by in BOUND.
+              apply BOUND with (task_cost := task_cost) (task_period := task_period) (task_deadline := task_deadline) (job_deadline := job_deadline) (job_task := job_task) (tsk := tsk_lst) (job_jitter := job_jitter)
+                               (ts := rcons ts' tsk_lst) (hp_bounds := hp_bounds)
+                               (higher_eq_priority := higher_eq_priority); clear BOUND; try (by ins).
+              apply R_list_unzip1 with (R := R_lst); try (by ins).
+              {
+                intros hp_tsk R0 HP j0 JOB0.
+                apply IH with (rt_bounds := hp_bounds) (tsk := hp_tsk); try (by ins).
+                by rewrite rcons_uniq in SET; move: SET => /andP [_ SET].
+                by red; ins; apply TASKPARAMS; rewrite mem_rcons in_cons; apply/orP; right.
+                by ins; apply RESTR; rewrite mem_rcons in_cons; apply/orP; right.
+                by apply sorted_rcons_prefix in SORT.
+                {
+                  intros tsk0 j1 t IN0 JOB1 BACK0.
+                  exploit (INVARIANT tsk0 j1 t); try (by ins);
+                    [by rewrite mem_rcons in_cons; apply/orP; right | intro INV].
+                  rewrite -cats1 count_cat /= addn0 in INV.
+                  unfold is_interfering_task_fp in INV.
+                  assert (NOINTERF: higher_eq_priority tsk_lst tsk0 = false).
+                  {
+                    apply order_sorted_rcons with (x := tsk0) in SORT; [|by ins | by ins].
+                    apply negbTE; apply/negP; unfold not; intro BUG.
+                    exploit UNIQ; [by apply/andP; split; [by apply BUG | by ins] | intro EQ].
+                    by rewrite rcons_uniq EQ IN0 in SET.
+                  }
+                  by rewrite NOINTERF 2!andFb addn0 in INV.
+                }
+              }
+              by ins; apply R_list_ge_cost with (ts' := ts') (rt_bounds := hp_bounds).
+              by ins; apply R_list_le_deadline with (ts' := ts') (rt_bounds := hp_bounds).
+              {
+                ins; exploit (INVARIANT tsk_lst j0 t); try (by ins).
+                by rewrite mem_rcons in_cons; apply/orP; left.
+              }
+              {
+                rewrite per_task_rta_fold.
+                apply per_task_rta_converges with (ts' := ts'); try (by ins).
+                {
+                  red; ins; apply TASKPARAMS.
+                  by rewrite mem_rcons in_cons; apply/orP; right.
+                }
+                apply leq_trans with (n := per_task_rta tsk_lst hp_bounds (max_steps tsk_lst) + task_jitter tsk_lst);
+                  first by apply leq_addr.
+                rewrite -SOME'.
+                apply R_list_le_deadline with (ts' := rcons ts' tsk_lst)
+                                            (rt_bounds := rcons hp_bounds (tsk_lst, R_lst)); try (by ins).
+                by rewrite mem_rcons in_cons; apply/orP; left; apply/eqP.
+              }
+            }
+          }
+        Qed.
+
+      End HelperLemma.
+      
+      (* If the schedulability test suceeds, ...*)
+      Hypothesis H_test_succeeds: fp_schedulable ts.
+      
+      (*..., then no task misses its deadline,... *)
+      Theorem taskset_with_jitter_schedulable_by_fp_rta :
+        forall tsk, tsk \in ts -> no_deadline_missed_by_task tsk.
+      Proof.
+        unfold no_deadline_missed_by_task, task_misses_no_deadline,
+               job_misses_no_deadline, completed, valid_fp_policy,
+               fp_schedulable, fp_is_reflexive, fp_is_transitive,
+               fp_is_total, valid_sporadic_job_with_jitter,
+               valid_sporadic_job in *.
+        rename H_valid_job_parameters into JOBPARAMS,
+               H_valid_task_parameters into TASKPARAMS,
+               H_restricted_deadlines into RESTR,
+               H_completed_jobs_dont_execute into COMP,
+               H_jobs_execute_after_jitter into MUSTARRIVE,
+               H_global_scheduling_invariant into INVARIANT,
+               H_sorted_ts into SORT,
+               H_unique_priorities into UNIQ,
+               H_all_jobs_from_taskset into ALLJOBS,
+               H_test_succeeds into TEST.
+        destruct H_valid_policy as [REFL [TRANS TOTAL]].
+
+        move => tsk INtsk j /eqP JOBtsk.
+        have RLIST := (R_list_has_response_time_bounds).
+        have NONEMPTY := (R_list_non_empty ts).
+        have DL := (R_list_le_deadline ts).
+
+        destruct (R_list ts) as [rt_bounds |]; last by ins.
+        exploit (NONEMPTY rt_bounds tsk); [by ins | intros [EX _]; specialize (EX INtsk); des].
+        exploit (RLIST rt_bounds tsk R); [by ins | by ins | by apply JOBtsk | intro COMPLETED].
+        exploit (DL rt_bounds tsk R); [by ins | by ins | clear DL; intro DL].
+        
+        rewrite eqn_leq; apply/andP; split; first by apply service_interval_le_cost.
+        apply leq_trans with (n := service rate sched j (job_arrival j + R)); last first.
+        {
+          unfold valid_sporadic_taskset, is_valid_sporadic_task in *.
+          apply service_monotonic; rewrite leq_add2l.
+          specialize (JOBPARAMS j); des; rewrite JOBPARAMS2.
+          by rewrite JOBtsk.
+        }
+        rewrite leq_eqVlt; apply/orP; left; rewrite eq_sym.
+        by apply COMPLETED.
+      Qed.
+
+      (* ..., and the schedulability test yields safe response-time
+         bounds for each task. *)
+      Theorem fp_schedulability_test_with_jitter_yields_response_time_bounds :
+        forall tsk,
+          tsk \in ts ->
+          exists R,
+            R <= task_deadline tsk /\
+            forall (j: JobIn arr_seq),
+              job_task j = tsk ->
+              completed job_cost rate sched j (job_arrival j + R).
+      Proof.
+        intros tsk IN.
+        unfold fp_schedulable in *.
+        have TASKS := R_list_non_empty ts.
+        have BOUNDS := (R_list_has_response_time_bounds).
+        have DL := (R_list_le_deadline ts).
+        destruct (R_list ts) as [rt_bounds |]; last by ins.
+        exploit (TASKS rt_bounds tsk); [by ins | clear TASKS; intro EX].
+        destruct EX as [EX _]; specialize (EX IN); des.
+        exists R; split.
+          by apply DL with (rt_bounds0 := rt_bounds).
+          by ins; apply (BOUNDS rt_bounds tsk).
+      Qed.
+
+      (* For completeness, since all jobs of the arrival sequence
+         are spawned by the task set, we conclude that no job misses
+         its deadline. *)
+      Theorem jobs_with_jitter_schedulable_by_fp_rta :
+        forall (j: JobIn arr_seq), no_deadline_missed_by_job j.
+      Proof.
+        intros j.
+        have SCHED := taskset_with_jitter_schedulable_by_fp_rta.
+        unfold no_deadline_missed_by_task, task_misses_no_deadline in *.
+        apply SCHED with (tsk := job_task j); last by rewrite eq_refl.
+        by apply H_all_jobs_from_taskset.
+      Qed.
+      
+    End Proof.
+
+  End Analysis.
+
+End ResponseTimeIterationFPWithJitter.
\ No newline at end of file
diff --git a/Vbase.v b/Vbase.v
index 9960c309c..0508e86f2 100644
--- a/Vbase.v
+++ b/Vbase.v
@@ -489,8 +489,8 @@ Ltac autos   := clarsimp; auto with vlib.
 
 Definition NW A (P: unit -> A) : A := P tt.
 
-Notation "<< x : t >>" := (NW (fun x => t)) (at level 80, x ident, no associativity).
-Notation "<< t >>" := (NW (fun _ => t)) (at level 79, no associativity).
+(*Notation "<< x : t >>" := (NW (fun x => t)) (at level 80, x ident, no associativity).
+Notation "<< t >>" := (NW (fun _ => t)) (at level 79, no associativity).*)
 
 Ltac unnw := unfold NW in *.
 Ltac rednw := red; unnw.
diff --git a/helper.v b/helper.v
index dce2f0ade..c5028e3f3 100644
--- a/helper.v
+++ b/helper.v
@@ -41,20 +41,25 @@ Notation "\sum_ ( ( m , n ) <- r | P ) F" :=
   (\sum_(i <- r | (let '(m,n) := i in P))
     (let '(m,n) := i in F)) : nat_scope.
 
-(*Reserved Notation "\big [ op / idx ]_ ( ( m , n ) <- r | P ) F"
-  (at level 36, F at level 36, op, idx at level 10, i, r at level 50,
-   format "'[' \big [ op / idx ]_ ( ( m , n ) <- r | P ) '/ ' F ']'").
+Reserved Notation "\max_ ( ( m , n ) <- r ) F"
+  (at level 41, F at level 41, m, n at level 50,
+   format "'[' \max_ ( ( m , n ) <- r ) '/ ' F ']'").
+
+Notation "\max_ ( ( m , n ) <- r ) F" :=
+  (\max_(i <- r) (let '(m,n) := i in F)) : nat_scope.
 
-Notation "\big [ op / idx ]_ ( ( m , n ) <- r | P ) F" :=
-  (bigop idx op r
-         (fun i => let '(m,n) := i in P%B)
-         (fun i => let '(m,n) := i in F)) : big_scope.*)
+Reserved Notation "\max_ ( ( m , n ) <- r | P ) F"
+  (at level 41, F at level 30, P at level 41, m, n at level 50,
+   format "'[' \max_ ( ( m , n ) <- r | P ) '/ ' F ']'").
 
-(*Variable natlist: seq nat.
-Check (\sum_(x1 <- natlist) x1).
+Notation "\max_ ( ( m , n ) <- r | P ) F" :=
+  (\max_(i <- r | (let '(m,n) := i in P))
+    (let '(m,n) := i in F)) : nat_scope.
 
-Variable tuplelist: seq (nat * nat).
-Check (\sum_( (x1,x2) <- tuplelist | x1 + x2 > 1) (x1 + x2)).*)
+Notation "[ 'seq' ( x , y ) <- s | C ]" :=
+  (filter (fun i => let '(x,y) := i in C%B) s)
+ (at level 0, x at level 99,
+  format "[ '[hv' 'seq' ( x , y ) <- s '/ ' | C ] ']'") : seq_scope.
 
 Reserved Notation "\cat_ ( i < n ) F"
   (at level 41, F at level 41, i, n at level 50,
@@ -588,6 +593,14 @@ Proof.
   }
 Qed.
 
+(* Based on https://www.ps.uni-saarland.de/formalizations/fset/html/libs.fset.html *)
+Definition powerset {T: eqType} (l: seq T) : seq (seq T) :=
+  let mT := ((size l).-tuple bool) in
+    (map (fun m : mT => (mask m l)) (enum {: mT})).
+
+Definition no_intersection {T: eqType} (l1 l2: seq T) :=
+  ~~ has (mem l1) l2.
+
 (*Program Definition fun_ord_to_nat2 {n} {T} (x0: T) (f: 'I_n -> T)
         (x : nat) : T :=
   match (x < n) with
-- 
GitLab